diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1a266bc4..a743d5b1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -36,7 +36,7 @@ variables: .version-fix: &version-fix - | $env:NEW_REL = $env:VERS_MAIN+"."+(get-date –format yyMM)+"."+(get-date –format ddHH) - $env:NUM_REL = $env:VERS_MAIN+"."+(get-date –format yyMM)+"."+(get-date –format ddHH) + $env:NUM_REL = $env:VERS_MAIN+"."+(get-date –format yyMM)+"."+(get-date –format dHH) $env:NUM_DEB = $env:VERS_MAIN+"."+(get-date –format yyMM)+"-beta."+(get-date –format dHH) $env:NEW_COPYRIGHT = "EgalWare @ 2006-" + (get-date -format yyyy) $contenuto = Get-Content -path 'VersGen\VersGen.cs' -Raw diff --git a/Documentazione/Icoel/Dettaglio Conferimento.sql b/Documentazione/Icoel/Dettaglio Conferimento.sql new file mode 100644 index 00000000..41364547 --- /dev/null +++ b/Documentazione/Icoel/Dettaglio Conferimento.sql @@ -0,0 +1,24 @@ +SELECT * +FROM DettagliConferimentoMES +where FillingId = 31729 +order by PackId + + +/* +Numero lotto = sigla giorno +sigla lotto: incrementale giornaliero + +in particoalre x il prodotto grosso --> seleziono da + fornitori (es fornitori grossi) + +PackId = id univoco scatoletta +FillingId / FillingRow NON USATI: li posso ignorare, si applicano al caso "travaso" da bins ingresso / bins uscita "tipizzati" --> serve x precalibrare +scaricoId = operazione di scannerizzazione ( è il barcode letto) +codice a barre è letto x ogni etichetta di conferimento +codice e nome fornitore = grower +codice e descrizione prodotto : sono il GREZZO specifico +cdice prodotto grezzo è il "ceppo" / famiglia +sigla e numero lotto: colonna di entrata ciliegie (frontiera) +idem x data e qta entrata + + +*/ \ No newline at end of file diff --git a/Documentazione/Icoel/Dettaglio confezioni.sql b/Documentazione/Icoel/Dettaglio confezioni.sql new file mode 100644 index 00000000..c702736b --- /dev/null +++ b/Documentazione/Icoel/Dettaglio confezioni.sql @@ -0,0 +1,16 @@ +SELECT * +FROM DettagliConfezioniMES + + +/* +pack id = singola cassetta/scatola/cartone +ean = barcode in uscita +batch id / batch name = dati tracciabilità, legato ai lotti in entrata sul sizer +lane [1/2]sizerBatchId = lotti del sizer +pesoDecigram = peso netto confezionato (tolleranza +/-10g...20gr) + +tabella scritta dal momento in cui arriva il cartone/cassetta per iniziare riempimento + +dati live li vediamo dal sizer + +*/ \ No newline at end of file diff --git a/Documentazione/Icoel/Report fine lavorazione lotto.sql b/Documentazione/Icoel/Report fine lavorazione lotto.sql new file mode 100644 index 00000000..86b1f865 --- /dev/null +++ b/Documentazione/Icoel/Report fine lavorazione lotto.sql @@ -0,0 +1,19 @@ +select top 100 * +from ProductsTotals + +/* +SizerBatch id = id del batch da WS SOAP +Index = indice di prodotto FINITO, di cui ho il NOME +- prodotti da matrice: colonne = gradi, righe = taglie(sizes) +- grado a colore rosso +- do il nome prodotto rosse 26- (che sono da 22 a 26 in grado A) +- colonna qualities = è la "somma dei qualities" ovvero le colonne che passano nelcontrollo prodotto +- codice in 3 parametri, che sono a,b,c + - a = qualità interna (SEMPRE NULL x le ciliegie) + - b grado = qualità esterna del frutto, es rosse, nere, con stelo... ricircolo = scarto per cattiva disposizione + - c : calibri che mi definiscono la dimensione, tipicamente 22..32 + + + si scrive tutto quando è chiuso il lotto + inizialmente 1 solo lotto x entrambe le linee +*/ \ No newline at end of file diff --git a/Documentazione/Icoel/Selezione_Frontiera.sql b/Documentazione/Icoel/Selezione_Frontiera.sql new file mode 100644 index 00000000..f53165b5 --- /dev/null +++ b/Documentazione/Icoel/Selezione_Frontiera.sql @@ -0,0 +1,23 @@ +/****** Script for SelectTopNRows command from SSMS ******/ +SELECT TOP (1000) [ID_CHIAVE] + ,[CODBARRE] + ,[CODICE_FORNITORE] + ,[CODICE_LUOGO_PRODUZIONE] + ,[NOME_FORNITORE] + ,[INDIRIZZO_FORNITORE] + ,[COMUNE_FORNITORE] + ,[NOME_LUOGO_PRODUZIONE] + ,[INDIRIZZO_LUOGO_PRODUZIONE] + ,[COMUNE_LUOGO_PRODUZIONE] + ,[CODICE_PRODOTTO] + ,[DESCRIZIONE_PRODOTTO] + ,[CODICE_PRODOTTO_GREZZO] + ,[DESCRIZIONE_PRODOTTO_GREZZO] + ,[SIGLA_LOTTO] + ,[NUMERO_LOTTO] + ,[DATA_ENTRATA] + ,[QUANTITA_ENTRATA] + FROM [frontiera].[dbo].[ENTRATACILIEGIE] + + + -- utilizzare codice e descrizione prodotto... \ No newline at end of file diff --git a/EgwProxy.Icoel.DataLayer/App.config b/EgwProxy.Icoel.DataLayer/App.config new file mode 100644 index 00000000..bb4630dd --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/App.config @@ -0,0 +1,42 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EgwProxy.Icoel.DataLayer/Controllers/DbController.cs b/EgwProxy.Icoel.DataLayer/Controllers/DbController.cs new file mode 100644 index 00000000..98ab5ffd --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/Controllers/DbController.cs @@ -0,0 +1,132 @@ +using NLog; +using System; +using System.Collections.Generic; +using System.Linq; + +/*------------------------------------------------ + * Aggiunto fix come da link seguente: + * + * https://stackoverflow.com/questions/14033193/entity-framework-provider-type-could-not-be-loaded + * + * I solved this by adding an using stament on top of my DBContext class, like so: + * using SqlProviderServices= System.Data.Entity.SqlServer.SqlProviderServices; + * + */ + +namespace EgwProxy.Icoel.DataLayer.Controllers +{ + /// + /// Controller accesso dati DB vari x ICOEL + /// + public class DbController : IDisposable + { +#if false + private static EntrataDbContext dbEntrataCtx; + private static ExportDbContext dbExportCtx; + private static TrackerDbContext dbTrackerCtx; +#endif + + #region Public Constructors + + /// + /// Avvio dell'oggetto gestione DB con stringa di connessione specifica + /// + /// Connessione DB locale di SYNC + public DbController(string connSyncState) + { + dbSyncStateCtx = new SyncStateDbContext(connSyncState); + Log.Info("Avviata classe dbSyncStateCtx"); + } + + #endregion Public Constructors + + #region Public Methods + + /// + /// Recupera la tab di CurrData corrente + /// + /// + public List CurrDataGetAll() + { + List dbResult = new List(); + + dbResult = dbSyncStateCtx + .DbSetCurrData + .ToList(); + + return dbResult; + } + + /// + /// Dispose classe + /// + public void Dispose() + { + // Clear database context +#if false + dbEntrataCtx.Dispose(); + dbExportCtx.Dispose(); + dbTrackerCtx.Dispose(); +#endif + dbSyncStateCtx.Dispose(); + } + + /// + /// Esegue una volta la stored di ImportAll (x recupero dati da DB esterni) e poi + /// restitusice in output la tab di SyncState x verificare lo stato + /// + /// + public List SyncStateDoExportAll() + { + List dbResult = new List(); + + dbResult = dbSyncStateCtx + .Database + .SqlQuery("EXEC stp_ExportAll") + .ToList(); + + return dbResult; + } + + /// + /// Esegue una volta la stored di ImportAll (x recupero dati da DB esterni) e poi + /// restitusice in output la tab di SyncState x verificare lo stato + /// + /// + public List SyncStateDoImportAll() + { + List dbResult = new List(); + + dbResult = dbSyncStateCtx + .Database + .SqlQuery("EXEC stp_ImportAll") + .ToList(); + + return dbResult; + } + + /// + /// recupera la tab di SyncState corrente + /// + /// + public List SyncStateGetAll() + { + List dbResult = new List(); + + dbResult = dbSyncStateCtx + .DbSetSyncState + .ToList(); + + return dbResult; + } + + #endregion Public Methods + + #region Private Fields + + private static SyncStateDbContext dbSyncStateCtx; + private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); + + #endregion Private Fields + } +} \ No newline at end of file diff --git a/EgwProxy.Icoel.DataLayer/DatabaseModels/CurrDataModel.cs b/EgwProxy.Icoel.DataLayer/DatabaseModels/CurrDataModel.cs new file mode 100644 index 00000000..f6fb6573 --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/DatabaseModels/CurrDataModel.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data.Entity.Spatial; + +namespace EgwProxy.Icoel.DataLayer.DatabaseModels +{ + + [Table("CurrData")] + public partial class CurrDataModel + { + [Key] + [StringLength(50)] + public string Topic { get; set; } + + public decimal CurrVal { get; set; } = 0; + } +} diff --git a/EgwProxy.Icoel.DataLayer/DatabaseModels/DettConferimentoModel.cs b/EgwProxy.Icoel.DataLayer/DatabaseModels/DettConferimentoModel.cs new file mode 100644 index 00000000..e1bad126 --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/DatabaseModels/DettConferimentoModel.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data.Entity.Spatial; + +namespace EgwProxy.Icoel.DataLayer.DatabaseModels +{ + + [Table("DettagliConferimentoMES")] + public partial class DettConferimentoModel + { + [Key] + [Column(Order = 0)] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public long PackId { get; set; } + + [Key] + [Column(Order = 1)] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public long FillingId { get; set; } + + [Key] + [Column(Order = 2)] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public int FilligRow { get; set; } + + [Key] + [Column(Order = 3)] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public long ScaricoId { get; set; } + + public string CODBARRE { get; set; } + + public string CODICE_FORNITORE { get; set; } + + public string NOME_FORNITORE { get; set; } + + public string CODICE_PRODOTTO { get; set; } + + public string DESCRIZIONE_PRODOTTO { get; set; } + + public string CODICE_PRODOTTO_GREZZO { get; set; } + + public string DESCRIZIONE_PRODOTTO_GREZZO { get; set; } + + public string SIGLA_LOTTO { get; set; } + + public string NUMERO_LOTTO { get; set; } + + public string DATA_ENTRATA { get; set; } + + public string QUANTITA_ENTRATA { get; set; } + } +} diff --git a/EgwProxy.Icoel.DataLayer/DatabaseModels/DettConfezioniModel.cs b/EgwProxy.Icoel.DataLayer/DatabaseModels/DettConfezioniModel.cs new file mode 100644 index 00000000..e1d3aebb --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/DatabaseModels/DettConfezioniModel.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data.Entity.Spatial; + +namespace EgwProxy.Icoel.DataLayer.DatabaseModels +{ + + [Table("DettagliConfezioniMES")] + public partial class DettConfezioniModel + { + [Key] + [Column("Pack Id", Order = 0)] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public long Pack_Id { get; set; } + + [StringLength(50)] + public string EAN { get; set; } + + [Key] + [Column("Batch Id", Order = 1)] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public long Batch_Id { get; set; } + + public string BatchName { get; set; } + + [Key] + [Column(Order = 2)] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public int Lane1SizerBatchId { get; set; } + + [Key] + [Column(Order = 3)] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public int Lane2SizerBatchId { get; set; } + + [Key] + [Column("End Time", Order = 4, TypeName = "datetime2")] + public DateTime End_Time { get; set; } + + [Key] + [Column(Order = 5)] + public Guid SizerProductGUID { get; set; } + + [Column("Product Name")] + public string Product_Name { get; set; } + + [Key] + [Column(Order = 6)] + public Guid SizerPackGUID { get; set; } + + [Column("Pack Name")] + [StringLength(50)] + public string Pack_Name { get; set; } + + [Key] + [Column(Order = 7)] + public decimal PesoDecigram { get; set; } + + [StringLength(10)] + public string FillingMode { get; set; } + + [Key] + [Column(Order = 8)] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public int Quantity { get; set; } + } +} diff --git a/EgwProxy.Icoel.DataLayer/DatabaseModels/EntrataModel.cs b/EgwProxy.Icoel.DataLayer/DatabaseModels/EntrataModel.cs new file mode 100644 index 00000000..d389d6ea --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/DatabaseModels/EntrataModel.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data.Entity.Spatial; + +namespace EgwProxy.Icoel.DataLayer.DatabaseModels +{ + + [Table("ENTRATACILIEGIE")] + public partial class EntrataModel + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public long ID_CHIAVE { get; set; } + + [StringLength(20)] + public string CODBARRE { get; set; } + + public double? CODICE_FORNITORE { get; set; } + + [StringLength(5)] + public string CODICE_LUOGO_PRODUZIONE { get; set; } + + [StringLength(50)] + public string NOME_FORNITORE { get; set; } + + [StringLength(50)] + public string INDIRIZZO_FORNITORE { get; set; } + + [StringLength(50)] + public string COMUNE_FORNITORE { get; set; } + + [StringLength(50)] + public string NOME_LUOGO_PRODUZIONE { get; set; } + + [StringLength(50)] + public string INDIRIZZO_LUOGO_PRODUZIONE { get; set; } + + [StringLength(50)] + public string COMUNE_LUOGO_PRODUZIONE { get; set; } + + [StringLength(10)] + public string CODICE_PRODOTTO { get; set; } + + [StringLength(50)] + public string DESCRIZIONE_PRODOTTO { get; set; } + + [StringLength(10)] + public string CODICE_PRODOTTO_GREZZO { get; set; } + + [StringLength(50)] + public string DESCRIZIONE_PRODOTTO_GREZZO { get; set; } + + [StringLength(50)] + public string SIGLA_LOTTO { get; set; } + + [StringLength(10)] + public string NUMERO_LOTTO { get; set; } + + [Column(TypeName = "datetime2")] + public DateTime? DATA_ENTRATA { get; set; } + + public double? QUANTITA_ENTRATA { get; set; } + } +} diff --git a/EgwProxy.Icoel.DataLayer/DatabaseModels/ProductsTotalsModel.cs b/EgwProxy.Icoel.DataLayer/DatabaseModels/ProductsTotalsModel.cs new file mode 100644 index 00000000..8a37d147 --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/DatabaseModels/ProductsTotalsModel.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data.Entity.Spatial; + +namespace EgwProxy.Icoel.DataLayer.DatabaseModels +{ + + [Table("ProductsTotals")] + public partial class ProductsTotalsModel + { + [Key] + [Column(Order = 0)] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public int SizerBatchId { get; set; } + + [Key] + [Column(Order = 1)] + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public int Index { get; set; } + + public string Nome { get; set; } + + public string Qualities { get; set; } + + public string Grado { get; set; } + + public string Calibro { get; set; } + + public int NumeroFrutti { get; set; } + + public string Decigrammi { get; set; } + } +} diff --git a/EgwProxy.Icoel.DataLayer/DatabaseModels/SyncStateModel.cs b/EgwProxy.Icoel.DataLayer/DatabaseModels/SyncStateModel.cs new file mode 100644 index 00000000..b37fa326 --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/DatabaseModels/SyncStateModel.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data.Entity.Spatial; + +namespace EgwProxy.Icoel.DataLayer.DatabaseModels +{ + + [Table("SyncState")] + public partial class SyncStateModel + { + [Key] + [StringLength(50)] + public string TableName { get; set; } + + public long LastIdx { get; set; } + + public long LastIdxIn { get; set; } + + public long LastIdxOut { get; set; } + + public long NumRec { get; set; } + + public long NumRecIn { get; set; } + + public long NumRecOut { get; set; } + + public DateTime LastUpdate { get; set; } = DateTime.Today; + } +} diff --git a/EgwProxy.Icoel.DataLayer/DbConfig.cs b/EgwProxy.Icoel.DataLayer/DbConfig.cs new file mode 100644 index 00000000..b86128ac --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/DbConfig.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EgwProxy.Icoel.DataLayer +{ + public static class DbConfig + { + #region Public Fields + + public static string DATABASE_NAME = "EgtBwDb"; + + public static int DATABASE_PROCESS_TIMEOUT = 5; + public static string DATABASE_PWD = "viacremasca"; + + // Database config + public static string DATABASE_SERV = "127.0.0.1"; + + public static string DATABASE_USER = "EgtUser"; + + #endregion Public Fields + + #region Public Properties + + /// + /// DB Connection string per azioni amministrative + /// + public static string ADMIN_CONNECTION_STRING { get; set; } = ""; + + /// + /// DB Connection string + /// + public static string CONNECTION_STRING { get; set; } = ""; + + #endregion Public Properties + + #region Public Methods + + /// + /// Metodo di init standard per DB in rete con Master_Key + /// + /// Indirizzo del server (tipicamente indirizzo di rete) + /// Numero chiave + /// Codice/pwd associato a chaive + /// Numero di chiave master con cui è creato il DB + public static void InitDb(string server, string nKey, string sKey, string masterKey = "") + { + // se nulla metto amster come nKey... + masterKey = string.IsNullOrEmpty(masterKey) ? nKey : masterKey; + DATABASE_SERV = server; + DATABASE_NAME = $"EgtBwDb_{masterKey}"; + DATABASE_USER = $"user_{nKey}"; + DATABASE_PWD = $"pwd_{sKey}"; + CONNECTION_STRING = $"server={DATABASE_SERV};port=3306;database={DATABASE_NAME};uid={DATABASE_USER};pwd={DATABASE_PWD};sslmode=None"; + // stringa admin con utente root egalware... + ADMIN_CONNECTION_STRING = $"server={DATABASE_SERV};port=3306;database=mysql;uid=root;pwd=Egalware_24068!;sslmode=None;CHARSET=utf8"; + } + +#if false + public static bool CheckUser(string nKey, string sKey, bool isNetwork) + { + // esecuzione script di install locale + return Controllers.DbController.man.checkCreateUser(DATABASE_USER, DATABASE_PWD, isNetwork); + } +#endif + + #endregion Public Methods + } +} diff --git a/EgwProxy.Icoel.DataLayer/EgwProxy.Icoel.DataLayer.csproj b/EgwProxy.Icoel.DataLayer/EgwProxy.Icoel.DataLayer.csproj new file mode 100644 index 00000000..9388cba0 --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/EgwProxy.Icoel.DataLayer.csproj @@ -0,0 +1,199 @@ + + + + + + Debug + AnyCPU + {E36544CB-D699-48D8-9F81-C2758E7C7D19} + Library + Properties + EgwProxy.Icoel.DataLayer + EgwProxy.Icoel.DataLayer + v4.6.2 + 512 + true + + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Azure.Core.1.6.0\lib\net461\Azure.Core.dll + + + ..\packages\Azure.Identity.1.3.0\lib\netstandard2.0\Azure.Identity.dll + + + ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll + + + ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll + + + ..\packages\Microsoft.Bcl.AsyncInterfaces.1.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll + + + ..\packages\Microsoft.Data.SqlClient.4.1.0\lib\net461\Microsoft.Data.SqlClient.dll + + + ..\packages\Microsoft.Identity.Client.4.22.0\lib\net461\Microsoft.Identity.Client.dll + + + ..\packages\Microsoft.Identity.Client.Extensions.Msal.2.16.5\lib\net45\Microsoft.Identity.Client.Extensions.Msal.dll + + + ..\packages\Microsoft.IdentityModel.JsonWebTokens.6.8.0\lib\net461\Microsoft.IdentityModel.JsonWebTokens.dll + + + ..\packages\Microsoft.IdentityModel.Logging.6.8.0\lib\net461\Microsoft.IdentityModel.Logging.dll + + + ..\packages\Microsoft.IdentityModel.Protocols.6.8.0\lib\net461\Microsoft.IdentityModel.Protocols.dll + + + ..\packages\Microsoft.IdentityModel.Protocols.OpenIdConnect.6.8.0\lib\net461\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll + + + ..\packages\Microsoft.IdentityModel.Tokens.6.8.0\lib\net461\Microsoft.IdentityModel.Tokens.dll + + + ..\packages\NLog.4.7.9\lib\net45\NLog.dll + + + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + + + ..\packages\System.Configuration.ConfigurationManager.5.0.0\lib\net461\System.Configuration.ConfigurationManager.dll + + + + + ..\packages\System.Diagnostics.DiagnosticSource.4.6.0\lib\net46\System.Diagnostics.DiagnosticSource.dll + + + + + ..\packages\System.IdentityModel.Tokens.Jwt.6.8.0\lib\net461\System.IdentityModel.Tokens.Jwt.dll + + + ..\packages\System.IO.4.3.0\lib\net462\System.IO.dll + True + True + + + + ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll + + + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.6.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + True + True + + + + + ..\packages\System.Security.AccessControl.5.0.0\lib\net461\System.Security.AccessControl.dll + + + ..\packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net461\System.Security.Cryptography.Algorithms.dll + True + True + + + ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + True + True + + + ..\packages\System.Security.Cryptography.ProtectedData.4.5.0\lib\net461\System.Security.Cryptography.ProtectedData.dll + + + ..\packages\System.Security.Permissions.5.0.0\lib\net461\System.Security.Permissions.dll + + + ..\packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll + + + + + ..\packages\System.Text.Encodings.Web.4.7.2\lib\net461\System.Text.Encodings.Web.dll + + + ..\packages\System.Text.Json.4.6.0\lib\net461\System.Text.Json.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.5.2\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll + + + + ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Questo progetto fa riferimento a uno o più pacchetti NuGet che non sono presenti in questo computer. Usare lo strumento di ripristino dei pacchetti NuGet per scaricarli. Per altre informazioni, vedere http://go.microsoft.com/fwlink/?LinkID=322105. Il file mancante è {0}. + + + + + + + + \ No newline at end of file diff --git a/EgwProxy.Icoel.DataLayer/EntrataDbContext.cs b/EgwProxy.Icoel.DataLayer/EntrataDbContext.cs new file mode 100644 index 00000000..58e851d3 --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/EntrataDbContext.cs @@ -0,0 +1,46 @@ +using EgwProxy.Icoel.DataLayer.DatabaseModels; +using NLog; +using System; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data.Entity; +using System.Linq; +using SqlProviderServices = System.Data.Entity.SqlServer.SqlProviderServices; + +namespace EgwProxy.Icoel.DataLayer +{ + /// + /// Classe per accesso dati accettazione merce Agrimatica (via ICOEL) + /// + public partial class EntrataDbContext : DbContext + { + private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); + + /// + /// Costruttore implicito + /// + public EntrataDbContext() : base("name=EntrataFrontiera") + { + Log.Info("Init 01 EntrataDbContext - DONE"); + } + + /// + /// Costruttore da connectionString + /// + /// + public EntrataDbContext(string connectionString) : base(connectionString) + { + Log.Info("Init 02 EntrataDbContext - DONE"); + } + /// + /// DbSet record entrata merce + /// + public virtual DbSet DbSetEntrataMerce { get; set; } + + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + modelBuilder.Entity() + .Property(e => e.DATA_ENTRATA) + .HasPrecision(0); + } + } +} diff --git a/EgwProxy.Icoel.DataLayer/ExportDbContext.cs b/EgwProxy.Icoel.DataLayer/ExportDbContext.cs new file mode 100644 index 00000000..5402b3b7 --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/ExportDbContext.cs @@ -0,0 +1,44 @@ +using EgwProxy.Icoel.DataLayer.DatabaseModels; +using NLog; +using System; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data.Entity; +using System.Linq; +using SqlProviderServices = System.Data.Entity.SqlServer.SqlProviderServices; + +namespace EgwProxy.Icoel.DataLayer +{ + /// + /// Classe per accesso dati Tacker ICOEL + /// + public partial class ExportDbContext : DbContext + { + private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); + + /// + /// Costruttore implicito + /// + public ExportDbContext() : base("name=ExportIcoel") + { + Log.Info("Init 01 ExportDbContext - DONE"); + } + + /// + /// Costruttore da connectionString + /// + /// + public ExportDbContext(string connectionString) : base(connectionString) + { + Log.Info("Init 02 ExportDbContext - DONE"); + } + + /// + /// DbSet dati prodotti + /// + public virtual DbSet DbSetProductsTotals { get; set; } + + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + } + } +} diff --git a/EgwProxy.Icoel.DataLayer/MainDbContext.cs b/EgwProxy.Icoel.DataLayer/MainDbContext.cs new file mode 100644 index 00000000..66793f1c --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/MainDbContext.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EgwProxy.Icoel.DataLayer +{ + public class MainDbContext : DbContext + { + #region Private Fields + + private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); + + #endregion Private Fields + + #region Public Constructors + + // Il contesto è stato configurato per utilizzare una stringa di connessione 'BBMModel' dal file di configurazione + // dell'applicazione (App.config o Web.config). Per impostazione predefinita, la stringa di connessione è destinata al + // database 'BBMModel' nell'istanza di LocalDb. + // + // Per destinarla a un database o un provider di database differente, modificare la stringa di connessione 'BBMModel' + // nel file di configurazione dell'applicazione. + [Obsolete("This constructor should never be used directly, and is only needed to generate entityframework stuff. Connection string can be adapted as pleased.")] + //public DatabaseContext() : base("BBMModel") + public MainDbContext() : base("Data Source=SQLSTEAM;Initial Catalog=SHERPA.BBM;User ID=sa;Password=keyhammer;integrated security=False;MultipleActiveResultSets=True;App=EntityFramework") + { + } + + public MainDbContext(string connectionString) : base(connectionString) + { + Log.Info($"init MainDbContext - start"); + + try + { + Database.CreateIfNotExists(); + Log.Error("CreateIfNotExists - DONE"); + + //Database.SetInitializer(new MigrateDatabaseToLatestVersion()); + Database.SetInitializer(null); + Database.Initialize(false); + } + catch (Exception exc) + { + Log.Error($"Eccezione in fase init MainDbContext, connectionString: {connectionString}{Environment.NewLine}{exc}"); + } + Log.Error("init MainDbContext - DONE"); + } + + #endregion Public Constructors + + // Aggiungere DbSet per ogni tipo di entità che si desidera includere nel modello. Per ulteriori informazioni + // sulla configurazione e sull'utilizzo di un modello Code, vedere http://go.microsoft.com/fwlink/?LinkId=390109. + + #region Public Properties + + public virtual DbSet DbSetBaskets { get; set; } + public virtual DbSet DbSetCompanies { get; set; } + public virtual DbSet DbSetCounters { get; set; } + public virtual DbSet DbSetCustomers { get; set; } + public virtual DbSet DbSetDocs { get; set; } + + public virtual DbSet DbSetFatt2Doc { get; set; } + + public virtual DbSet DbSetItems { get; set; } + + public virtual DbSet DbSetNegotiations { get; set; } + + public virtual DbSet DbSetResources { get; set; } + + #endregion Public Properties + + #region Protected Methods + + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + // Precision attribute for decimals + Precision.ConfigureModelBuilder(modelBuilder); + } + + #endregion Protected Methods + } + +} diff --git a/EgwProxy.Icoel.DataLayer/Properties/AssemblyInfo.cs b/EgwProxy.Icoel.DataLayer/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..374243d1 --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Le informazioni generali relative a un assembly sono controllate dal seguente +// set di attributi. Modificare i valori di questi attributi per modificare le informazioni +// associate a un assembly. +[assembly: AssemblyTitle("EgwProxy.Icoel.DataLayer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("EgwProxy.Icoel.DataLayer")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Se si imposta ComVisible su false, i tipi in questo assembly non saranno visibili +// ai componenti COM. Se è necessario accedere a un tipo in questo assembly da +// COM, impostare su true l'attributo ComVisible per tale tipo. +[assembly: ComVisible(false)] + +// Se il progetto viene esposto a COM, il GUID seguente verrà utilizzato come ID della libreria dei tipi +[assembly: Guid("e36544cb-d699-48d8-9f81-c2758e7c7d19")] + +// Le informazioni sulla versione di un assembly sono costituite dai seguenti quattro valori: +// +// Versione principale +// Versione secondaria +// Numero di build +// Revisione +// +// È possibile specificare tutti i valori oppure impostare valori predefiniti per i numeri relativi alla revisione e alla build +// usando l'asterisco '*' come illustrato di seguito: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/EgwProxy.Icoel.DataLayer/SyncStateDbContext.cs b/EgwProxy.Icoel.DataLayer/SyncStateDbContext.cs new file mode 100644 index 00000000..fd401841 --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/SyncStateDbContext.cs @@ -0,0 +1,48 @@ +using EgwProxy.Icoel.DataLayer.DatabaseModels; +using NLog; +using System; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data.Entity; +using System.Linq; + +namespace EgwProxy.Icoel.DataLayer +{ + /// + /// Classe per accesso dati SyncState del DB + /// + public partial class SyncStateDbContext : DbContext + { + private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); + + /// + /// Costruttore implicito + /// + public SyncStateDbContext() : base("name=SyncState") + { + Log.Info("Init 01 SyncStateDbContext - DONE"); + } + + /// + /// Costruttore da connectionString + /// + /// + public SyncStateDbContext(string connectionString) : base(connectionString) + { + Log.Info("Init 02 SyncStateDbContext - DONE"); + } + + /// + /// DbSet dei dati stato sync DB esterni <--> locale + /// + public virtual DbSet DbSetSyncState { get; set; } + + /// + /// DbSet CurrData + /// + public virtual DbSet DbSetCurrData { get; set; } + + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + } + } +} diff --git a/EgwProxy.Icoel.DataLayer/TrackerDbContext.cs b/EgwProxy.Icoel.DataLayer/TrackerDbContext.cs new file mode 100644 index 00000000..c8800f54 --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/TrackerDbContext.cs @@ -0,0 +1,49 @@ +using EgwProxy.Icoel.DataLayer.DatabaseModels; +using NLog; +using System; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data.Entity; +using System.Linq; +using SqlProviderServices = System.Data.Entity.SqlServer.SqlProviderServices; + +namespace EgwProxy.Icoel.DataLayer +{ + /// + /// Classe per accesso dati Tacker ICOEL + /// + public partial class TrackerDbContext : DbContext + { + private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); + + /// + /// Costruttore implicito + /// + public TrackerDbContext() : base("name=TrackerLotti") + { + Log.Info("Init 01 TrackerDbContext - DONE"); + } + + /// + /// Costruttore da connectionString + /// + /// + public TrackerDbContext(string connectionString) : base(connectionString) + { + Log.Info("Init 02 TrackerDbContext - DONE"); + } + + /// + /// DbSet dai dati conferimento <--> pack di uscita + /// + public virtual DbSet DbSetConferimento { get; set; } + + /// + /// DbSet dai dati conferimento <--> confezioni + /// + public virtual DbSet DbSetConfezioni { get; set; } + + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + } + } +} diff --git a/EgwProxy.Icoel.DataLayer/packages.config b/EgwProxy.Icoel.DataLayer/packages.config new file mode 100644 index 00000000..d4e647cc --- /dev/null +++ b/EgwProxy.Icoel.DataLayer/packages.config @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EgwProxy.Icoel.Test/App.config b/EgwProxy.Icoel.Test/App.config index 2e734fec..3f1e6976 100644 --- a/EgwProxy.Icoel.Test/App.config +++ b/EgwProxy.Icoel.Test/App.config @@ -1,24 +1,73 @@ - + - - - + + +
+ + + + + + + + + + + + + + + + + - + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/EgwProxy.Icoel.Test/EgwProxy.Icoel.Test.csproj b/EgwProxy.Icoel.Test/EgwProxy.Icoel.Test.csproj index 981c75ef..fcdfd69f 100644 --- a/EgwProxy.Icoel.Test/EgwProxy.Icoel.Test.csproj +++ b/EgwProxy.Icoel.Test/EgwProxy.Icoel.Test.csproj @@ -34,6 +34,7 @@ + @@ -43,9 +44,6 @@ - - - @@ -59,10 +57,17 @@ + + {E36544CB-D699-48D8-9F81-C2758E7C7D19} + EgwProxy.Icoel.DataLayer + {c45f5e6e-866b-4a34-a598-29aab2d178ad} EgwProxy.Icoel + + + \ No newline at end of file diff --git a/EgwProxy.Icoel.Test/Program.cs b/EgwProxy.Icoel.Test/Program.cs index 9f6bd3b5..0b499450 100644 --- a/EgwProxy.Icoel.Test/Program.cs +++ b/EgwProxy.Icoel.Test/Program.cs @@ -1,7 +1,10 @@ -using EgwProxy.Icoel.SizerService; -using EgwProxy.Icoel.Test.INI; +using EgwProxy.Icoel.DataLayer.DatabaseModels; +using EgwProxy.Icoel.SizerService; +//using EgwProxy.Icoel.Test.INI; using System; using System.Collections.Generic; +using System.Configuration; +using System.Diagnostics; namespace EgwProxy.Icoel.Test { @@ -9,6 +12,33 @@ namespace EgwProxy.Icoel.Test { #region Internal Methods + /// + /// Mostra tutte le metriche di performance ricevute + /// + /// + internal static void DisplayPerfMeter(Dictionary perfMeter) + { + // mostra tutti i parametri rilevati... + foreach (var item in perfMeter) + { + Console.WriteLine($"{item.Key} | {item.Value:N2}"); + } + } + /// + /// Mostra tutte le metriche di performance ricevute + /// + /// + internal static void DisplayCurrBatch(Dictionary currData) + { + // mostra tutti i parametri rilevati... + foreach (var item in currData) + { + Console.WriteLine($"{item.Key} | {item.Value}"); + } + } + + + /// /// Generazione di una list di info sui dati variety /// @@ -175,6 +205,26 @@ namespace EgwProxy.Icoel.Test } } + /// + /// legge conf in formato stringa + /// + /// + /// + protected static string ReadSetting(string key) + { + string answ = ""; + try + { + answ = $"{ConfigurationManager.AppSettings[key]}" ?? ""; + } + catch (Exception exc) + { + Console.Write("Eccezione in ReadSettings"); + Console.Write(exc.Message); + } + return answ; + } + /// /// Programma principale /// @@ -183,15 +233,67 @@ namespace EgwProxy.Icoel.Test { // leggo conf da file ini (ip/port) Console.WriteLine("Loading Files..."); - Settaggi setup = new Settaggi(); - setup.Load(); string userInput = ""; - // oggetto x connessione - Connector IcoelSizer = new Connector(setup.IndirizzoIpSizer, setup.SizerTcpPort); + + Console.WriteLine("------------ Test DB ------------"); + EgwProxy.Icoel.DbProxy dbProxy = new DbProxy(ReadSetting("SyncState")); + Console.WriteLine(); + Console.WriteLine("--- SyncState ---"); + bool needRedo = true; + int numTry = 1; + //int numTry = 3; + var elencoSyncState = dbProxy.DataController.SyncStateGetAll(); + while (needRedo && numTry >= 0) + { + Console.WriteLine(" --- PRE --- "); + if (elencoSyncState != null) + { + foreach (var item in elencoSyncState) + { + Console.WriteLine($"TAB: {item.TableName} | IdxIN / IdxLocal {item.LastIdxIn} / {item.LastIdx} | NumIn / NumLocal {item.NumRecIn} / {item.NumRec}"); + // verifico se serva redo.. + } + } + Console.WriteLine(); + Console.WriteLine("Premere un tasto x continuare..."); + Console.ReadKey(); + Stopwatch sw = new Stopwatch(); + sw.Start(); + elencoSyncState = dbProxy.DataController.SyncStateDoImportAll(); + sw.Stop(); + Console.WriteLine($" process time: {sw.ElapsedMilliseconds} ms "); + Console.WriteLine(" --- POST --- "); + if (elencoSyncState != null) + { + foreach (var item in elencoSyncState) + { + Console.WriteLine($"TAB: {item.TableName} | IdxIN / IdxLocal {item.LastIdxIn} / {item.LastIdx} | NumIn / NumLocal {item.NumRecIn} / {item.NumRec}"); + // verifico se serva redo.. + } + } + // processo + needRedo = testNeedRedo(elencoSyncState); + numTry--; + } + Console.WriteLine(); + Console.WriteLine("Premere un tasto x continuare..."); + Console.ReadKey(); + + // oggetto x connessione al sizer icoel + Connector IcoelSizer = new Connector(ReadSetting("IndirizzoIpSizer"), ReadSetting("SizerTcpPort")); + //Connector IcoelSizer = new Connector(setup.IndirizzoIpSizer, setup.SizerTcpPort); + + Console.WriteLine("------------ Parametri CurrBatch rilevati ------------"); + var cBatch = IcoelSizer.GetCurrBatchData(); + if (cBatch != null) + { + DisplayCurrBatch(cBatch); + } // ora effettua un pò di letture/scritture try { + Console.WriteLine("------------ TUTTE variety ------------"); var varList = IcoelSizer.GetVarietyList(false); var varietyData = IcoelSizer.GetLayoutForVarietyList(varList); @@ -203,6 +305,17 @@ namespace EgwProxy.Icoel.Test Console.WriteLine("Premere un tasto x continuare..."); userInput = Console.ReadLine(); + + Console.WriteLine("------------ Parametri velocità rilevati ------------"); + var perfMeter = IcoelSizer.GetPerfMeters(); + if (perfMeter != null) + { + DisplayPerfMeter(perfMeter); + } + Console.WriteLine(); + Console.WriteLine("Premere un tasto x continuare..."); + userInput = Console.ReadLine(); + // solo attive Console.WriteLine("------------ solo attive ------------"); varList = IcoelSizer.GetVarietyList(); @@ -250,6 +363,22 @@ namespace EgwProxy.Icoel.Test Console.ReadKey(); } } + /// + /// Verifico necessità di rifare sync + /// + /// + /// + /// + private static bool testNeedRedo(List elencoSyncState) + { + bool answ = false; + foreach (var item in elencoSyncState) + { + answ = answ || (item.NumRecIn > item.NumRec || item.LastIdxIn > item.LastIdx); + } + return answ; + } + #endregion Private Methods } diff --git a/EgwProxy.Icoel.sln b/EgwProxy.Icoel.sln index 6961afad..9b3a9da9 100644 --- a/EgwProxy.Icoel.sln +++ b/EgwProxy.Icoel.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EgwProxy.Icoel", "EgwProxy. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EgwProxy.Icoel.Test", "EgwProxy.Icoel.Test\EgwProxy.Icoel.Test.csproj", "{A655A6AC-5997-46F9-9752-8C621B80516C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EgwProxy.Icoel.DataLayer", "EgwProxy.Icoel.DataLayer\EgwProxy.Icoel.DataLayer.csproj", "{E36544CB-D699-48D8-9F81-C2758E7C7D19}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +23,10 @@ Global {A655A6AC-5997-46F9-9752-8C621B80516C}.Debug|Any CPU.Build.0 = Debug|Any CPU {A655A6AC-5997-46F9-9752-8C621B80516C}.Release|Any CPU.ActiveCfg = Release|Any CPU {A655A6AC-5997-46F9-9752-8C621B80516C}.Release|Any CPU.Build.0 = Release|Any CPU + {E36544CB-D699-48D8-9F81-C2758E7C7D19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E36544CB-D699-48D8-9F81-C2758E7C7D19}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E36544CB-D699-48D8-9F81-C2758E7C7D19}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E36544CB-D699-48D8-9F81-C2758E7C7D19}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/EgwProxy.Icoel/App.config b/EgwProxy.Icoel/App.config index 2e734fec..3abe0f28 100644 --- a/EgwProxy.Icoel/App.config +++ b/EgwProxy.Icoel/App.config @@ -1,24 +1,59 @@ - + - - - - - - - - - - - - - - - - - - - - - - + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EgwProxy.Icoel/Appunti.md b/EgwProxy.Icoel/Appunti.md new file mode 100644 index 00000000..ae375519 --- /dev/null +++ b/EgwProxy.Icoel/Appunti.md @@ -0,0 +1,107 @@ +# Appunti impiego connesisoni ICOEL + +## Icoel SOAP + +Oltre ai metodi legati al batch, ci sono questi metodi x recuperare informazioni specifiche di produttività + +| Metodo | Descrizione | +| ---------- | ---------- | +| GetMachineTonnesPH() | valore tonnellate/ora di velocità impianto | +| GetMachineTotalFPM() | valore frutti per minuto | +| GetMachineRodsPM() | velocità catena (carrellini / minuto) | +| GetMachineCupfill() | percentuale riempimento carrellini (100% = 1 frutto x ogni carrellino) | + + +## Icoel DB + +Appunti sulla gestione tabelle di frontiera + +### Products total + +/****** Script for SelectTopNRows command from SSMS ******/ +SELECT TOP (1000) [SizerBatchId] + ,[Index] + ,[Nome] + ,[Qualities] + ,[Grado] + ,[Calibro] + ,[NumeroFrutti] + ,[Decigrammi] + FROM [IcoelExport].[dbo].[ProductsTotals] + + +### Entrata Ciliegie + +SELECT * +FROM [frontiera].[dbo].[ENTRATACILIEGIE] + + + -- utilizzare codice e descrizione prodotto... + +### Fine lavorazione +select top 100 * +from ProductsTotals + +/* +SizerBatch id = id del batch da WS SOAP +Index = indice di prodotto FINITO, di cui ho il NOME +- prodotti da matrice: colonne = gradi, righe = taglie(sizes) +- grado a colore rosso +- do il nome prodotto rosse 26- (che sono da 22 a 26 in grado A) +- colonna qualities = è la "somma dei qualities" ovvero le colonne che passano nelcontrollo prodotto +- codice in 3 parametri, che sono a,b,c + - a = qualità interna (SEMPRE NULL x le ciliegie) + - b grado = qualità esterna del frutto, es rosse, nere, con stelo... ricircolo = scarto per cattiva disposizione + - c : calibri che mi definiscono la dimensione, tipicamente 22..32 + + + si scrive tutto quando è chiuso il lotto + inizialmente 1 solo lotto x entrambe le linee +*/ + +### Conferimento MES + + +SELECT * +FROM DettagliConferimentoMES +where FillingId = 31729 +order by PackId + + +/* +Numero lotto = sigla giorno +sigla lotto: incrementale giornaliero + +in particoalre x il prodotto grosso --> seleziono da + fornitori (es fornitori grossi) + +PackId = id univoco scatoletta +FillingId / FillingRow NON USATI: li posso ignorare, si applicano al caso "travaso" da bins ingresso / bins uscita "tipizzati" --> serve x precalibrare +scaricoId = operazione di scannerizzazione ( è il barcode letto) +codice a barre è letto x ogni etichetta di conferimento +codice e nome fornitore = grower +codice e descrizione prodotto : sono il GREZZO specifico +cdice prodotto grezzo è il "ceppo" / famiglia +sigla e numero lotto: colonna di entrata ciliegie (frontiera) +idem x data e qta entrata + + +*/ + +### Confezioni Mes + + +SELECT * +FROM DettagliConfezioniMES + + +pack id = singola cassetta/scatoal/cartone +ean = barcode in uscita +batch id / batch name = dati tracciabilità, legato ai lotti in entrata sul sizer +lane [1/2]sizerBatchId = lotti del sizer +pesoDecigram = peso netto confezionato (tolleranza +/-10g...20gr) + +tabella scritta dal momento in cui arriva il cartone/cassetta per iniziare riempimento + +dati live li vediamo dal sizer + +*/ \ No newline at end of file diff --git a/EgwProxy.Icoel/Compac/ComClient.cs b/EgwProxy.Icoel/Compac/ComClient.cs index 646d41af..3f5ee6e6 100644 --- a/EgwProxy.Icoel/Compac/ComClient.cs +++ b/EgwProxy.Icoel/Compac/ComClient.cs @@ -1,5 +1,6 @@ using EgwProxy.Icoel.SizerService; using System; +using System.Collections.Generic; using System.Runtime.Serialization; using System.ServiceModel; @@ -174,6 +175,31 @@ namespace EgwProxy.Icoel.Compac SSClient.AddBatch(batch); } + /// + /// Recupera elenco parametri performance impianto + /// + /// Dizionario delle variabili di performance dell'impianto in formato Dictionary + internal Dictionary GetPerfMeters() + { + Dictionary answ = new Dictionary(); + // velocità processo indicata in tonnellate /oOra + double velTonnOra = SSClient.GetMachineTonnesPH(); + // velocità espressa in frutti/minuto + double velFruttiMinuto = SSClient.GetMachineTotalFPM(); + // percentuale riempimento carrellini + double percRiemp = SSClient.GetMachineCupfill(); + // Numero confezioni/ora + double numPackOra = SSClient.GetMachinePacksPH(); + + // accodo i valori ricavati + answ.Add("NumPacksOra", numPackOra); + answ.Add("PercRiemp", percRiemp); + answ.Add("VelFruttiMinuto", velFruttiMinuto); + answ.Add("VelTonnOra", velTonnOra); + return answ; + } + + #endregion Internal Methods #region Private Properties diff --git a/EgwProxy.Icoel/Connector.cs b/EgwProxy.Icoel/Connector.cs index 30bb284e..a25cd862 100644 --- a/EgwProxy.Icoel/Connector.cs +++ b/EgwProxy.Icoel/Connector.cs @@ -38,6 +38,38 @@ namespace EgwProxy.Icoel Client.CheckGrower(GrowerData.GrowerCode, GrowerData.GrowerName); } } + /// + /// Recupera array varie velocità rilevate + /// + /// Dictionary delle velocità rilevate sul sizer + public Dictionary GetPerfMeters() + { + Dictionary answ = new Dictionary(); + using (var Client = new ComClient(ipAddress, tcpPort)) + { + answ = Client.GetPerfMeters(); + } + return answ; + } + + + /// + /// Recupera array dei batch sulle 2 linee: ID batch + layout + varietà x ogni linea... + /// + /// Dictionary dei dati correnti x linea (batch, layout, variety) rilevate sul sizer + public Dictionary GetCurrBatchData() + { + Dictionary answ = new Dictionary(); + var batchData = GetCurrentBatch(); + foreach (var item in batchData) + { + answ.Add($"L{item.Key}_Batch", $"{item.Value.Id} | {item.Value.Name} | {item.Value.StartTime}"); + answ.Add($"L{item.Key}_Grower", $"{item.Value.GrowerCode}"); + answ.Add($"L{item.Key}_Layout", $"{item.Value.LayoutId} | {item.Value.LayoutName}"); + answ.Add($"L{item.Key}_Variety", $"{item.Value.VarietyId} | {item.Value.VarietyName}"); + } + return answ; + } /// /// Invia un lotto in coda produzione sul sizer diff --git a/EgwProxy.Icoel/DbProxy.cs b/EgwProxy.Icoel/DbProxy.cs new file mode 100644 index 00000000..a9045a63 --- /dev/null +++ b/EgwProxy.Icoel/DbProxy.cs @@ -0,0 +1,42 @@ +using EgwProxy.Icoel.DataLayer.Controllers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EgwProxy.Icoel +{ + /// + /// Proxy connessione DB + /// + public class DbProxy + { + /// + /// Controller DB esposto + /// + public DbController DataController { get; set; } + +#if false + /// + /// Inizializzazione proxy + /// + /// stringa connesisone DB Entrata + /// stringa connesisone DB Tracker + /// stringa connesisone DB Export + /// Connessione DB locale di SYNC + public DbProxy(string connEntrata, string connTracker, string connExport, string connSyncState) + { + DataController = new DbController(connEntrata, connTracker, connExport, connSyncState); + } +#endif + /// + /// Inizializzazione proxy + /// + /// Connessione DB locale di SYNC + public DbProxy(string connSyncState) + { + DataController = new DbController(connSyncState); + } + } +} diff --git a/EgwProxy.Icoel/EgwProxy.Icoel.csproj b/EgwProxy.Icoel/EgwProxy.Icoel.csproj index 77e5750a..c3552784 100644 --- a/EgwProxy.Icoel/EgwProxy.Icoel.csproj +++ b/EgwProxy.Icoel/EgwProxy.Icoel.csproj @@ -39,12 +39,17 @@ + + ..\packages\NLog.4.7.9\lib\net45\NLog.dll + + + @@ -54,6 +59,7 @@ + True @@ -135,6 +141,7 @@ + @@ -155,5 +162,11 @@ Reference.cs + + + {e36544cb-d699-48d8-9f81-c2758e7c7d19} + EgwProxy.Icoel.DataLayer + + \ No newline at end of file diff --git a/EgwProxy.Icoel/packages.config b/EgwProxy.Icoel/packages.config new file mode 100644 index 00000000..1a6b20de --- /dev/null +++ b/EgwProxy.Icoel/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/EgwProxy.MultiCncLib/CNC/CNC.FANUC/CNC.FANUC.vb b/EgwProxy.MultiCncLib/CNC/CNC.FANUC/CNC.FANUC.vb index c6e92a67..913522f8 100644 --- a/EgwProxy.MultiCncLib/CNC/CNC.FANUC/CNC.FANUC.vb +++ b/EgwProxy.MultiCncLib/CNC/CNC.FANUC/CNC.FANUC.vb @@ -1098,7 +1098,8 @@ Namespace CNC Dim sz_routine As String = "-", sz_temp As String = "", d As Double = 0.0 Try - If nVar >= &H8000 Then ' if var like 98xxx then use the other read routine .... ( :(( no comment ) + If nVar >= 10000 Then ' if var like 98xxx then use the other read routine .... ( :(( no comment ) + 'If nVar >= &H8000 Then ' if var like 98xxx then use the other read routine .... ( :(( no comment ) n_ret_code = Focas1.cnc_rdmacror3(nLibHandle(1), nVar, ONE_DATA_ONLY, MacroInfo3) diff --git a/IOB-MAN/App.config b/IOB-MAN/App.config index 929d1f27..376f58be 100644 --- a/IOB-MAN/App.config +++ b/IOB-MAN/App.config @@ -43,7 +43,7 @@ - + @@ -51,7 +51,7 @@ - + @@ -59,7 +59,7 @@ - + @@ -67,7 +67,7 @@ - + @@ -95,6 +95,10 @@ + + + + diff --git a/IOB-MAN/App_Readme/README_SteamWare.txt b/IOB-MAN/App_Readme/README_SteamWare.txt index bf60ed18..954eff8b 100644 --- a/IOB-MAN/App_Readme/README_SteamWare.txt +++ b/IOB-MAN/App_Readme/README_SteamWare.txt @@ -1,5 +1,5 @@ --------------------------------------------------------------- -------- SteamWareLib SDK ------- +------- SteamWare SDK ------- --------------------------------------------------------------- Libreria di utility base di SteamWare. diff --git a/IOB-MAN/Core/Compression/Snappy/lib/linux/libsnappy64.so b/IOB-MAN/Core/Compression/Snappy/lib/linux/libsnappy64.so new file mode 100644 index 00000000..584bedfc Binary files /dev/null and b/IOB-MAN/Core/Compression/Snappy/lib/linux/libsnappy64.so differ diff --git a/IOB-MAN/Core/Compression/Snappy/lib/osx/libsnappy64.dylib b/IOB-MAN/Core/Compression/Snappy/lib/osx/libsnappy64.dylib new file mode 100644 index 00000000..bbce3c21 Binary files /dev/null and b/IOB-MAN/Core/Compression/Snappy/lib/osx/libsnappy64.dylib differ diff --git a/IOB-MAN/Core/Compression/Zstandard/lib/linux/libzstd.so b/IOB-MAN/Core/Compression/Zstandard/lib/linux/libzstd.so new file mode 100644 index 00000000..8309c49b Binary files /dev/null and b/IOB-MAN/Core/Compression/Zstandard/lib/linux/libzstd.so differ diff --git a/IOB-MAN/Core/Compression/Zstandard/lib/osx/libzstd.dylib b/IOB-MAN/Core/Compression/Zstandard/lib/osx/libzstd.dylib new file mode 100644 index 00000000..5400d760 Binary files /dev/null and b/IOB-MAN/Core/Compression/Zstandard/lib/osx/libzstd.dylib differ diff --git a/IOB-MAN/IOB-MAN.csproj b/IOB-MAN/IOB-MAN.csproj index c149f9bd..f4c3cc5e 100644 --- a/IOB-MAN/IOB-MAN.csproj +++ b/IOB-MAN/IOB-MAN.csproj @@ -38,42 +38,38 @@ IobManIcon.ico - - ..\packages\Crc32C.NET.1.0.5.0\lib\net20\Crc32C.NET.dll - - - ..\packages\DnsClient.1.5.0\lib\net45\DnsClient.dll + + ..\packages\DnsClient.1.6.0\lib\net45\DnsClient.dll ..\packages\SharpZipLib.1.3.3\lib\net45\ICSharpCode.SharpZipLib.dll - - ..\packages\MapoSDK.6.14.2109.2809\lib\net40\MapoSDK.dll + + ..\packages\MapoSDK.6.14.2204.2616\lib\MapoSDK.dll - - ..\packages\Microsoft.Bcl.AsyncInterfaces.5.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll + + ..\packages\Microsoft.Bcl.AsyncInterfaces.6.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll - - ..\packages\MongoDB.Bson.2.13.2\lib\net452\MongoDB.Bson.dll + + ..\packages\MongoDB.Bson.2.15.0\lib\netstandard2.0\MongoDB.Bson.dll - - ..\packages\MongoDB.Driver.2.13.2\lib\net452\MongoDB.Driver.dll + + ..\packages\MongoDB.Driver.2.15.0\lib\netstandard2.0\MongoDB.Driver.dll - - ..\packages\MongoDB.Driver.Core.2.13.2\lib\net452\MongoDB.Driver.Core.dll + + ..\packages\MongoDB.Driver.Core.2.15.0\lib\netstandard2.0\MongoDB.Driver.Core.dll - - ..\packages\MongoDB.Libmongocrypt.1.2.3\lib\netstandard2.0\MongoDB.Libmongocrypt.dll + + ..\packages\MongoDB.Libmongocrypt.1.3.0\lib\netstandard2.0\MongoDB.Libmongocrypt.dll ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll - ..\packages\NLog.4.7.12\lib\net45\NLog.dll - True + ..\packages\NLog.4.7.15\lib\net45\NLog.dll - ..\packages\Pipelines.Sockets.Unofficial.2.2.0\lib\net461\Pipelines.Sockets.Unofficial.dll + ..\packages\Pipelines.Sockets.Unofficial.2.2.2\lib\net461\Pipelines.Sockets.Unofficial.dll ..\packages\RestSharp.106.15.0\lib\net452\RestSharp.dll @@ -81,23 +77,20 @@ ..\packages\RestSharp.Serializers.NewtonsoftJson.106.15.0\lib\net452\RestSharp.Serializers.NewtonsoftJson.dll - - ..\packages\SharpCompress.0.30.0\lib\net461\SharpCompress.dll - - - ..\packages\Snappy.NET.1.1.1.8\lib\net45\Snappy.NET.dll + + ..\packages\SharpCompress.0.31.0\lib\net461\SharpCompress.dll - ..\packages\StackExchange.Redis.2.2.79\lib\net461\StackExchange.Redis.dll + ..\packages\StackExchange.Redis.2.5.61\lib\net461\StackExchange.Redis.dll - - ..\packages\SteamWare.IO.5.1.2109.1716\lib\net462\SteamWare.IO.dll + + ..\packages\SteamWare.IO.5.2.2205.1719\lib\net462\SteamWare.IO.dll - - ..\packages\SteamWare.Logger.5.1.2109.1716\lib\net462\SteamWare.Logger.dll + + ..\packages\SteamWare.Logger.5.2.2205.1719\lib\net462\SteamWare.Logger.dll - - ..\packages\Steamware.Scheduler.5.1.2109.1716\lib\net462\Steamware.Scheduler.dll + + ..\packages\SteamWare.Scheduler.5.2.2205.1719\lib\net462\SteamWare.Scheduler.dll @@ -105,8 +98,8 @@ - - ..\packages\System.Diagnostics.PerformanceCounter.5.0.1\lib\net461\System.Diagnostics.PerformanceCounter.dll + + ..\packages\System.Diagnostics.PerformanceCounter.6.0.1\lib\net461\System.Diagnostics.PerformanceCounter.dll ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll @@ -114,8 +107,8 @@ True - - ..\packages\System.IO.Pipelines.5.0.1\lib\net461\System.IO.Pipelines.dll + + ..\packages\System.IO.Pipelines.6.0.2\lib\net461\System.IO.Pipelines.dll ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll @@ -129,8 +122,8 @@ ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll - - ..\packages\System.Runtime.CompilerServices.Unsafe.5.0.0\lib\net45\System.Runtime.CompilerServices.Unsafe.dll + + ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll @@ -159,11 +152,11 @@ True - - ..\packages\System.Text.Encoding.CodePages.5.0.0\lib\net461\System.Text.Encoding.CodePages.dll + + ..\packages\System.Text.Encoding.CodePages.6.0.0\lib\net461\System.Text.Encoding.CodePages.dll - - ..\packages\System.Threading.Channels.5.0.0\lib\net461\System.Threading.Channels.dll + + ..\packages\System.Threading.Channels.6.0.0\lib\net461\System.Threading.Channels.dll ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll @@ -236,6 +229,10 @@ + + + + Always @@ -276,13 +273,13 @@ - + - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + Questo progetto fa riferimento a uno o più pacchetti NuGet che non sono presenti in questo computer. Usare lo strumento di ripristino dei pacchetti NuGet per scaricarli. Per altre informazioni, vedere http://go.microsoft.com/fwlink/?LinkID=322105. Il file mancante è {0}. - - + + - + \ No newline at end of file diff --git a/IOB-MAN/IOBManPanel.cs b/IOB-MAN/IOBManPanel.cs index 55028d14..6289073a 100644 --- a/IOB-MAN/IOBManPanel.cs +++ b/IOB-MAN/IOBManPanel.cs @@ -2,7 +2,7 @@ using Newtonsoft.Json; using RestSharp; using RestSharp.Serializers.NewtonsoftJson; -using Steamware.Scheduler; +using SteamWare.Scheduler; using SteamWare.IO; using SteamWare.Logger; using System; diff --git a/IOB-MAN/NLog.config b/IOB-MAN/NLog.config index 350bebf8..124f6170 100644 --- a/IOB-MAN/NLog.config +++ b/IOB-MAN/NLog.config @@ -12,7 +12,7 @@ name="f_base" fileName="${logDir}/${var:codIOB:default=0000}/${shortdate}.log" layout="${longdate} [${uppercase:${level}}] ${logger:shortName=true}|${message}" - archiveFileName="${logDir}/${var:codIOB:default=0000}/${shortdate}.{###}.zip" + archiveFileName="${logDir}/${var:codIOB:default=0000}/${shortdate}.{###}.log" archiveNumbering="Sequence" archiveAboveSize="10240000" maxArchiveFiles="60" @@ -23,7 +23,7 @@ name="f_error" fileName="${logDir}/${var:codIOB:default=0000}/${shortdate}.log" layout="${longdate} [${uppercase:${level}}] ${logger:shortName=true}|${message}${newline}${exception:format=tostring}" - archiveFileName="${logDir}/${var:codIOB:default=0000}/${shortdate}.{###}.zip" + archiveFileName="${logDir}/${var:codIOB:default=0000}/${shortdate}.{###}.log" archiveNumbering="Sequence" archiveAboveSize="10240000" maxArchiveFiles="60" diff --git a/IOB-MAN/RedisMan.cs b/IOB-MAN/RedisMan.cs index 9fd85ad4..c550295c 100644 --- a/IOB-MAN/RedisMan.cs +++ b/IOB-MAN/RedisMan.cs @@ -29,6 +29,16 @@ namespace IOB_MAN /// public float counterMAC { get; set; } = 0; + /// + /// Ultimo stato noto dei parametri in memoria letti dalla macchina + /// + public Dictionary currParams { get; set; } = new Dictionary(); + + /// + /// Note (libere) da child a controller + /// + public string freeNotes { get; set; } = ""; + /// /// Tipo IOB /// @@ -39,6 +49,11 @@ namespace IOB_MAN /// public DateTime lastDataIn { get; set; } = DateTime.Now.AddMinutes(-1); + /// + /// DataOra ultima comunicazione OUT (con MP Server) + /// + public DateTime lastDataOut { get; set; } = DateTime.Now.AddDays(-1); + /// /// DataOra ultima comunicazione OUT (con MP Server) /// @@ -49,21 +64,6 @@ namespace IOB_MAN /// public bool online { get; set; } = false; -#if false - /// - /// Indica se sia correntemente in setup - /// - public bool inSetup { get; set; } = false; - /// - /// Semaforo IN (IOB-PLC) - /// - public Semaforo SemIn { get; set; } = Semaforo.ND; - /// - /// Semaforo OUT (IOB-MPserver) - /// - public Semaforo SemOut { get; set; } = Semaforo.ND; -#endif - /// /// Lungh coda ALLARMI in uscita /// @@ -84,73 +84,26 @@ namespace IOB_MAN /// public int queueMsLen { get; set; } = 0; - #endregion Public Properties + /// + /// Semaforo IN (IOB-Macchina) + /// + public string semIn { get; set; } = "ND"; -#if false - /// - /// DataOra ultima comunicazione OUT (con MP Server) - /// - public DateTime lastDataOut { get; set; } = DateTime.Now.AddDays(-1); - /// - /// Ultimo stato noto dei parametri in memoria letti da PLC - /// - public Dictionary currParams { get; set; } = null; -#endif + /// + /// Semaforo OUT (IOB-MPServer) + /// + public string semOut { get; set; } = "ND"; + + /// + /// Parametri configurazione (es IP target, porta, ...) + /// + public Dictionary setupParams { get; set; } = new Dictionary(); + + #endregion Public Properties } public class RedisIobCache { - #region Private Fields - - /// - /// Connessione lazy a redis... - /// - private Lazy lazyConnection = new Lazy(() => - { - string RedisConn = utils.CRS("RedisConn"); - if (string.IsNullOrEmpty(RedisConn)) - { - RedisConn = "localhost,abortConnect=false,ssl=false"; - } - - return ConnectionMultiplexer.Connect(RedisConn); - }); - - /// - /// Connessione lazy a redis... - /// - private Lazy lazyConnectionAdmin = new Lazy(() => - { - string RedisConnAdmin = utils.CRS("RedisConnAdmin"); - if (string.IsNullOrEmpty(RedisConnAdmin)) - { - RedisConnAdmin = "localhost,abortConnect=false,ssl=false,allowAdmin=true"; - } - - return ConnectionMultiplexer.Connect(RedisConnAdmin); - }); - - #endregion Private Fields - - #region Protected Fields - - /// - /// Cod IOB - /// - protected string CodIob = "000"; - - /// - /// Hash redis x dati IOB - /// - protected string redIobKey = ""; - - /// - /// Hash redis x dati server - /// - protected string redServKey = ""; - - #endregion Protected Fields - #region Public Constructors /// @@ -225,15 +178,6 @@ namespace IOB_MAN #endregion Public Enums - #region Private Properties - - /// - /// Oggetto currentDb locale - /// - private IDatabase _currDB { get; set; } - - #endregion Private Properties - #region Public Properties /// @@ -385,36 +329,11 @@ namespace IOB_MAN #endregion Public Properties - #region Private Methods - - /// - /// Effettua comaprazione x CHIAVE in KVP ASC - /// - /// - /// - /// - private int CompareKey(KeyValuePair x, KeyValuePair y) - { - return x.Key.CompareTo(y.Key); - } - - /// - /// Effettua comaprazione x CHIAVE in KVP DESC - /// - /// - /// - /// - private int CompareKeyDesc(KeyValuePair x, KeyValuePair y) - { - return y.Key.CompareTo(x.Key); - } - - #endregion Private Methods - #region Public Methods /// - /// Nome della variabile HASH da utilizzare (dato CodModulo / Server / DB impiegato da funzionalita' DbConfig) + keyName richiesto... + /// Nome della variabile HASH da utilizzare (dato CodModulo / Server / DB impiegato da + /// funzionalita' DbConfig) + keyName richiesto... /// public static string redHash(string keyName) { @@ -556,8 +475,7 @@ namespace IOB_MAN public int redCountKey(string keyPattern) { int answ = 0; - // cerco se ci sia valore in redis... - // se vuoto = ALL... + // cerco se ci sia valore in redis... se vuoto = ALL... keyPattern = string.IsNullOrEmpty(keyPattern) ? "**" : keyPattern; try { @@ -607,8 +525,7 @@ namespace IOB_MAN public bool redFlushKey(string keyPattern) { bool answ = false; - // cerco se ci sia valore in redis... - // se vuoto = ALL... + // cerco se ci sia valore in redis... se vuoto = ALL... keyPattern = string.IsNullOrEmpty(keyPattern) ? "**" : keyPattern; try { @@ -895,7 +812,9 @@ namespace IOB_MAN /// /// chiave /// valori - /// scadenza preimpostata hash (secondi) | defaoult = -1 (non scade) + /// + /// scadenza preimpostata hash (secondi) | defaoult = -1 (non scade) + /// /// public bool redSaveHash(string hashKey, KeyValuePair[] hashFields, double expireSeconds = -1) { @@ -953,7 +872,9 @@ namespace IOB_MAN /// /// chiave /// valori - /// scadenza preimpostata hash (secondi) | defaoult = -1 (non scade) + /// + /// scadenza preimpostata hash (secondi) | defaoult = -1 (non scade) + /// /// public bool redSaveHashDict(string hashKey, Dictionary hashFields, double expireSeconds = -1) { @@ -1109,7 +1030,7 @@ namespace IOB_MAN } /// - /// Salva un set KVP (Key Value Pair) in RedisCache + /// Salva un set KVP (Key Value Pair) in RedisCache /// /// Set KVP chiave-valore da salvare /// @@ -1174,6 +1095,92 @@ namespace IOB_MAN } #endregion Public Methods + + #region Protected Fields + + /// + /// Cod IOB + /// + protected string CodIob = "000"; + + /// + /// Hash redis x dati IOB + /// + protected string redIobKey = ""; + + /// + /// Hash redis x dati server + /// + protected string redServKey = ""; + + #endregion Protected Fields + + #region Private Fields + + /// + /// Connessione lazy a redis... + /// + private Lazy lazyConnection = new Lazy(() => + { + string RedisConn = utils.CRS("RedisConn"); + if (string.IsNullOrEmpty(RedisConn)) + { + RedisConn = "localhost,abortConnect=false,ssl=false"; + } + + return ConnectionMultiplexer.Connect(RedisConn); + }); + + /// + /// Connessione lazy a redis... + /// + private Lazy lazyConnectionAdmin = new Lazy(() => + { + string RedisConnAdmin = utils.CRS("RedisConnAdmin"); + if (string.IsNullOrEmpty(RedisConnAdmin)) + { + RedisConnAdmin = "localhost,abortConnect=false,ssl=false,allowAdmin=true"; + } + + return ConnectionMultiplexer.Connect(RedisConnAdmin); + }); + + #endregion Private Fields + + #region Private Properties + + /// + /// Oggetto currentDb locale + /// + private IDatabase _currDB { get; set; } + + #endregion Private Properties + + #region Private Methods + + /// + /// Effettua comaprazione x CHIAVE in KVP ASC + /// + /// + /// + /// + private int CompareKey(KeyValuePair x, KeyValuePair y) + { + return x.Key.CompareTo(y.Key); + } + + /// + /// Effettua comaprazione x CHIAVE in KVP DESC + /// + /// + /// + /// + private int CompareKeyDesc(KeyValuePair x, KeyValuePair y) + { + return y.Key.CompareTo(x.Key); + } + + #endregion Private Methods } /// diff --git a/IOB-MAN/Resources/NLog._demo.config b/IOB-MAN/Resources/NLog._demo.config index b144b03e..490ed2bc 100644 --- a/IOB-MAN/Resources/NLog._demo.config +++ b/IOB-MAN/Resources/NLog._demo.config @@ -48,12 +48,12 @@ name="f" fileName="${logDir}/${var:codIOB:default=0000}/${shortdate}.log" layout="${longdate} [${uppercase:${level}}] ${logger:shortName=true}|${message}|${exception:format=tostring}" - archiveFileName="${logDir}/${var:codIOB:default=0000}/${shortdate}.{###}.zip" + archiveFileName="${logDir}/${var:codIOB:default=0000}/${shortdate}.{###}.log" archiveNumbering="Sequence" archiveEvery="Day" archiveOldFileOnStartup="true" maxArchiveFiles="90" - enableArchiveFileCompression="true" + enableArchiveFileCompression="false" keepFileOpen="true" />--> diff --git a/IOB-MAN/Resources/NLog.template.config b/IOB-MAN/Resources/NLog.template.config index 216df569..515b7ac3 100644 --- a/IOB-MAN/Resources/NLog.template.config +++ b/IOB-MAN/Resources/NLog.template.config @@ -12,7 +12,7 @@ name="f_base" fileName="${logDir}/${var:codIOB:default=0000}/${shortdate}.log" layout="${longdate} [${uppercase:${level}}] ${logger:shortName=true}|${message}" - archiveFileName="${logDir}/${var:codIOB:default=0000}/${shortdate}.{###}.zip" + archiveFileName="${logDir}/${var:codIOB:default=0000}/${shortdate}.{###}.log" archiveNumbering="Sequence" archiveAboveSize="10240000" maxArchiveFiles="60" @@ -23,7 +23,7 @@ name="f_error" fileName="${logDir}/${var:codIOB:default=0000}/${shortdate}.log" layout="${longdate} [${uppercase:${level}}] ${logger:shortName=true}|${message}${newline}${exception:format=tostring}" - archiveFileName="${logDir}/${var:codIOB:default=0000}/${shortdate}.{###}.zip" + archiveFileName="${logDir}/${var:codIOB:default=0000}/${shortdate}.{###}.log" archiveNumbering="Sequence" archiveAboveSize="10240000" maxArchiveFiles="60" @@ -33,7 +33,7 @@ - + diff --git a/IOB-MAN/packages.config b/IOB-MAN/packages.config index a762bb63..fc4b5a6f 100644 --- a/IOB-MAN/packages.config +++ b/IOB-MAN/packages.config @@ -1,43 +1,41 @@  - - - - - - - - + + + + + + + - + - + - + - - - - - + + + + - + - + - + - - + + \ No newline at end of file diff --git a/IOB-UT-NEXT/BinaryFormatter.cs b/IOB-UT-NEXT/BinaryFormatter.cs index a91b074e..0619bf95 100644 --- a/IOB-UT-NEXT/BinaryFormatter.cs +++ b/IOB-UT-NEXT/BinaryFormatter.cs @@ -6,20 +6,6 @@ namespace IOB_UT_NEXT { public class BinaryUtils : IFormatProvider, ICustomFormatter { - #region Private Methods - - private string HandleOtherFormats(string format, object arg) - { - if (arg is IFormattable) - return ((IFormattable)arg).ToString(format, CultureInfo.CurrentCulture); - else if (arg != null) - return arg.ToString(); - else - return String.Empty; - } - - #endregion Private Methods - #region Public Methods // Format number in binary (B), octal (O), or hexadecimal (H). @@ -29,8 +15,7 @@ namespace IOB_UT_NEXT int baseNumber; // Handle null or empty format string, string with precision specifier. string thisFmt = String.Empty; - // Extract first character of format string (precision specifiers - // are not supported). + // Extract first character of format string (precision specifiers are not supported). if (!String.IsNullOrEmpty(format)) thisFmt = format.Length > 1 ? format.Substring(0, 1) : format; @@ -140,5 +125,19 @@ namespace IOB_UT_NEXT } #endregion Public Methods + + #region Private Methods + + private string HandleOtherFormats(string format, object arg) + { + if (arg is IFormattable) + return ((IFormattable)arg).ToString(format, CultureInfo.CurrentCulture); + else if (arg != null) + return arg.ToString(); + else + return String.Empty; + } + + #endregion Private Methods } } \ No newline at end of file diff --git a/IOB-UT-NEXT/Enums.cs b/IOB-UT-NEXT/Enums.cs index 92572e53..e4b87443 100644 --- a/IOB-UT-NEXT/Enums.cs +++ b/IOB-UT-NEXT/Enums.cs @@ -1,6 +1,4 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using System; +using System; namespace IOB_UT_NEXT { @@ -309,6 +307,11 @@ namespace IOB_UT_NEXT /// MODBUS_TCP_CEDAX, + /// + /// Adapter ModBus TCP versione Centerfrigo (Giacovelli) + /// + MODBUS_TCP_CENTERFRIGO, + /// /// Adapter ModBus TCP versione HAM (Pizzaferri) /// @@ -439,6 +442,11 @@ namespace IOB_UT_NEXT /// SIEMENS_LASCO, + /// + /// Adapter SIEMENS, interfaccia versione NWSE (Giacovelli, impianto filtrazione NWS) + /// + SIEMENS_NWSE, + /// /// Adapter SIEMENS, interfaccia versione PRESSOIL + CEI (Valvital, Pressa Idraulica) /// @@ -470,35 +478,6 @@ namespace IOB_UT_NEXT WPS } -#if false - /// - /// Enumerazione tipi di semaforo - /// - public enum Semaforo - { - /// - /// Stato non definito - /// - ND, - /// - /// Verde - /// - SV, - /// - /// Giallo - /// - SG, - /// - /// Rosso - /// - SR, - /// - /// Grigio/Spento - /// - SS - } -#endif - /// /// Enumerazione tipi di tipi di URL x invio /// @@ -514,30 +493,14 @@ namespace IOB_UT_NEXT /// SignIN, + /// + /// Salvataggio RawTransf (valori raw da decodificare a valle) + /// + RawTransf, + /// /// Salvataggio UserLog (valori log attività utente) /// ULog } - - /// - /// Tipologia dato Raw Transfer (derivare da MapoSdk e togliere qui) - /// - /// serializzazione Native - /// [JsonConverter(typeof(JsonStringEnumConverter))] - /// serializzazione Newtonsoft json - /// [JsonConverter(typeof(StringEnumConverter))] - [JsonConverter(typeof(StringEnumConverter))] - public enum rawTransfType - { - ND = 0, - /// - /// Icoel: Batch info - /// - IcoelBatch, - /// - /// Icoel: Variety + layout info relative - /// - IcoelVarInfo - } } \ No newline at end of file diff --git a/IOB-UT-NEXT/Eurom63.cs b/IOB-UT-NEXT/Eurom63.cs index d601eabe..0ffba8c9 100644 --- a/IOB-UT-NEXT/Eurom63.cs +++ b/IOB-UT-NEXT/Eurom63.cs @@ -1,8 +1,5 @@ using System; using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; namespace IOB_UT_NEXT { @@ -39,7 +36,8 @@ namespace IOB_UT_NEXT TimeSet, /// - /// Verificato il canale di comunicazione è OK, fatta pulizia con AbortAll, NON ci sono report attivi + /// Verificato il canale di comunicazione è OK, fatta pulizia con AbortAll, NON ci sono + /// report attivi /// ChannelOk, @@ -135,7 +133,8 @@ namespace IOB_UT_NEXT public int PzPallet { get; set; } = 1; /// - /// Indica se sia possibile impostare i pezzi pallet dal server, ed in tal caso moltiplica i pezzi letti dalla macchina per il valore pzPallet (vedi sopra) + /// Indica se sia possibile impostare i pezzi pallet dal server, ed in tal caso + /// moltiplica i pezzi letti dalla macchina per il valore pzPallet (vedi sopra) /// public bool SetPzPalletFromSrv { get; set; } = false; @@ -170,7 +169,8 @@ namespace IOB_UT_NEXT public List FileList { get; set; } = new List(); /// - /// Numero MAX di esecuzioni da mantenere in HIST prima di eliminare i + vecchi (fare folder HIST\SESSnnnn) + /// Numero MAX di esecuzioni da mantenere in HIST prima di eliminare i + vecchi (fare + /// folder HIST\SESSnnnn) /// public int Max2Keep { get; set; } = 50; @@ -190,7 +190,7 @@ namespace IOB_UT_NEXT public string RespOk { get; set; } = "PROCESSED"; /// - /// Seconds before do a new retry (default = 0 --> no veto) + /// Seconds before do a new retry (default = 0 --> no veto) /// public double RetrySec { get; set; } = 0; diff --git a/IOB-UT-NEXT/IOB-UT-NEXT.csproj b/IOB-UT-NEXT/IOB-UT-NEXT.csproj index 8dbe51fe..1fdf8d09 100644 --- a/IOB-UT-NEXT/IOB-UT-NEXT.csproj +++ b/IOB-UT-NEXT/IOB-UT-NEXT.csproj @@ -59,8 +59,8 @@ ..\packages\SharpZipLib.1.3.1\lib\net45\ICSharpCode.SharpZipLib.dll - - ..\packages\MapoSDK.6.14.2204.2616\lib\MapoSDK.dll + + ..\packages\MapoSDK.6.14.2205.2808\lib\MapoSDK.dll ..\packages\Microsoft.Bcl.AsyncInterfaces.6.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll @@ -123,6 +123,7 @@ + @@ -134,7 +135,6 @@ - diff --git a/IOB-UT-NEXT/IniFile.cs b/IOB-UT-NEXT/IniFile.cs index 1ea22447..a23f2453 100644 --- a/IOB-UT-NEXT/IniFile.cs +++ b/IOB-UT-NEXT/IniFile.cs @@ -1,7 +1,7 @@ using System; +using System.Globalization; using System.Runtime.InteropServices; using System.Text; -using System.Globalization; namespace IOB_UT_NEXT { @@ -16,9 +16,6 @@ namespace IOB_UT_NEXT #endregion Public Fields - // INI filename - - // import windows dll functions #region Public Constructors @@ -33,25 +30,6 @@ namespace IOB_UT_NEXT #endregion Public Constructors - #region Private Methods - - [DllImport("kernel32")] - private static extern int GetPrivateProfileInt(string section, string key, int def, string filePath); - - [DllImport("kernel32")] - private static extern int GetPrivateProfileSection(string section, IntPtr retVal, uint size, string filePath); - - [DllImport("kernel32")] - private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath); - - [DllImport("kernel32")] - private static extern bool WritePrivateProfileSection(string section, string value, string filePath); - - [DllImport("kernel32", CharSet = CharSet.Auto, BestFitMapping = false)] - private static extern long WritePrivateProfileString(string section, string key, string val, string filePath); - - #endregion Private Methods - #region Public Methods /// @@ -149,7 +127,9 @@ namespace IOB_UT_NEXT /// /// /// Section name - /// restituisce delle stringhe keys=values da suddividere appunto come key/val successivamente + /// + /// restituisce delle stringhe keys=values da suddividere appunto come key/val successivamente + /// public string[] ReadSection(string Section) { const int bufferSize = 2048; // max is 32767 @@ -270,5 +250,68 @@ namespace IOB_UT_NEXT } #endregion Public Methods + + #region Private Methods + + + // INI filename + + /// + /// GetPrivateProfileInt: import windows dll functions + /// + /// + /// + /// + /// + /// + [DllImport("kernel32")] + private static extern int GetPrivateProfileInt(string section, string key, int def, string filePath); + + /// + /// GetPrivateProfileSection: import windows dll functions + /// + /// + /// + /// + /// + /// + [DllImport("kernel32")] + private static extern int GetPrivateProfileSection(string section, IntPtr retVal, uint size, string filePath); + + /// + /// GetPrivateProfileString: import windows dll functions + /// + /// + /// + /// + /// + /// + /// + /// + [DllImport("kernel32")] + private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath); + + /// + /// WritePrivateProfileSection: import windows dll functions + /// + /// + /// + /// + /// + [DllImport("kernel32")] + private static extern bool WritePrivateProfileSection(string section, string value, string filePath); + + /// + /// WritePrivateProfileString: import windows dll functions + /// + /// + /// + /// + /// + /// + [DllImport("kernel32", CharSet = CharSet.Auto, BestFitMapping = false)] + private static extern long WritePrivateProfileString(string section, string key, string val, string filePath); + + #endregion Private Methods } } \ No newline at end of file diff --git a/IOB-UT-NEXT/IobWinStatus.cs b/IOB-UT-NEXT/IobWinStatus.cs new file mode 100644 index 00000000..2422f53b --- /dev/null +++ b/IOB-UT-NEXT/IobWinStatus.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; + +namespace IOB_UT_NEXT +{ + /// + /// Rappresentazione dello stato corrente dell'IOB + /// + public class IobWinStatus + { + #region Public Properties + + /// + /// ID univoco + /// + public string CodIob { get; set; } = "0"; + + /// + /// Contatore IOB + /// + public float counterIOB { get; set; } = 0; + + /// + /// Contatore Macchina + /// + public float counterMAC { get; set; } = 0; + + /// + /// Ultimo stato noto dei parametri in memoria letti dalla macchina + /// + public Dictionary currParams { get; set; } = new Dictionary(); + + /// + /// Note (libere) da child a controller + /// + public string freeNotes { get; set; } = ""; + + /// + /// Tipo IOB + /// + public string IobType { get; set; } = ""; + + /// + /// DataOra ultima comunicazione IN (con PLC) + /// + public DateTime lastDataIn { get; set; } = DateTime.Now.AddMinutes(-1); + + /// + /// DataOra ultima comunicazione OUT (con MP Server) + /// + public DateTime lastDataOut { get; set; } = DateTime.Now.AddDays(-1); + + /// + /// DataOra ultima comunicazione OUT (con MP Server) + /// + public DateTime lastUpdate { get; set; } = DateTime.Now.AddDays(-1); + + /// + /// Status del SINGOLO IOB + /// + public bool online { get; set; } = false; + + /// + /// Lungh coda ALLARMI in uscita + /// + public int queueAlLen { get; set; } = 0; + + /// + /// Lunghezza coda EVENTI in uscita + /// + public int queueEvLen { get; set; } = 0; + + /// + /// Lunghezza coda FluxLog in uscita + /// + public int queueFlLen { get; set; } = 0; + + /// + /// Lungh coda MESSAGGI in uscita + /// + public int queueMsLen { get; set; } = 0; + + /// + /// Lungh coda UserLog in uscita + /// + public int queueRawTransfLen { get; set; } = 0; + + /// + /// Lungh coda UserLog in uscita + /// + public int queueUlLen { get; set; } = 0; + + /// + /// Semaforo IN (IOB-Macchina) + /// + public string semIn { get; set; } = "ND"; + + /// + /// Semaforo OUT (IOB-MPServer) + /// + public string semOut { get; set; } = "ND"; + + /// + /// Parametri configurazione (es IP target, porta, ...) + /// + public Dictionary setupParams { get; set; } = new Dictionary(); + + #endregion Public Properties + + #region Public Methods + + /// + /// Override metodo di equality + /// + /// + /// + public override bool Equals(object obj) + { + if (!(obj is IobWinStatus item)) + return false; + + if (online != item.online) + return false; + // controllo se sia ALMENO 1 sec... + if (lastDataIn != item.lastDataIn) + { + if (lastDataIn.Subtract(item.lastDataIn).TotalSeconds > 1) + return false; + } + // controllo se sia ALMENO 1 sec... + if (lastDataOut != item.lastDataOut) + { + if (lastDataOut.Subtract(item.lastDataOut).TotalSeconds > 1) + return false; + } + if (semIn != item.semIn) + return false; + if (semOut != item.semOut) + return false; + //if (!currParams.Equals(item.currParams)) + // return false; + if (counterIOB != item.counterIOB) + return false; + if (counterMAC != item.counterMAC) + return false; + if (queueAlLen != item.queueAlLen) + return false; + if (queueEvLen != item.queueEvLen) + return false; + if (queueFlLen != item.queueFlLen) + return false; + if (queueMsLen != item.queueMsLen) + return false; + if (queueRawTransfLen != item.queueRawTransfLen) + return false; + if (queueUlLen != item.queueUlLen) + return false; + if (freeNotes != item.freeNotes) + return false; + //if (setupParams != item.setupParams) + // return false; + if (IobType != item.IobType) + return false; + if (CodIob != item.CodIob) + return false; + + return true; + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + #endregion Public Methods + } +} \ No newline at end of file diff --git a/IOB-UT-NEXT/Logging.cs b/IOB-UT-NEXT/Logging.cs index ab425119..795dfd44 100644 --- a/IOB-UT-NEXT/Logging.cs +++ b/IOB-UT-NEXT/Logging.cs @@ -1,15 +1,10 @@ using NLog; using NLog.Config; using NLog.Targets; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace IOB_UT_NEXT {/// - /// Classe helper x LOG basata su NLog - /// + /// Classe helper x LOG basata su NLog public static class Logging { #region Public Constructors diff --git a/IOB-UT-NEXT/Objects.cs b/IOB-UT-NEXT/Objects.cs index dbe3a6f0..d10b609e 100644 --- a/IOB-UT-NEXT/Objects.cs +++ b/IOB-UT-NEXT/Objects.cs @@ -117,32 +117,6 @@ namespace IOB_UT_NEXT #endregion Public Methods } - /// - /// Classe di base per trasferimento informazioni di tipo RawTransfer FixMe Todo Fare !!! - /// elimnare usando SDK MAPO - /// - public class BaseRawTransf - { - #region Public Properties - - /// - /// Data-Ora riferimento (x ordinamento fifo) - /// - public DateTime dataRif { get; set; } = DateTime.Now; - - /// - /// Messaggio in modalità raw/stringa - /// - public object mesContent { get; set; } = null; - - /// - /// Tipo di messaggio trasmesso - /// - public rawTransfType mesType { get; set; } = rawTransfType.ND; - - #endregion Public Properties - } - /// /// Cache a tempo valori INT /// @@ -231,6 +205,7 @@ namespace IOB_UT_NEXT #endregion Public Properties } +#if false /// /// Rappresentazione dello stato corrente dell'IOB /// @@ -305,6 +280,8 @@ namespace IOB_UT_NEXT #endregion Public Properties + #region Public Methods + /// /// Override metodo di equality /// @@ -333,7 +310,7 @@ namespace IOB_UT_NEXT return false; if (queueRawTransfLen != item.queueRawTransfLen) return false; - if (queueUlLen!= item.queueUlLen) + if (queueUlLen != item.queueUlLen) return false; return true; @@ -343,7 +320,10 @@ namespace IOB_UT_NEXT { return base.GetHashCode(); } - } + + #endregion Public Methods + } +#endif /// /// Elenco oggetti del monitoraggio (DynData, Status) per WPS diff --git a/IOB-UT-NEXT/RedisMan.cs b/IOB-UT-NEXT/RedisMan.cs index 5bda2a2e..0de3697f 100644 --- a/IOB-UT-NEXT/RedisMan.cs +++ b/IOB-UT-NEXT/RedisMan.cs @@ -2,68 +2,12 @@ using StackExchange.Redis; using System; using System.Collections.Generic; -using System.Linq; using System.Text; namespace IOB_UT_NEXT { public class RedisIobCache { - #region Private Fields - - /// - /// Connessione lazy a redis... - /// - private Lazy lazyConnection = new Lazy(() => - { - string RedisConn = baseUtils.CRS("RedisConn"); - if (string.IsNullOrEmpty(RedisConn)) - { - RedisConn = "localhost,abortConnect=false,ssl=false"; - } - - return ConnectionMultiplexer.Connect(RedisConn); - }); - - /// - /// Connessione lazy a redis... - /// - private Lazy lazyConnectionAdmin = new Lazy(() => - { - string RedisConnAdmin = baseUtils.CRS("RedisConnAdmin"); - if (string.IsNullOrEmpty(RedisConnAdmin)) - { - RedisConnAdmin = "localhost,abortConnect=false,ssl=false,allowAdmin=true"; - } - - return ConnectionMultiplexer.Connect(RedisConnAdmin); - }); - - #endregion Private Fields - - #region Protected Fields - - /// - /// Cod IOB - /// - protected string currCodIob = "000"; - /// - /// Tipo IOB - /// - protected string currIobType = "ND"; - - /// - /// Hash redis x dati IOB - /// - protected string redIobKey = ""; - - /// - /// Hash redis x dati server - /// - protected string redServKey = ""; - - #endregion Protected Fields - #region Public Constructors /// @@ -97,7 +41,7 @@ namespace IOB_UT_NEXT IobWinStatus newIobStatus = new IobWinStatus() { CodIob = currCodIob, - IobType= currIobType, + IobType = currIobType, online = false }; // salvo in area REDIS @@ -137,15 +81,6 @@ namespace IOB_UT_NEXT #endregion Public Enums - #region Private Properties - - /// - /// Oggetto currentDb locale - /// - private IDatabase _currDB { get; set; } - - #endregion Private Properties - #region Public Properties /// @@ -216,7 +151,7 @@ namespace IOB_UT_NEXT answ = new IobWinStatus() { CodIob = currCodIob, - IobType=currIobType, + IobType = currIobType, online = false }; // salvo serializzando... @@ -233,7 +168,32 @@ namespace IOB_UT_NEXT set { string rawData = JsonConvert.SerializeObject(value); - setRSV(redIobKey, rawData); + saveAndSendMessage(redIobKey, redIobChannel, rawData); + //setRSV(redIobKey, rawData); + } + } + + /// + /// MEssage Dispatcher: oggetto comunicazione pub/sub via REDIS channels corrente + /// + public ISubscriber messageDisp + { + get + { + ISubscriber answ; + // se già valorizzato uso oggetto private... + if (_currSub != null) + { + answ = _currSub; + } + else + { + // init DB (sullo 0) + answ = connRedis.GetSubscriber(); + _currSub = answ; + } + // restituisco oggetto DB + return answ; } } @@ -298,39 +258,6 @@ namespace IOB_UT_NEXT #endregion Public Properties - #region Private Methods - - /// - /// Effettua comaprazione x CHIAVE in KVP ASC - /// - /// - /// - /// - private int CompareKey(KeyValuePair x, KeyValuePair y) - { - return x.Key.CompareTo(y.Key); - } - - /// - /// Effettua comaprazione x CHIAVE in KVP DESC - /// - /// - /// - /// - private int CompareKeyDesc(KeyValuePair x, KeyValuePair y) - { - return y.Key.CompareTo(x.Key); - } - - private void initHashKeys() - { - // init dati di base... - redServKey = redHash($"MP"); - redIobKey = redHash($"IOB:{currCodIob}"); - } - - #endregion Private Methods - #region Public Methods /// @@ -477,8 +404,7 @@ namespace IOB_UT_NEXT public int redCountKey(string keyPattern) { int answ = 0; - // cerco se ci sia valore in redis... - // se vuoto = ALL... + // cerco se ci sia valore in redis... se vuoto = ALL... keyPattern = string.IsNullOrEmpty(keyPattern) ? "**" : keyPattern; try { @@ -528,8 +454,7 @@ namespace IOB_UT_NEXT public bool redFlushKey(string keyPattern) { bool answ = false; - // cerco se ci sia valore in redis... - // se vuoto = ALL... + // cerco se ci sia valore in redis... se vuoto = ALL... keyPattern = string.IsNullOrEmpty(keyPattern) ? "**" : keyPattern; try { @@ -702,7 +627,8 @@ namespace IOB_UT_NEXT } /// - /// Nome della variabile HASH da utilizzare (dato CodModulo / Server / DB impiegato da funzionalita' DbConfig) + keyName richiesto... + /// Nome della variabile HASH da utilizzare (dato CodModulo / Server / DB impiegato da + /// funzionalita' DbConfig) + keyName richiesto... /// public string redHash(string keyName) { @@ -834,7 +760,9 @@ namespace IOB_UT_NEXT /// /// chiave /// valori - /// scadenza preimpostata hash (secondi) | defaoult = -1 (non scade) + /// + /// scadenza preimpostata hash (secondi) | defaoult = -1 (non scade) + /// /// public bool redSaveHash(string hashKey, KeyValuePair[] hashFields, double expireSeconds = -1) { @@ -891,7 +819,9 @@ namespace IOB_UT_NEXT /// /// chiave /// valori - /// scadenza preimpostata hash (secondi) | defaoult = -1 (non scade) + /// + /// scadenza preimpostata hash (secondi) | defaoult = -1 (non scade) + /// /// public bool redSaveHashDict(string hashKey, Dictionary hashFields, double expireSeconds = -1) { @@ -992,6 +922,43 @@ namespace IOB_UT_NEXT return answ; } + /// + /// Invia un messaggio tramite notify channel + salva in cache (se scaduto periodo veto) + /// + /// + /// + /// + /// + public bool saveAndSendMessage(string memKey, string notifyChannel, string message) + { + bool fatto = false; + // effettuo la scrittura nell'area di memoria indicata SE passato intervallo minimo + bool doSave = true; + if (LastKeySave.ContainsKey(memKey)) + { + if (DateTime.Now.Subtract(LastKeySave[memKey]).TotalSeconds < 1) + { + doSave = false; + } + } + else + { + LastKeySave.Add(memKey, DateTime.Now); + } + if (doSave) + { + cache.StringSet(memKey, message); + LastKeySave[memKey] = DateTime.Now; + Logging.Instance.Trace($"Redis Cache Key: {memKey}"); + } + + // invio notifica tramite il canale richiesto + messageDisp.Publish(notifyChannel, message); + fatto = true; + // restituisco! + return fatto; + } + /// /// Serializzazione di un oggetto generico /// @@ -1058,7 +1025,7 @@ namespace IOB_UT_NEXT } /// - /// Salva un set KVP (Key Value Pair) in RedisCache + /// Salva un set KVP (Key Value Pair) in RedisCache /// /// Set KVP chiave-valore da salvare /// @@ -1123,5 +1090,119 @@ namespace IOB_UT_NEXT } #endregion Public Methods + + #region Protected Fields + + /// + /// Cod IOB + /// + protected string currCodIob = "000"; + + /// + /// Tipo IOB + /// + protected string currIobType = "ND"; + + /// + /// Hash REDIS x dati IOB + /// + protected string redIobKey = ""; + + /// + /// Nome del channel REDIS x dati IOB + /// + protected string redIobChannel = "IobChannel"; + + /// + /// Hash REDIS x dati server + /// + protected string redServKey = ""; + + #endregion Protected Fields + + #region Private Fields + + /// + /// Dizionario delle ultime scritture in cache redis dei messaggi + /// + private Dictionary LastKeySave = new Dictionary(); + + /// + /// Connessione lazy a redis... + /// + private Lazy lazyConnection = new Lazy(() => + { + string RedisConn = baseUtils.CRS("RedisConn"); + if (string.IsNullOrEmpty(RedisConn)) + { + RedisConn = "localhost,abortConnect=false,ssl=false"; + } + + return ConnectionMultiplexer.Connect(RedisConn); + }); + + /// + /// Connessione lazy a redis... + /// + private Lazy lazyConnectionAdmin = new Lazy(() => + { + string RedisConnAdmin = baseUtils.CRS("RedisConnAdmin"); + if (string.IsNullOrEmpty(RedisConnAdmin)) + { + RedisConnAdmin = "localhost,abortConnect=false,ssl=false,allowAdmin=true"; + } + + return ConnectionMultiplexer.Connect(RedisConnAdmin); + }); + + #endregion Private Fields + + #region Private Properties + + /// + /// Oggetto currentDb REDIS locale + /// + private IDatabase _currDB { get; set; } + + /// + /// Oggetto subscriber x pubblicazione/sottoscrizione canali REDIS + /// + private ISubscriber _currSub { get; set; } + + #endregion Private Properties + + #region Private Methods + + /// + /// Effettua comaprazione x CHIAVE in KVP ASC + /// + /// + /// + /// + private int CompareKey(KeyValuePair x, KeyValuePair y) + { + return x.Key.CompareTo(y.Key); + } + + /// + /// Effettua comaprazione x CHIAVE in KVP DESC + /// + /// + /// + /// + private int CompareKeyDesc(KeyValuePair x, KeyValuePair y) + { + return y.Key.CompareTo(x.Key); + } + + private void initHashKeys() + { + // init dati di base... + redServKey = redHash($"MP"); + redIobKey = redHash($"IOB:{currCodIob}"); + redIobChannel = $"IobChannel_{currCodIob}"; + } + + #endregion Private Methods } } \ No newline at end of file diff --git a/IOB-UT-NEXT/TCMan.cs b/IOB-UT-NEXT/TCMan.cs index 0a8c1937..c513a8c0 100644 --- a/IOB-UT-NEXT/TCMan.cs +++ b/IOB-UT-NEXT/TCMan.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace IOB_UT_NEXT { @@ -27,50 +24,6 @@ namespace IOB_UT_NEXT #endregion Public Constructors - #region Protected Properties - - /// - /// Fattore lambda (innovazione) per calcolo EWMA valore TCiclo corrente - /// - protected double _lambda { get; set; } = 0.4; - - /// - /// Ultimo TCiclo osservato in SECONDI - /// - protected double _lastTC { get; set; } = 0; - - /// - /// ULTIMO Contapezzi IOB VALIDO - /// - protected int _lastValidPzCountIOB { get; set; } = 0; - - /// - /// ULTIMO Contapezzi PLC VALIDO - /// - protected int _lastValidPzCountPLC { get; set; } = 0; - - /// - /// Fattore massimo ammesso di delay x il TCiclo - /// - protected double _maxDelayFactor { get; set; } = 1.2; - - /// - /// Incremento amssimo pezzi per cui fare calcolo del tempociclo attuale - /// - protected double _maxIncrPz { get; set; } = 2; - - /// - /// Contapezzi IOB - /// - protected int _pzCountIOB { get; set; } = 0; - - /// - /// Contapezzi PLC - /// - protected int _pzCountPLC { get; set; } = 0; - - #endregion Protected Properties - #region Public Properties /// @@ -171,5 +124,49 @@ namespace IOB_UT_NEXT } #endregion Public Properties + + #region Protected Properties + + /// + /// Fattore lambda (innovazione) per calcolo EWMA valore TCiclo corrente + /// + protected double _lambda { get; set; } = 0.4; + + /// + /// Ultimo TCiclo osservato in SECONDI + /// + protected double _lastTC { get; set; } = 0; + + /// + /// ULTIMO Contapezzi IOB VALIDO + /// + protected int _lastValidPzCountIOB { get; set; } = 0; + + /// + /// ULTIMO Contapezzi PLC VALIDO + /// + protected int _lastValidPzCountPLC { get; set; } = 0; + + /// + /// Fattore massimo ammesso di delay x il TCiclo + /// + protected double _maxDelayFactor { get; set; } = 1.2; + + /// + /// Incremento amssimo pezzi per cui fare calcolo del tempociclo attuale + /// + protected double _maxIncrPz { get; set; } = 2; + + /// + /// Contapezzi IOB + /// + protected int _pzCountIOB { get; set; } = 0; + + /// + /// Contapezzi PLC + /// + protected int _pzCountPLC { get; set; } = 0; + + #endregion Protected Properties } } \ No newline at end of file diff --git a/IOB-UT-NEXT/ToMapo.cs b/IOB-UT-NEXT/ToMapo.cs index f91154da..56a1011b 100644 --- a/IOB-UT-NEXT/ToMapo.cs +++ b/IOB-UT-NEXT/ToMapo.cs @@ -1,11 +1,7 @@ using MapoSDK; using Newtonsoft.Json; using Newtonsoft.Json.Converters; -using System; -using System.Collections; using System.Collections.Generic; -using System.Linq; -using System.Text; namespace IOB_UT_NEXT { @@ -14,7 +10,23 @@ namespace IOB_UT_NEXT /// public class BaseAlarmConf { - #region Public Fields + #region Public Properties + + /// + /// Elenco dei contatori blink x gestione caso fronte salita/discesa segnale che blinka + /// + public int[] alarmsBlinkCounter { get; set; } + + /// + /// BitMask 16bit (1 = valido, 0 = filtro) degli allarmi silenziati/disabilitati (se + /// iniziano per ##) come valore da sottrarre x check + /// + public uint[] alarmsMask { get; set; } + + /// + /// Array dei valori allarme correnti + /// + public uint[] alarmsState { get; set; } /// /// valore di partenza x un segnale di blink in caso di fine variazione (fronte discesa) @@ -26,25 +38,6 @@ namespace IOB_UT_NEXT /// public int blinkUpVal { get; set; } = 3; - #endregion Public Fields - - #region Public Properties - - /// - /// Elenco dei contatori blink x gestione caso fronte salita/discesa segnale che blinka - /// - public int[] alarmsBlinkCounter { get; set; } - - /// - /// BitMask 16bit (1 = valido, 0 = filtro) degli allarmi silenziati/disabilitati (se iniziano per ##) come valore da sottrarre x check - /// - public uint[] alarmsMask { get; set; } - - /// - /// Array dei valori allarme correnti - /// - public uint[] alarmsState { get; set; } - /// /// Descrizione area allarmi /// @@ -177,7 +170,8 @@ namespace IOB_UT_NEXT alarmsState = new uint[size / 2]; alarmsMask = new uint[size / 2]; - // una volta inizializzata la classe di base sistemo vettori allarmi disabilitati ed il contatore blink dei fronti di discesa + // una volta inizializzata la classe di base sistemo vettori allarmi disabilitati ed il + // contatore blink dei fronti di discesa alarmsBlinkCounter = new int[messages.Count]; int idx = 0; int bank = 0; @@ -217,7 +211,8 @@ namespace IOB_UT_NEXT } /// - /// Classe gestione configurazione parametri di base x configuraizone estesa (es MTConnect, OPC-UA, ...) + /// Classe gestione configurazione parametri di base x configuraizone estesa (es MTConnect, + /// OPC-UA, ...) /// public class BaseParamConf { @@ -229,14 +224,13 @@ namespace IOB_UT_NEXT public List condWork { get; set; } = new List(); /// - /// Indica se l'emergenza armata va riportata verso Mapo come bit a TRUE - /// True --> armata = 1 / triggered = 0 - /// False --> triggered = 1 / armata = 0 + /// Indica se l'emergenza armata va riportata verso Mapo come bit a TRUE True --> armata + /// = 1 / triggered = 0 False --> triggered = 1 / armata = 0 /// public bool emergencyArmedTrue { get; set; } = true; /// - /// Elenco items FILTRATI da invio come dynData --> FluxLog (events o samples) + /// Elenco items FILTRATI da invio come dynData --> FluxLog (events o samples) /// public List fluxLogVeto { get; set; } = new List(); @@ -309,7 +303,8 @@ namespace IOB_UT_NEXT } /// - /// Classe per rappresentare una lista di oggetti chiave/valore target x controlo condizioni multiple + indicazione modalità di controllo (AND/OR/...) + /// Classe per rappresentare una lista di oggetti chiave/valore target x controlo condizioni + /// multiple + indicazione modalità di controllo (AND/OR/...) /// public class diCheckCondSetup { @@ -326,13 +321,75 @@ namespace IOB_UT_NEXT public boolCheckMode checkMode { get; set; } = boolCheckMode.AND; /// - /// indica se il check vada NEGATO (esempio se cerco la condizione opposta, esempio num allarmi 0 --> se true NEGO la condizione HO ALLARMI) + /// indica se il check vada NEGATO (esempio se cerco la condizione opposta, esempio num + /// allarmi 0 --> se true NEGO la condizione HO ALLARMI) /// public bool negateValue { get; set; } = false; #endregion Public Properties } + /// + /// Classe x definizione delle azioni in fase di setup macchina + /// + public class MachineSetupAction + { + #region Public Properties + + /// + /// Indica se vada disabilitato il contapezzi quando la condizione NotEqual sia soddisfatta + /// + public bool DisablePzCountNotEqual { get; set; } = false; + + /// + /// Parametro target dell'azione + /// + public string TargetParam { get; set; } = ""; + + /// + /// parametro da impostare SE il check da esito EQUAL + /// + public int TargetValEqual { get; set; } = 0; + + /// + /// parametro da impostare SE il check da esito NOT EQUAL + /// + public int TargetValNotEqual { get; set; } = 1; + + #endregion Public Properties + } + + /// + /// Definizione parametri di setup incrociato... + /// + public class MachineSetupConf + { + #region Public Properties + + /// + /// Dizionario dei parametri di corrispondenza tra variabili MES e variabili Macchina MES = + /// scritte dal MES Macchina = scritte da macchina + /// + public Dictionary checkParList { get; set; } = new Dictionary(); + + /// + /// Abilitazione gestione Setup Avanzato (= scrittura) + /// + public bool EnableAdvSetup { get; set; } = false; + + /// + /// Modalità gestione setup + /// + public MachineSetupMode SetupMode { get; set; } = MachineSetupMode.ND; + + /// Dizionario dei parametri da scrivere quando si rilevano differenze tra i + /// parametri MES/Macchina string (key) --> memoria da scrivere tuple --> valori da scrivere quando uguali o diversi + public List writeParAction { get; set; } = new List(); + + #endregion Public Properties + } + /// /// COnfigurazione blocchi x accesso memoria ottimizzato /// @@ -360,84 +417,6 @@ namespace IOB_UT_NEXT #endregion Public Properties } - /// - /// Definizione parametri watchdog - /// - public class WatchDogConf - { - /// - /// Abilitazione WatchDog - /// - public bool IsEnabled { get; set; } = false; - /// - /// Conf memoria x lettura WatchDog (ToMes), se !="" è gestito - /// - public string MemConfRead { get; set; } = ""; - /// - /// Conf memoria x scrittura WatchDog (FromMes), se !="" è gestito - /// - public string MemConfWrite { get; set; } = ""; - /// - /// Valore max contatore prima di resettare - /// - public int MaxVal { get; set; } = 9999; - } - - /// - /// Definizione parametri di setup incrociato... - /// - public class MachineSetupConf - { - /// - /// Modalità gestione setup - /// - public MachineSetupMode SetupMode { get; set; } = MachineSetupMode.ND; - - /// - /// Abilitazione gestione Setup Avanzato (= scrittura) - /// - public bool EnableAdvSetup { get; set; } = false; - - /// - /// Dizionario dei parametri di corrispondenza tra variabili MES e variabili Macchina - /// MES = scritte dal MES - /// Macchina = scritte da macchina - /// - public Dictionary checkParList { get; set; } = new Dictionary(); - - /// - /// Dizionario dei parametri da scrivere quando si rilevano differenze tra i parametri MES/Macchina - /// string (key) --> memoria da scrivere - /// tuple --> valori da scrivere quando uguali o diversi - /// - public List writeParAction { get; set; } = new List(); - } - - /// - /// Classe x definizione delle azioni in fase di setup macchina - /// - public class MachineSetupAction - { - /// - /// Parametro target dell'azione - /// - public string TargetParam { get; set; } = ""; - - /// - /// parametro da impostare SE il check da esito EQUAL - /// - public int TargetValEqual { get; set; } = 0; - /// - /// parametro da impostare SE il check da esito NOT EQUAL - /// - public int TargetValNotEqual { get; set; } = 1; - - /// - /// Indica se vada disabilitato il contapezzi quando la condizione NotEqual sia soddisfatta - /// - public bool DisablePzCountNotEqual { get; set; } = false; - } - /// /// Classe gestione configurazione parametri specifici OPC-UA da BaseParamConf /// @@ -470,12 +449,6 @@ namespace IOB_UT_NEXT /// public diCheckCondSetup condError { get; set; } = new diCheckCondSetup(); - - /// - /// Struttura dati x check condizione Errore - /// - public diCheckCondSetup condWorkOpc { get; set; } = new diCheckCondSetup(); - /// /// Struttura dati x check condizione Emergenza /// @@ -496,6 +469,11 @@ namespace IOB_UT_NEXT /// public diCheckCondSetup condReady { get; set; } = new diCheckCondSetup(); + /// + /// Struttura dati x check condizione Setup + /// + public diCheckCondSetup condSetup { get; set; } = new diCheckCondSetup(); + /// /// Struttura dati x check condizione WarmUp - CoolDown /// @@ -505,16 +483,19 @@ namespace IOB_UT_NEXT /// Struttura dati x check condizione Warning /// public diCheckCondSetup condWarning { get; set; } = new diCheckCondSetup(); + /// - /// Struttura dati x check condizione Setup + /// Struttura dati x check condizione Errore /// - public diCheckCondSetup condSetup { get; set; } = new diCheckCondSetup(); + public diCheckCondSetup condWorkOpc { get; set; } = new diCheckCondSetup(); /// /// Elenco dei NodeId da ignorare intesi come interi rami (se vuoto NON filtro) /// public List filterItemsNodeId { get; set; } = new List(); + public UserIdent Identity { get; set; } = new UserIdent(); + /// /// Aree di memoria lettura /// @@ -525,34 +506,66 @@ namespace IOB_UT_NEXT /// public Dictionary mMapWrite { get; set; } = new Dictionary(); - /// - /// Elenco dei SOLI item sottoscritti (se vuoto TUTTI) - /// - public List subscribedItems { get; set; } = new List(); - /// /// Elenco item RAW sottoscritti e relative configurazioni di decodifica da byte[] /// public Dictionary rawSubscribedItemsConf { get; set; } = new Dictionary(); - /// - /// Conf Gestione WatchDog - /// - public WatchDogConf WatchDog { get; set; } = new WatchDogConf(); - /// /// Conf gestione setup macchina /// public MachineSetupConf SetupConf { get; set; } = new MachineSetupConf(); - public UserIdent Identity { get; set; } = new UserIdent(); + /// + /// Elenco dei SOLI item sottoscritti (se vuoto TUTTI) + /// + public List subscribedItems { get; set; } = new List(); + + /// + /// Conf Gestione WatchDog + /// + public WatchDogConf WatchDog { get; set; } = new WatchDogConf(); #endregion Public Properties } public class UserIdent { - public string UserName { get; set; } = ""; + #region Public Properties + public string Passwd { get; set; } = ""; + public string UserName { get; set; } = ""; + + #endregion Public Properties + } + + /// + /// Definizione parametri watchdog + /// + public class WatchDogConf + { + #region Public Properties + + /// + /// Abilitazione WatchDog + /// + public bool IsEnabled { get; set; } = false; + + /// + /// Valore max contatore prima di resettare + /// + public int MaxVal { get; set; } = 9999; + + /// + /// Conf memoria x lettura WatchDog (ToMes), se !="" è gestito + /// + public string MemConfRead { get; set; } = ""; + + /// + /// Conf memoria x scrittura WatchDog (FromMes), se !="" è gestito + /// + public string MemConfWrite { get; set; } = ""; + + #endregion Public Properties } } \ No newline at end of file diff --git a/IOB-UT-NEXT/baseUtils.cs b/IOB-UT-NEXT/baseUtils.cs index 7f074349..a038471d 100644 --- a/IOB-UT-NEXT/baseUtils.cs +++ b/IOB-UT-NEXT/baseUtils.cs @@ -1,4 +1,3 @@ -using MapoSDK; using NLog; using System; using System.Collections; @@ -49,35 +48,6 @@ namespace IOB_UT_NEXT #endregion Public Fields -#if false - { - get - { - return redisMan.servStatus.dtVetoPing; - } - set - { - var currData = redisMan.servStatus; - currData.dtVetoPing = value; - redisMan.servStatus = currData; - } - } -#endif - - #region Protected Properties - - /// - /// Oggetto WebClient BASE da riutilizzare - /// - protected static WebClientWT client { get; set; } - - /// - /// Oggetto WebClient con PAYLOAD da riutilizzare - /// - protected static WebClientWT clientPayload { get; set; } - - #endregion Protected Properties - #region Public Properties /// @@ -89,10 +59,10 @@ namespace IOB_UT_NEXT { // parto dal dato std di veto per pauseSendMSec int answ = CRI("pauseSendMSec"); - // aggiungo NOISE... +/- 33% + // aggiungo NOISE... +/- 50% Random rnd = new Random(); - int noise = rnd.Next(1, answ / 3); - answ += noise - (answ / 6); + int noise = rnd.Next(1, answ / 2); + answ += noise - (answ / 4); return answ; } } @@ -117,6 +87,7 @@ namespace IOB_UT_NEXT { } return answ; } + /// /// formatta un numero in forma binaria 0/1 /// @@ -409,7 +380,9 @@ namespace IOB_UT_NEXT /// number will be formatted as a 32-character binary number in two's compliment. /// /// self-explanatory - /// if binary number contains fewer characters leading zeros are added + /// + /// if binary number contains fewer characters leading zeros are added + /// /// string as described above public static string IntToBinStr(int theNumber, int minimumDigits) { @@ -420,7 +393,9 @@ namespace IOB_UT_NEXT /// verifica se un dato bit sia alzato (come flag di strobe) /// /// valore da testare - /// valore cercato, può essere un singolo valore o un insieme in modalità AND + /// + /// valore cercato, può essere un singolo valore o un insieme in modalità AND + /// /// public static bool IsSetAll(StFlag32 value, StFlag32 flag) { @@ -431,7 +406,9 @@ namespace IOB_UT_NEXT /// verifica se un dato bit sia alzato (come flag di strobe) /// /// valore da testare - /// valore cercato, può essere un singolo valore o un insieme in modalità OR + /// + /// valore cercato, può essere un singolo valore o un insieme in modalità OR + /// /// public static bool IsSetAny(StFlag32 value, StFlag32 flag) { @@ -586,7 +563,8 @@ namespace IOB_UT_NEXT } /// - /// provvede a verificare la dim della cartella dei log e cancella i + vecchi fino a restare a dim inferiori a _logMaxMb + /// provvede a verificare la dim della cartella dei log e cancella i + vecchi fino a restare + /// a dim inferiori a _logMaxMb /// public static void shrinkDir(string dirPath) { @@ -616,7 +594,8 @@ namespace IOB_UT_NEXT // inizio con eliminare file + vecchi della data indicata... int maxLogDays = CRI("maxLogDays"); fileMover.obj.deleteOlderThan(maxLogDays); - // ora controllo SE sia superata la dim max della directory --> in tal caso cancello dal + vecchio... + // ora controllo SE sia superata la dim max della directory --> in tal caso cancello dal + // + vecchio... dirSizeMb = fileMover.obj.totalMb(); int maxLogDirSize = CRI("maxLogDirSize"); int maxTry = 100; @@ -723,6 +702,20 @@ namespace IOB_UT_NEXT } #endregion Public Methods + + #region Protected Properties + + /// + /// Oggetto WebClient BASE da riutilizzare + /// + protected static WebClientWT client { get; set; } + + /// + /// Oggetto WebClient con PAYLOAD da riutilizzare + /// + protected static WebClientWT clientPayload { get; set; } + + #endregion Protected Properties } /// diff --git a/IOB-UT-NEXT/packages.config b/IOB-UT-NEXT/packages.config index 70e045e6..26591de3 100644 --- a/IOB-UT-NEXT/packages.config +++ b/IOB-UT-NEXT/packages.config @@ -1,6 +1,6 @@  - + diff --git a/IOB-UT-NEXT/val.cs b/IOB-UT-NEXT/val.cs deleted file mode 100644 index 94029a5c..00000000 --- a/IOB-UT-NEXT/val.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace IOB_UT_NEXT -{ - internal class val - { - } -} \ No newline at end of file diff --git a/IOB-WIN-NEXT/AdapterForm.cs b/IOB-WIN-NEXT/AdapterForm.cs index 728abef3..2c6b6890 100644 --- a/IOB-WIN-NEXT/AdapterForm.cs +++ b/IOB-WIN-NEXT/AdapterForm.cs @@ -122,7 +122,7 @@ namespace IOB_WIN_NEXT // inizializzo orologi firstStart = DateTime.Now; - lastStartTry = DateTime.Now; + lastStartTry = DateTime.Now.AddHours(-1); initDatamonitor(); @@ -274,7 +274,7 @@ namespace IOB_WIN_NEXT protected int maxFlQueue { get; set; } protected int maxMsQueue { get; set; } - + protected int maxRwTrQueue { get; set; } protected int maxUlQueue { get; set; } @@ -286,7 +286,7 @@ namespace IOB_WIN_NEXT protected int qFlLen { get; set; } protected int qMsLen { get; set; } - + protected int qRTrLen { get; set; } protected int qUlLen { get; set; } @@ -1168,7 +1168,7 @@ namespace IOB_WIN_NEXT cpuType = fIni.ReadString("CNC", "CPUTYPE", ""), rack = (short)fIni.ReadInteger("CNC", "RACK", 0), slot = (short)fIni.ReadInteger("CNC", "SLOT", 0), - serverData = new serverMapo(fIni.ReadString("SERVER", "MPIP", "::1"), fIni.ReadString("SERVER", "MPURL", "/MP/IO"), fIni.ReadString("SERVER", "CMDBASE", "/IOB/input/"), fIni.ReadString("SERVER", "CMDFLOG", "/IOB/flog/"), fIni.ReadString("SERVER", "CMDULOG", "/IOB/ulog/"), fIni.ReadString("SERVER", "CMDALIVE", "/"), fIni.ReadString("SERVER", "CMDENABLED", "/"), fIni.ReadString("SERVER", "CMDREBO", "/"), fIni.ReadString("SERVER", "CMD_ODL_STARTED", "/IOB/getCurrOdlStart/"), fIni.ReadString("SERVER", "CLI_INST", "SW_CLI"), fIni.ReadString("SERVER", "CMD_FORCLE_SPLIT_ODL", "/IOB/forceSplitOdlFull/")), + serverData = new serverMapo(fIni.ReadString("SERVER", "MPIP", "::1"), fIni.ReadString("SERVER", "MPURL", "/MP/IO"), fIni.ReadString("SERVER", "CMDBASE", "/IOB/input/"), fIni.ReadString("SERVER", "CMDFLOG", "/IOB/flog/"), fIni.ReadString("SERVER", "CMDULOG", "/IOB/ulog/"), fIni.ReadString("SERVER", "CMDALIVE", "/"), fIni.ReadString("SERVER", "CMDENABLED", "/"), fIni.ReadString("SERVER", "CMDREBO", "/"), fIni.ReadString("SERVER", "CMD_ODL_STARTED", "/IOB/getCurrOdlStart/"), fIni.ReadString("SERVER", "CLI_INST", "SW_CLI"), fIni.ReadString("SERVER", "CMD_FORCLE_SPLIT_ODL", "/IOB/forceSplitOdlFull/"), fIni.ReadString("SERVER", "CMDRAWTRANSF", "/IOB/rawTransfJson/")), MAX_COUNTER_BLINK = Convert.ToInt32(fIni.ReadString("BLINK", "MAX_COUNTER_BLINK", "1")), BLINK_FILT = Convert.ToInt32(fIni.ReadString("BLINK", "BLINK_FILT", "0")), TCMaxDelayFactor = Convert.ToDouble(fIni.ReadString("OPTPAR", "TC_MAX_TC_FACTOR", "1.2").Replace(".", ",")), @@ -1243,6 +1243,7 @@ namespace IOB_WIN_NEXT iobObj = new IobIcoelDb(this, IOBConf); start.Enabled = true; break; + case tipoAdapter.IcoelSoap: iobObj = new IobIcoelSoap(this, IOBConf); start.Enabled = true; @@ -1258,6 +1259,11 @@ namespace IOB_WIN_NEXT start.Enabled = true; break; + case tipoAdapter.MODBUS_TCP_CENTERFRIGO: + iobObj = new IobModbusTCPCenterfrigo(this, IOBConf); + start.Enabled = true; + break; + case tipoAdapter.MODBUS_TCP_HAM: iobObj = new IobModbusTCPHam(this, IOBConf); start.Enabled = true; @@ -1377,6 +1383,11 @@ namespace IOB_WIN_NEXT start.Enabled = true; break; + case tipoAdapter.SIEMENS_NWSE: + iobObj = new IobSiemensNWSE(this, IOBConf); + start.Enabled = true; + break; + case tipoAdapter.SIEMENS_PRESSOIL_CEI: iobObj = new IobSiemensPressoilCei(this, IOBConf); start.Enabled = true; @@ -1492,6 +1503,10 @@ namespace IOB_WIN_NEXT // aggiorno labels counters... counterIob = $"pz IOB {iobObj.contapezziIOB}"; counterMac = $"pz PLC {iobObj.contapezziPLC}"; + Dictionary setPar = new Dictionary(); + setPar.Add("IP", iobObj.cIobConf.cncIpAddr); + setPar.Add("PORT", iobObj.cIobConf.cncPort); + string note = $"DT ultimo avvio: {iobObj.dtAvvioAdp}"; // verifico IOB status IobWinStatus currIobStatus = new IobWinStatus() { @@ -1507,7 +1522,10 @@ namespace IOB_WIN_NEXT counterMAC = iobObj.contapezziPLC, lastUpdate = lastIobStatus.lastUpdate, online = utils.IOB_Online, - lastDataIn = iobObj.lastReadPLC + lastDataIn = iobObj.lastReadPLC, + lastDataOut = iobObj.lastIobOnline, + setupParams = setPar, + freeNotes = note }; // se diverso SALVO! if (!lastIobStatus.Equals(currIobStatus)) diff --git a/IOB-WIN-NEXT/App.config b/IOB-WIN-NEXT/App.config index 13ffb3ff..679e165b 100644 --- a/IOB-WIN-NEXT/App.config +++ b/IOB-WIN-NEXT/App.config @@ -1,164 +1,174 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/3025.ini b/IOB-WIN-NEXT/DATA/CONF/3025.ini index 008d6846..59840aed 100644 --- a/IOB-WIN-NEXT/DATA/CONF/3025.ini +++ b/IOB-WIN-NEXT/DATA/CONF/3025.ini @@ -26,7 +26,7 @@ CMDREBO=/sendReboot.aspx?idxMacchina= ; Red: Y31.4 | Yellow: Y31.5 | Green Y31.6 | riscaldamento Y7.4 ??? ;BIT0=CONN BIT1=Y31.6 -BIT2=PZCOUNT.PAR.6711 +BIT2=STD.MACRO.10100 BIT3=Y31.4 BIT4=Y31.5 BIT5=Y7.4 @@ -59,7 +59,10 @@ BLINK_FILT=0 [OPTPAR] ;PZCOUNT_MODE=STD|BIT -PZCOUNT_MODE=STD.PAR.6711 +;PZCOUNT_MODE=STD.PAR.6711 +;PZREQ_MODE=STD.PAR.6713 +PZCOUNT_MODE=STD.MACRO.10100 +PZREQ_MODE=STD.MACRO.10000 PZGTOT_MODE=STD.PAR.6712 PZREQ_MODE=STD.PAR.6713 ;PZCAD_MODE=STD.D.6408.DW diff --git a/IOB-WIN-NEXT/DATA/CONF/FINASSI_HELPI_01.json b/IOB-WIN-NEXT/DATA/CONF/FINASSI_HELPI_01.json index aa1a3a1c..c0f4eb4f 100644 --- a/IOB-WIN-NEXT/DATA/CONF/FINASSI_HELPI_01.json +++ b/IOB-WIN-NEXT/DATA/CONF/FINASSI_HELPI_01.json @@ -151,7 +151,7 @@ }, "PPM": { "name": "PPM", - "description": "Velocità espressa come Pacchi Per Minuto", + "description": "Velocit� espressa come Pacchi Per Minuto", "memAddr": "41106", "tipoMem": "Real", "index": 1106, diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_001.ini b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_001.ini new file mode 100644 index 00000000..cdf3faf6 --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_001.ini @@ -0,0 +1,76 @@ +;Configurazione IOB-WIN +[IOB] +;Impianto Cedax di Turi (test) - Giacovelli +CNCTYPE=MODBUS_TCP_CEDAX +PING_MS_TIMEOUT=1000 + +[MACHINE] +VENDOR=CEDAX +MODEL=CEDAX Hydrocooler + +[CNC] +IP=192.168.2.60 +PORT=502 + +[SERVER] +MPIP=http://192.168.1.14 +MPURL=/MP/IO +CMDBASE=/IOB/input/ +CMDFLOG=/IOB/flog/ +CMDALIVE=/IOB +CMDENABLED=/IOB/enabled/ +CMDADV1=?valore= +CMDREBO=/sendReboot.aspx?idxMacchina= + +[MEMORY] +ADDR_READ=41001 +ADDR_WRITE=41021 +SIZE_READ=20 +SIZE_WRITE=0 +HR_BASE_ADDR=40000 + + +[BLINK] +;MAX_COUNTER_BLINK = 30 +MAX_COUNTER_BLINK = 15 +;bit0 = 0 +;bit1 = 0 +;bit2 = 1 +;bit3 = 1 +;bit4 = 1 +;bit5 = 0 +;bit6 = 0 +;bit7 = 0 +BLINK_FILT=0 +;BLINK_FILT=28 + +[OPTPAR] +;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice +PZCOUNT_MODE=STD.DB85.DBRE16 +DISABLE_PZCOUNT=TRUE +ENABLE_SEND_PZC_BLOCK=TRUE +MIN_SEND_PZC_BLOCK=0 +MAX_SEND_PZC_BLOCK=100 +; GEST DATI DYN +ENABLE_DYN_DATA=TRUE +FORCE_DYN_DATA=TRUE +; gestione delta minimo accettabile tra min/MAX +DELTA_VAL=0.1 + +; clock base (da 10ms) +timerIntMs=10 + +; conf parametri memoria READ/WRITE +PARAM_CONF=GIACO_CEDAX_001.json + +NO_PING=FALSE +; conf blocchi memoria x READ +MEM_BLOCK=GIACO_CEDAX_001_MBlock.json +; conf aree allarme +ALARM_CONF=GIACO_CEDAX_001_alarm.json + +; rimozione check limiti min/max dynData +disDynDataRangeCheck=true + +[BRANCH] +NAME=master \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_001.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_001.json new file mode 100644 index 00000000..edf4343e --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_001.json @@ -0,0 +1,258 @@ +{ + "mMapWrite": { + "Dose_Staz_1": { + "name": "Dose_Staz_1", + "description": "Dose Stazione 1", + "memAddr": "40024", + "tipoMem": "Int", + "index": 24, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + }, + "Dose_Staz_2": { + "name": "Dose_Staz_2", + "description": "Dose Stazione 2", + "memAddr": "40025", + "tipoMem": "Int", + "index": 25, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + }, + "Dose_Staz_3": { + "name": "Dose_Staz_3", + "description": "Dose Stazione 3", + "memAddr": "40026", + "tipoMem": "Int", + "index": 26, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + }, + "Dose_Staz_4": { + "name": "Dose_Staz_4", + "description": "Dose Stazione 4", + "memAddr": "40027", + "tipoMem": "Int", + "index": 27, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + } + }, + "mMapRead": { + "Stag_H2O": { + "name": "Stag_H2O", + "description": "Totale H2O Stagione", + "memAddr": "41001", + "tipoMem": "HLPInt", + "index": 1001, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 1, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "Stag_Prod1": { + "name": "Stag_Prod1", + "description": "Totale Prodotto 1 Stagione", + "memAddr": "41003", + "tipoMem": "HLPInt", + "index": 1003, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 1, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "Stag_Prod2": { + "name": "Stag_Prod2", + "description": "Totale Prodotto 2 Stagione", + "memAddr": "41005", + "tipoMem": "HLPInt", + "index": 1005, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 1, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "Stag_Prod3": { + "name": "Stag_Prod3", + "description": "Totale Prodotto 3 Stagione", + "memAddr": "41007", + "tipoMem": "HLPInt", + "index": 1007, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "Stag_Prod4": { + "name": "Stag_Prod4", + "description": "Totale Prodotto 4 Stagione", + "memAddr": "41009", + "tipoMem": "HLPInt", + "index": 1009, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "Giorno_H2O": { + "name": "Giorno_H2O", + "description": "Totale H2O Giorno", + "memAddr": "41011", + "tipoMem": "HLPInt", + "index": 1011, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 1, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "Giorno_Prod1": { + "name": "Giorno_Prod1", + "description": "Totale Prodotto 1 Giorno", + "memAddr": "41013", + "tipoMem": "HLPInt", + "index": 1013, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 1, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "Giorno_Prod2": { + "name": "Giorno_Prod2", + "description": "Totale Prodotto 2 Giorno", + "memAddr": "41015", + "tipoMem": "HLPInt", + "index": 1015, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 1, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "Giorno_Prod3": { + "name": "Giorno_Prod3", + "description": "Totale Prodotto 3 Giorno", + "memAddr": "41017", + "tipoMem": "HLPInt", + "index": 1017, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "Giorno_Prod4": { + "name": "Giorno_Prod4", + "description": "Totale Prodotto 4 Giorno", + "memAddr": "41019", + "tipoMem": "HLPInt", + "index": 1019, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "Dose_Staz_1": { + "name": "Dose_Staz_1", + "description": "Dose Stazione 1", + "memAddr": "40024", + "tipoMem": "Int", + "index": 24, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + }, + "Dose_Staz_2": { + "name": "Dose_Staz_2", + "description": "Dose Stazione 2", + "memAddr": "40025", + "tipoMem": "Int", + "index": 25, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + }, + "Dose_Staz_3": { + "name": "Dose_Staz_3", + "description": "Dose Stazione 3", + "memAddr": "40026", + "tipoMem": "Int", + "index": 26, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + }, + "Dose_Staz_4": { + "name": "Dose_Staz_4", + "description": "Dose Stazione 4", + "memAddr": "40027", + "tipoMem": "Int", + "index": 27, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + } + } +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_001_MBlock.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_001_MBlock.json new file mode 100644 index 00000000..6ce9d4fd --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_001_MBlock.json @@ -0,0 +1,6 @@ +{ + "ReadBlocks": { + "40016": 16, + "40999": 32 + } +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_01_alarm.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_001_alarm.json similarity index 100% rename from IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_01_alarm.json rename to IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_001_alarm.json diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_01.ini b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_002.ini similarity index 78% rename from IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_01.ini rename to IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_002.ini index 0af3ab79..def79ad2 100644 --- a/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_01.ini +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_002.ini @@ -6,23 +6,21 @@ PING_MS_TIMEOUT=1000 [MACHINE] VENDOR=CEDAX -MODEL=CEDAX +MODEL=CEDAX Scarico [CNC] -IP=10.74.82.65 +IP=192.168.2.61 PORT=502 [SERVER] -MPIP=https://iis01.egalware.com -;MPIP=https://gwms.egalware.com +MPIP=http://192.168.1.14 MPURL=/MP/IO CMDBASE=/IOB/input/ CMDFLOG=/IOB/flog/ CMDALIVE=/IOB CMDENABLED=/IOB/enabled/ CMDADV1=?valore= -CMDREBO=/IOB/sendReboot?idxMacchina= -;CMDREBO=/sendReboot.aspx?idxMacchina= +CMDREBO=/sendReboot.aspx?idxMacchina= [MEMORY] ADDR_READ=41001 @@ -63,13 +61,16 @@ DELTA_VAL=0.1 timerIntMs=10 ; conf parametri memoria READ/WRITE -PARAM_CONF=GIACO_CEDAX_01.json +PARAM_CONF=GIACO_CEDAX_002.json NO_PING=TRUE ; conf blocchi memoria x READ -MEM_BLOCK=GIACO_CEDAX_01_MBlock.json +MEM_BLOCK=GIACO_CEDAX_002_MBlock.json ; conf aree allarme -ALARM_CONF=GIACO_CEDAX_01_alarm.json +ALARM_CONF=GIACO_CEDAX_002_alarm.json + +; rimozione check limiti min/max dynData +disDynDataRangeCheck=true [BRANCH] NAME=master \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_002.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_002.json new file mode 100644 index 00000000..bef5f18f --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_002.json @@ -0,0 +1,286 @@ +{ + "mMapWrite": { + "Dose_Staz_1": { + "name": "Dose_Staz_1", + "description": "Dose Stazione 1", + "memAddr": "40024", + "tipoMem": "Int", + "index": 24, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + }, + "Dose_Staz_2": { + "name": "Dose_Staz_2", + "description": "Dose Stazione 2", + "memAddr": "40025", + "tipoMem": "Int", + "index": 25, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + }, + "Dose_Staz_3": { + "name": "Dose_Staz_3", + "description": "Dose Stazione 3", + "memAddr": "40026", + "tipoMem": "Int", + "index": 26, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + }, + "Dose_Staz_4": { + "name": "Dose_Staz_4", + "description": "Dose Stazione 4", + "memAddr": "40027", + "tipoMem": "Int", + "index": 27, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + } + }, + "mMapRead": { + "A_Stag_H2O": { + "name": "A_Stag_H2O", + "description": "Linea A Totale H2O Stagione", + "memAddr": "41001", + "tipoMem": "HLPInt", + "index": 1001, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 1, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "A_Stag_Prod1": { + "name": "A_Stag_Prod1", + "description": "Linea A Totale Prodotto 1 Stagione", + "memAddr": "40003", + "tipoMem": "HLPInt", + "index": 1003, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "A_Stag_Prod2": { + "name": "A_Stag_Prod2", + "description": "Linea A Totale Prodotto 2 Stagione", + "memAddr": "40005", + "tipoMem": "HLPInt", + "index": 1005, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "A_Giorno_H2O": { + "name": "A_Giorno_H2O", + "description": "Linea A Totale H2O Giorno", + "memAddr": "41007", + "tipoMem": "HLPInt", + "index": 1007, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 1, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "A_Giorno_Prod1": { + "name": "A_Giorno_Prod1", + "description": "Linea A Totale Prodotto 1 Giorno", + "memAddr": "40009", + "tipoMem": "HLPInt", + "index": 1009, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "A_Giorno_Prod2": { + "name": "A_Giorno_Prod2", + "description": "Linea A Totale Prodotto 2 Giorno", + "memAddr": "40011", + "tipoMem": "HLPInt", + "index": 1011, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "B_Stag_H2O": { + "name": "B_Stag_H2O", + "description": "Linea B Totale H2O Stagione", + "memAddr": "41013", + "tipoMem": "HLPInt", + "index": 1013, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 1, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "B_Stag_Prod1": { + "name": "B_Stag_Prod1", + "description": "Linea B Totale Prodotto 1 Stagione", + "memAddr": "40015", + "tipoMem": "HLPInt", + "index": 1015, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "B_Stag_Prod2": { + "name": "B_Stag_Prod2", + "description": "Linea B Totale Prodotto 2 Stagione", + "memAddr": "40017", + "tipoMem": "HLPInt", + "index": 1009, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "B_Giorno_H2O": { + "name": "B_Giorno_H2O", + "description": "Linea B Totale H2O Giorno", + "memAddr": "41019", + "tipoMem": "HLPInt", + "index": 1019, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 1, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "B_Giorno_Prod1": { + "name": "B_Giorno_Prod1", + "description": "Linea B Totale Prodotto 1 Giorno", + "memAddr": "40021", + "tipoMem": "HLPInt", + "index": 1021, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "B_Giorno_Prod2": { + "name": "B_Giorno_Prod2", + "description": "Linea B Totale Prodotto 2 Giorno", + "memAddr": "40023", + "tipoMem": "HLPInt", + "index": 1023, + "size": 2, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "l" + }, + "Dose_Staz_1": { + "name": "Dose_Staz_1", + "description": "Dose Stazione 1", + "memAddr": "40024", + "tipoMem": "Int", + "index": 24, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + }, + "Dose_Staz_2": { + "name": "Dose_Staz_2", + "description": "Dose Stazione 2", + "memAddr": "40025", + "tipoMem": "Int", + "index": 25, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + }, + "Dose_Staz_3": { + "name": "Dose_Staz_3", + "description": "Dose Stazione 3", + "memAddr": "40026", + "tipoMem": "Int", + "index": 26, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + }, + "Dose_Staz_4": { + "name": "Dose_Staz_4", + "description": "Dose Stazione 4", + "memAddr": "40027", + "tipoMem": "Int", + "index": 27, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + } + } +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_002_MBlock.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_002_MBlock.json new file mode 100644 index 00000000..6ce9d4fd --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_002_MBlock.json @@ -0,0 +1,6 @@ +{ + "ReadBlocks": { + "40016": 16, + "40999": 32 + } +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_002_alarm.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_002_alarm.json new file mode 100644 index 00000000..c684acec --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_002_alarm.json @@ -0,0 +1,27 @@ +[ + { + "description": "Allarmi Impianto", + "tipoMem": "DInt", + "memAddr": "40999", + "index": 999, + "size": 2, + "messages": [ + "##On Pompa 1", + "Allarme Pompa 1", + "##On Pompa 2", + "Allarme Pompa 2", + "##On Pompa 3", + "Allarme Pompa 3", + "##On Pompa 4", + "Allarme Pompa 4", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##" + ] + } +] \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_003.ini b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_003.ini new file mode 100644 index 00000000..fae12535 --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_003.ini @@ -0,0 +1,76 @@ +;Configurazione IOB-WIN +[IOB] +;Impianto Cedax di Turi (test) - Giacovelli +CNCTYPE=MODBUS_TCP_CEDAX +PING_MS_TIMEOUT=1000 + +[MACHINE] +VENDOR=CEDAX +MODEL=CEDAX Lavorazione + +[CNC] +IP=192.168.2.62 +PORT=502 + +[SERVER] +MPIP=http://192.168.1.14 +MPURL=/MP/IO +CMDBASE=/IOB/input/ +CMDFLOG=/IOB/flog/ +CMDALIVE=/IOB +CMDENABLED=/IOB/enabled/ +CMDADV1=?valore= +CMDREBO=/sendReboot.aspx?idxMacchina= + +[MEMORY] +ADDR_READ=41001 +ADDR_WRITE=41021 +SIZE_READ=20 +SIZE_WRITE=0 +HR_BASE_ADDR=40000 + + +[BLINK] +;MAX_COUNTER_BLINK = 30 +MAX_COUNTER_BLINK = 15 +;bit0 = 0 +;bit1 = 0 +;bit2 = 1 +;bit3 = 1 +;bit4 = 1 +;bit5 = 0 +;bit6 = 0 +;bit7 = 0 +BLINK_FILT=0 +;BLINK_FILT=28 + +[OPTPAR] +;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice +PZCOUNT_MODE=STD.DB85.DBRE16 +DISABLE_PZCOUNT=TRUE +ENABLE_SEND_PZC_BLOCK=TRUE +MIN_SEND_PZC_BLOCK=0 +MAX_SEND_PZC_BLOCK=100 +; GEST DATI DYN +ENABLE_DYN_DATA=TRUE +FORCE_DYN_DATA=TRUE +; gestione delta minimo accettabile tra min/MAX +DELTA_VAL=0.1 + +; clock base (da 10ms) +timerIntMs=10 + +; conf parametri memoria READ/WRITE +PARAM_CONF=GIACO_CEDAX_003.json + +NO_PING=TRUE +; conf blocchi memoria x READ +MEM_BLOCK=GIACO_CEDAX_003_MBlock.json +; conf aree allarme +ALARM_CONF=GIACO_CEDAX_003_alarm.json + +; rimozione check limiti min/max dynData +disDynDataRangeCheck=true + +[BRANCH] +NAME=master \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_01.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_003.json similarity index 62% rename from IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_01.json rename to IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_003.json index 30690b79..0635e72c 100644 --- a/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_01.json +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_003.json @@ -1,5 +1,47 @@ { "mMapWrite": { + "Dose_Staz_1": { + "name": "Dose_Staz_1", + "description": "Dose Stazione 1", + "memAddr": "40024", + "tipoMem": "Int", + "index": 24, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + }, + "Dose_Staz_2": { + "name": "Dose_Staz_2", + "description": "Dose Stazione 2", + "memAddr": "40025", + "tipoMem": "Int", + "index": 25, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + }, + "Dose_Staz_3": { + "name": "Dose_Staz_3", + "description": "Dose Stazione 3", + "memAddr": "40026", + "tipoMem": "Int", + "index": 26, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + } }, "mMapRead": { "Stag_H2O": { @@ -58,26 +100,12 @@ "maxVal": 999999999, "unit": "l" }, - "Stag_Prod4": { - "name": "Stag_Prod4", - "description": "Totale Prodotto 4 Stagione", - "memAddr": "40009", - "tipoMem": "HLPInt", - "index": 1009, - "size": 2, - "func": "MEDIAN", - "period": 90, - "factor": 0.01, - "minVal": 0, - "maxVal": 999999999, - "unit": "l" - }, "Giorno_H2O": { "name": "Giorno_H2O", "description": "Totale H2O Giorno", - "memAddr": "41011", + "memAddr": "41009", "tipoMem": "HLPInt", - "index": 1011, + "index": 1009, "size": 2, "func": "MEDIAN", "period": 90, @@ -89,9 +117,9 @@ "Giorno_Prod1": { "name": "Giorno_Prod1", "description": "Totale Prodotto 1 Giorno", - "memAddr": "40013", + "memAddr": "40011", "tipoMem": "HLPInt", - "index": 1013, + "index": 1011, "size": 2, "func": "MEDIAN", "period": 90, @@ -103,9 +131,9 @@ "Giorno_Prod2": { "name": "Giorno_Prod2", "description": "Totale Prodotto 2 Giorno", - "memAddr": "40015", + "memAddr": "40013", "tipoMem": "HLPInt", - "index": 1015, + "index": 1013, "size": 2, "func": "MEDIAN", "period": 90, @@ -117,9 +145,9 @@ "Giorno_Prod3": { "name": "Giorno_Prod3", "description": "Totale Prodotto 3 Giorno", - "memAddr": "40017", + "memAddr": "40015", "tipoMem": "HLPInt", - "index": 1017, + "index": 1015, "size": 2, "func": "MEDIAN", "period": 90, @@ -128,19 +156,47 @@ "maxVal": 999999999, "unit": "l" }, - "Giorno_Prod4": { - "name": "Giorno_Prod4", - "description": "Totale Prodotto 4 Giorno", - "memAddr": "40021", - "tipoMem": "HLPInt", - "index": 1021, - "size": 2, + "Dose_Staz_1": { + "name": "Dose_Staz_1", + "description": "Dose Stazione 1", + "memAddr": "40024", + "tipoMem": "Int", + "index": 24, + "size": 1, "func": "MEDIAN", "period": 90, "factor": 0.01, "minVal": 0, "maxVal": 999999999, - "unit": "l" + "unit": "%" + }, + "Dose_Staz_2": { + "name": "Dose_Staz_2", + "description": "Dose Stazione 2", + "memAddr": "40025", + "tipoMem": "Int", + "index": 25, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" + }, + "Dose_Staz_3": { + "name": "Dose_Staz_3", + "description": "Dose Stazione 3", + "memAddr": "40026", + "tipoMem": "Int", + "index": 26, + "size": 1, + "func": "MEDIAN", + "period": 90, + "factor": 0.01, + "minVal": 0, + "maxVal": 999999999, + "unit": "%" } } } \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_003_MBlock.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_003_MBlock.json new file mode 100644 index 00000000..6ce9d4fd --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_003_MBlock.json @@ -0,0 +1,6 @@ +{ + "ReadBlocks": { + "40016": 16, + "40999": 32 + } +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_003_alarm.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_003_alarm.json new file mode 100644 index 00000000..c684acec --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_003_alarm.json @@ -0,0 +1,27 @@ +[ + { + "description": "Allarmi Impianto", + "tipoMem": "DInt", + "memAddr": "40999", + "index": 999, + "size": 2, + "messages": [ + "##On Pompa 1", + "Allarme Pompa 1", + "##On Pompa 2", + "Allarme Pompa 2", + "##On Pompa 3", + "Allarme Pompa 3", + "##On Pompa 4", + "Allarme Pompa 4", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##" + ] + } +] \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_01_MBlock.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_01_MBlock.json deleted file mode 100644 index b5e46ee5..00000000 --- a/IOB-WIN-NEXT/DATA/CONF/GIACO_CEDAX_01_MBlock.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ReadBlocks": { - "40999": 30 - } -} \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_CENTERFRIGO.ini b/IOB-WIN-NEXT/DATA/CONF/GIACO_CENTERFRIGO.ini new file mode 100644 index 00000000..80cf0d15 --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_CENTERFRIGO.ini @@ -0,0 +1,79 @@ +;Configurazione IOB-WIN +[IOB] +;Impianto Cedax di Turi (test) - Giacovelli +CNCTYPE=MODBUS_TCP_CENTERFRIGO +PING_MS_TIMEOUT=1000 + +[MACHINE] +VENDOR=Centerfrigo +MODEL=Impianto Turi + +[CNC] +IP=192.168.4.161 +PORT=502 + +[SERVER] +MPIP=http://192.168.1.14 +MPURL=/MP/IO +CMDBASE=/IOB/input/ +CMDFLOG=/IOB/flog/ +CMDALIVE=/IOB +CMDENABLED=/IOB/enabled/ +CMDADV1=?valore= +CMDREBO=/sendReboot.aspx?idxMacchina= + +[MEMORY] +ADDR_READ=40001 +ADDR_WRITE=41000 +SIZE_READ=2400 +SIZE_WRITE=0 +HR_BASE_ADDR=40000 +DELTA_BASE=0 + +[BLINK] +;MAX_COUNTER_BLINK = 30 +MAX_COUNTER_BLINK = 15 +;bit0 = 0 +;bit1 = 0 +;bit2 = 1 +;bit3 = 1 +;bit4 = 1 +;bit5 = 0 +;bit6 = 0 +;bit7 = 0 +BLINK_FILT=0 +;BLINK_FILT=28 + +[OPTPAR] +;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice +PZCOUNT_MODE=STD.DB85.DBRE16 +DISABLE_PZCOUNT=TRUE +ENABLE_SEND_PZC_BLOCK=TRUE +MIN_SEND_PZC_BLOCK=0 +MAX_SEND_PZC_BLOCK=100 +; GEST DATI DYN +ENABLE_DYN_DATA=TRUE +FORCE_DYN_DATA=TRUE +; gestione delta minimo accettabile tra min/MAX +DELTA_VAL=0.1 + +; clock base (da 10ms) +timerIntMs=100 +minWait=50 +maxWait=150 + + +; conf parametri memoria READ/WRITE +PARAM_CONF=GIACO_CENTERFRIGO.json + +NO_PING=FALSE +; conf blocchi memoria x READ +MEM_BLOCK=GIACO_CENTERFRIGO_MBlock.json +; conf aree allarme +ALARM_CONF=GIACO_CENTERFRIGO_alarm.json + +; rimozione check limiti min/max dynData +disDynDataRangeCheck=true + +[BRANCH] +NAME=master \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_CENTERFRIGO.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_CENTERFRIGO.json new file mode 100644 index 00000000..7b06ce3d --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_CENTERFRIGO.json @@ -0,0 +1,426 @@ +{ + "mMapWrite": { + "TestWrite": { + "name": "TestWrite", + "description": "Test Scrittura", + "memAddr": "41621", + "tipoMem": "Real", + "index": 1621, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "SetPoint_Tunnel": { + "name": "SetPoint_Tunnel", + "description": "Setpoint Tunnel", + "memAddr": "41560", + "tipoMem": "Real", + "index": 1560, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + } + }, + "mMapRead": { + "Temp_Tunnel": { + "name": "Temp_Tunnel", + "description": "Temperatura Tunnel", + "memAddr": "41520", + "tipoMem": "Real", + "index": 1520, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "SetPoint_Tunnel": { + "name": "SetPoint_Tunnel", + "description": "Setpoint Tunnel", + "memAddr": "41560", + "tipoMem": "Real", + "index": 1560, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "Temp_Cella_01": { + "name": "Temp_Cella_01", + "description": "Temperatura Cella 01", + "memAddr": "41660", + "tipoMem": "Real", + "index": 1660, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "SetPoint_Cella_01": { + "name": "SetPoint_Cella_01", + "description": "Setpoint Cella 01", + "memAddr": "41700", + "tipoMem": "Real", + "index": 1700, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "Temp_Cella_02": { + "name": "Temp_Cella_02", + "description": "Temperatura Cella 02", + "memAddr": "41810", + "tipoMem": "Real", + "index": 1810, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "SetPoint_Cella_02": { + "name": "SetPoint_Cella_02", + "description": "Setpoint Cella 02", + "memAddr": "41840", + "tipoMem": "Real", + "index": 1840, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "Temp_Cella_03": { + "name": "Temp_Cella_03", + "description": "Temperatura Cella 03", + "memAddr": "41930", + "tipoMem": "Real", + "index": 1930, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "SetPoint_Cella_03": { + "name": "SetPoint_Cella_03", + "description": "Setpoint Cella 03", + "memAddr": "41960", + "tipoMem": "Real", + "index": 1960, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "Temp_Cella_04": { + "name": "Temp_Cella_04", + "description": "Temperatura Cella 04", + "memAddr": "42050", + "tipoMem": "Real", + "index": 2050, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "SetPoint_Cella_04": { + "name": "SetPoint_Cella_04", + "description": "Setpoint Cella 04", + "memAddr": "41840", + "tipoMem": "Real", + "index": 1840, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "Temp_Sala_Bassa": { + "name": "Temp_Sala_Bassa", + "description": "Temperatura Sala Zona Bassa", + "memAddr": "42290", + "tipoMem": "Real", + "index": 2290, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "SetPoint_Sala_Bassa": { + "name": "SetPoint_Sala_Bassa", + "description": "Setpoint Sala Zona Bassa", + "memAddr": "42330", + "tipoMem": "Real", + "index": 2330, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "Temp_Sala_Alta": { + "name": "Temp_Sala_Alta", + "description": "Temperatura Sala Zona Alta", + "memAddr": "42420", + "tipoMem": "Real", + "index": 2420, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "SetPoint_Sala_Alta": { + "name": "SetPoint_Sala_Alta", + "description": "Setpoint Sala Zona Alta", + "memAddr": "42460", + "tipoMem": "Real", + "index": 2460, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "Temp_Hydrocooler": { + "name": "Temp_Hydrocooler", + "description": "Temperatura Hydrocooler", + "memAddr": "42550", + "tipoMem": "Real", + "index": 2550, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "SetPoint_Hydrocooler": { + "name": "SetPoint_Hydrocooler", + "description": "Setpoint Hydrocooler", + "memAddr": "42580", + "tipoMem": "Real", + "index": 2580, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "Temp_Calibr_01": { + "name": "Temp_Calibr_01", + "description": "Temperatura Calibratrice 01", + "memAddr": "42670", + "tipoMem": "Real", + "index": 2670, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "SetPoint_Calibr_01": { + "name": "SetPoint_Calibr_01", + "description": "SetPoint Calibratrice 01", + "memAddr": "42710", + "tipoMem": "Real", + "index": 2710, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "Temp_Calibr_02": { + "name": "Temp_Calibr_02", + "description": "Temperatura Calibratrice 02", + "memAddr": "42800", + "tipoMem": "Real", + "index": 2800, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "SetPoint_Calibr_02": { + "name": "SetPoint_Calibr_02", + "description": "SetPoint Calibratrice 02", + "memAddr": "42830", + "tipoMem": "Real", + "index": 2830, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "Temp_Calibr_03": { + "name": "Temp_Calibr_03", + "description": "Temperatura Calibratrice 03", + "memAddr": "42920", + "tipoMem": "Real", + "index": 2920, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "SetPoint_Calibr_03": { + "name": "SetPoint_Calibr_03", + "description": "SetPoint Calibratrice 03", + "memAddr": "42950", + "tipoMem": "Real", + "index": 2950, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "Temp_Calibr_04": { + "name": "Temp_Calibr_04", + "description": "Temperatura Calibratrice 04", + "memAddr": "43050", + "tipoMem": "Real", + "index": 3050, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "SetPoint_Calibr_04": { + "name": "SetPoint_Calibr_04", + "description": "SetPoint Calibratrice 04", + "memAddr": "43080", + "tipoMem": "Real", + "index": 3080, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "Temp_Serbatoi": { + "name": "Temp_Serbatoi", + "description": "Temperatura Searbatoi", + "memAddr": "43170", + "tipoMem": "Real", + "index": 3170, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "SetPoint_Searbatoi": { + "name": "SetPoint_Searbatoi", + "description": "SetPoint Searbatoi", + "memAddr": "43200", + "tipoMem": "Real", + "index": 3200, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "Temp_Serpentine": { + "name": "Temp_Serpentine", + "description": "Temperatura Serpentine", + "memAddr": "43290", + "tipoMem": "Real", + "index": 3290, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + }, + "SetPoint_Serpentine": { + "name": "SetPoint_Serpentine", + "description": "SetPoint Serpentine", + "memAddr": "43320", + "tipoMem": "Real", + "index": 3320, + "size": 2, + "func": "MEDIAN", + "period": 60, + "factor": 1, + "minVal": -100, + "maxVal": 100, + "unit": "°C" + } + } +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_CENTERFRIGO_MBlock.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_CENTERFRIGO_MBlock.json new file mode 100644 index 00000000..da89c677 --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_CENTERFRIGO_MBlock.json @@ -0,0 +1,25 @@ +{ + "ReadBlocks": { + "41500": 32, + "41532": 32, + "41616": 32, + "41650": 32, + "41682": 32, + "41800": 32, + "41832": 32, + "41920": 44, + "42040": 44, + "42160": 8, + "42290": 44, + "42410": 32, + "42442": 32, + "42540": 44, + "42660": 32, + "42692": 32, + "42790": 44, + "42910": 44, + "43040": 44, + "43160": 44, + "43280": 44 + } +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_CENTERFRIGO_alarm.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_CENTERFRIGO_alarm.json new file mode 100644 index 00000000..2220b2a4 --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_CENTERFRIGO_alarm.json @@ -0,0 +1,227 @@ +[ + { + "description": "Centrale Frigorifera", + "tipoMem": "DInt", + "memAddr": "41508", + "index": 1508, + "size": 2, + "messages": [ + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "ALLARME CENTRALE FRIGORIFERA", + "ALLARME GENERICO IMPIANTO", + "##", + "##", + "##", + "##", + "##", + "##", + "##" + ] + }, + { + "description": "Allarmi Tunnel", + "tipoMem": "DInt", + "memAddr": "41654", + "index": 1654, + "size": 2, + "messages": [ + "ALLARME ALTA TEMPERATURA AMBIENTE TUNNEL", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "ALLARME CUMULATIVO TUNNEL", + "##", + "##", + "##", + "##", + "##" + ] + }, + { + "description": "Allarmi Cella 01", + "tipoMem": "DInt", + "memAddr": "41804", + "index": 1804, + "size": 2, + "messages": [ + "ALLARME ALTA TEMPERATURA AMBIENTE CELLA 01", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "ALLARME CUMULATIVO CELLA 01", + "##", + "##", + "##", + "##", + "##" + ] + }, + { + "description": "Allarmi Cella 02", + "tipoMem": "DInt", + "memAddr": "41924", + "index": 1924, + "size": 2, + "messages": [ + "ALLARME ALTA TEMPERATURA AMBIENTE CELLA 02", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "ALLARME CUMULATIVO CELLA 02", + "##", + "##", + "##", + "##", + "##" + ] + }, + { + "description": "Allarmi Cella 03", + "tipoMem": "DInt", + "memAddr": "42044", + "index": 2044, + "size": 2, + "messages": [ + "ALLARME ALTA TEMPERATURA AMBIENTE CELLA 03", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "ALLARME CUMULATIVO CELLA 03", + "##", + "##", + "##", + "##", + "##" + ] + }, +// { +// "description": "Allarmi Cella 04", +// "tipoMem": "DInt", +// "memAddr": "42164", +// "index": 2164, +// "size": 2, +// "messages": [ +// "ALLARME ALTA TEMPERATURA AMBIENTE CELLA 04", +// "##", +// "##", +// "##", +// "##", +// "##", +// "##", +// "##", +// "##", +// "##", +// "ALLARME CUMULATIVO CELLA 04", +// "##", +// "##", +// "##", +// "##", +// "##" +// ] +// }, + { + "description": "Allarmi Sala Bassa", + "tipoMem": "DInt", + "memAddr": "42414", + "index": 2414, + "size": 2, + "messages": [ + "ALLARME ALTA TEMPERATURA AMBIENTE SALA BASSA", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "ALLARME CUMULATIVO SALA BASSA", + "##", + "##", + "##", + "##", + "##" + ] + }, + { + "description": "Allarmi Sala Alta", + "tipoMem": "DInt", + "memAddr": "42544", + "index": 2544, + "size": 2, + "messages": [ + "ALLARME ALTA TEMPERATURA AMBIENTE SALA ALTA", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "ALLARME CUMULATIVO SALA ALTA", + "##", + "##", + "##", + "##", + "##" + ] + }, + { + "description": "Allarmi Hydrocooler", + "tipoMem": "DInt", + "memAddr": "42664", + "index": 2664, + "size": 2, + "messages": [ + "ALLARME ALTA TEMPERATURA AMBIENTE HYDROCOOLER", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "ALLARME CUMULATIVO HYDROCOOLER", + "##", + "##", + "##", + "##", + "##" + ] + } +] \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_001.ini b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_001.ini index 7eee9efe..1e80902f 100644 --- a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_001.ini +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_001.ini @@ -3,7 +3,6 @@ ;Centro di lavoro OpcUa CNCTYPE=OpcUaOmronIcoel PING_MS_TIMEOUT=500 -IOB_NAME=GIACO_ICOEL [MACHINE] VENDOR=ICOEL diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini index 16caef0b..3cf5fb6e 100644 --- a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.ini @@ -3,7 +3,7 @@ ;WebService SOAP x sizer CNCTYPE=IcoelSoap PING_MS_TIMEOUT=500 -IOB_NAME=GIACO_ICOEL +;IOB_NAME=GIACO_ICOEL [MACHINE] VENDOR=ICOEL @@ -19,6 +19,7 @@ MPIP=http://192.168.1.14 MPURL=/MP/IO CMDBASE=/IOB/input/ CMDFLOG=/IOB/flog/ +CMDRAWTRANSF=/IOB/rawTransfJson/ CMDALIVE=/IOB CMDENABLED=/IOB/enabled/ CMDADV1=?valore= @@ -60,14 +61,17 @@ DISABLE_PZCOUNT=FALSE ENABLE_SEND_PZC_BLOCK=TRUE MIN_SEND_PZC_BLOCK=0 MAX_SEND_PZC_BLOCK=100 -ENABLE_DYN_DATA=FALSE +ENABLE_DYN_DATA=TRUE FORCE_DYN_DATA=TRUE +DEM_FACT_DYN_DATA=2 ENABLE_DATA_FILTER=TRUE ENABLE_CLI_RESTART=TRUE -VETO_SIG_IN=TRUE + +; clock base (da 10ms) +timerIntMs=40 ; conf parametri memoria READ/WRITE -OPC_PARAM_CONF=GIACO_ICOEL_001.json +PARAM_CONF=GIACO_ICOEL_002.json [BRANCH] NAME=master \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.json new file mode 100644 index 00000000..df6898b4 --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_002.json @@ -0,0 +1,124 @@ +{ + "mMapWrite": { + "setSupplier": { + "name": "setSupplier", + "description": "Send Batch req (GrowerCode|Descript)", + "tipoMem": "String", + "memAddr": "setSupplier", + "index": 0, + "size": 50 + } + }, + "mMapRead": { + "VelTonnOra": { + "name": "VelTonnOra", + "description": "Vel. Impianto Tonnellate / Ora", + "memAddr": "VelTonnOra", + "tipoMem": "Real", + "index": 0, + "size": 0, + "func": "AVG", + "period": 50, + "factor": 1 + }, + "VelFruttiMinuto": { + "name": "VelFruttiMinuto", + "description": "Vel. Impianto Frutti / Minuto", + "memAddr": "VelFruttiMinuto", + "tipoMem": "Real", + "index": 0, + "size": 0, + "func": "AVG", + "period": 50, + "factor": 1 + }, + "NumPacksOra": { + "name": "NumPacksOra", + "description": "Numero confezioni / Ora", + "memAddr": "NumPacksOra", + "tipoMem": "Real", + "index": 0, + "size": 0, + "func": "AVG", + "period": 50, + "factor": 1 + }, + "PercRiemp": { + "name": "PercRiemp", + "description": "Percentuale riempimento carrelli", + "memAddr": "PercRiemp", + "tipoMem": "Real", + "index": 0, + "size": 0, + "func": "AVG", + "period": 50, + "factor": 1 + }, + "L1_Batch": { + "name": "L1_Batch", + "description": "Curr Batch", + "tipoMem": "String", + "memAddr": "L1_Batch", + "index": 0, + "size": 50, + "func": "POINT", + "period": 120, + "factor": 1 + }, + "L2_Batch": { + "name": "L2_Batch", + "description": "Curr Batch", + "tipoMem": "String", + "memAddr": "L2_Batch", + "index": 0, + "size": 50, + "func": "POINT", + "period": 120, + "factor": 1 + }, + "L1_Grower": { + "name": "L1_Grower", + "description": "Grower Data", + "tipoMem": "String", + "memAddr": "L1_Grower", + "index": 0, + "size": 50, + "func": "POINT", + "period": 120, + "factor": 1 + }, + "L2_Grower": { + "name": "L2_Grower", + "description": "Grower Data", + "tipoMem": "String", + "memAddr": "L2_Grower", + "index": 0, + "size": 50, + "func": "POINT", + "period": 120, + "factor": 1 + }, + "L1_Variety": { + "name": "L1_Variety", + "description": "Variety Data", + "tipoMem": "String", + "memAddr": "L1_Variety", + "index": 0, + "size": 50, + "func": "POINT", + "period": 120, + "factor": 1 + }, + "L2_Variety": { + "name": "L2_Variety", + "description": "Variety Data", + "tipoMem": "String", + "memAddr": "L2_Variety", + "index": 0, + "size": 50, + "func": "POINT", + "period": 120, + "factor": 1 + } + } +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini new file mode 100644 index 00000000..249ff7e5 --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.ini @@ -0,0 +1,81 @@ +;Configurazione IOB-WIN +[IOB] +;Accesso gestione sync DB x sync ICOEL --> MoonPro_ISF --> MoonPro_IS +CNCTYPE=IcoelDb +PING_MS_TIMEOUT=500 +;IOB_NAME=GIACO_ICOEL + +[MACHINE] +VENDOR=ICOEL +MODEL=Impianto Ciliegie Turi + +[CNC] +IP=192.168.137.11 +PORT=1443 +GETPRGNAME=false + +[SERVER] +MPIP=http://192.168.1.14 +MPURL=/MP/IO +CMDBASE=/IOB/input/ +CMDFLOG=/IOB/flog/ +CMDRAWTRANSF=/IOB/rawTransfJson/ +CMDALIVE=/IOB +CMDENABLED=/IOB/enabled/ +CMDADV1=?valore= +CMDREBO=/sendReboot.aspx?idxMacchina= + +[MEMORY] +ADDR_READ=DB9999.DBB0 +ADDR_WRITE=DB9999.DBB0 +SIZE_READ=0 +SIZE_WRITE=0 +;BIT0=CONN +;BIT1=DB60.DBB1 +;BIT2=PZCOUNT.STD.DB700.DBW22 +;BIT3=DB60.DBB3 +;BIT4=DB60.DBB4 + + +[BLINK] +;MAX_COUNTER_BLINK = 30 +MAX_COUNTER_BLINK = 15 +;bit0 = 0 +;bit1 = 0 +;bit2 = 1 +;bit3 = 1 +;bit4 = 1 +;bit5 = 0 +;bit6 = 0 +;bit7 = 0 +BLINK_FILT=0 +;BLINK_FILT=28 + +[OPTPAR] +AUTO_CHANGE_ODL=false +CHANGE_ODL_MODE=TIME +CHANGE_ODL_HOURS=24 +CHANGE_ODL_IDLE_MIN=5 +PZCOUNT_MODE=Icoel +DISABLE_PZCOUNT=FALSE +ENABLE_SEND_PZC_BLOCK=TRUE +MIN_SEND_PZC_BLOCK=0 +MAX_SEND_PZC_BLOCK=100 +ENABLE_DYN_DATA=TRUE +FORCE_DYN_DATA=TRUE +DEM_FACT_DYN_DATA=5 +ENABLE_DATA_FILTER=TRUE +ENABLE_CLI_RESTART=TRUE +SyncStateDb=localhost\sqlexpress +SyncStateUser=egalware +SyncStatePwd=egalware2022 +SyncStateCTout= + +; clock base (da 10ms) +timerIntMs=20 + +; conf parametri memoria READ/WRITE +PARAM_CONF=GIACO_ICOEL_003.json + +[BRANCH] +NAME=master \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.json new file mode 100644 index 00000000..96401b9a --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_ICOEL_003.json @@ -0,0 +1,29 @@ +{ + "mMapWrite": { + + }, + "mMapRead": { + "TotMerceProcTonn": { + "name": "TotMerceProcTonn", + "description": "Totale merce processata oggi su impianto (Tonn)", + "memAddr": "TotMerceProcTonn", + "tipoMem": "Real", + "index": 0, + "size": 0, + "func": "MAX", + "period": 60, + "factor": 1 + }, + "TotMerceCaricTonn": { + "name": "TotMerceCaricTonn", + "description": "Totale merce caricata oggi su impianto (Tonn)", + "memAddr": "TotMerceCaricTonn", + "tipoMem": "Real", + "index": 0, + "size": 0, + "func": "MAX", + "period": 60, + "factor": 1 + } + } +} diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_NWSE.ini b/IOB-WIN-NEXT/DATA/CONF/GIACO_NWSE.ini new file mode 100644 index 00000000..a05d14d4 --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_NWSE.ini @@ -0,0 +1,71 @@ +;Configurazione IOB-WIN +[IOB] +;Macchina pulitrice RobotService x Donati +CNCTYPE=SIEMENS_NWSE +PING_MS_TIMEOUT=500 + +[MACHINE] +VENDOR=NWS +MODEL=Impianto Turi + +[CNC] +IP=192.168.19.10 +CPUTYPE=S71200 +RACK=0 +SLOT=0 + +[SERVER] +MPIP=http://192.168.1.14 +MPURL=/MP/IO +CMDBASE=/IOB/input/ +CMDFLOG=/IOB/flog/ +CMDALIVE=/IOB +CMDENABLED=/IOB/enabled/ +CMDADV1=?valore= +CMDREBO=/sendReboot.aspx?idxMacchina= + +[MEMORY] +ADDR_READ=DB100.DBB0 +ADDR_WRITE=DB101.DBB0 +SIZE_READ=54 +SIZE_WRITE=8 + + +[BLINK] +;MAX_COUNTER_BLINK = 30 +MAX_COUNTER_BLINK = 15 +;bit0 = 0 +;bit1 = 0 +;bit2 = 1 +;bit3 = 1 +;bit4 = 1 +;bit5 = 0 +;bit6 = 0 +;bit7 = 0 +BLINK_FILT=0 +;BLINK_FILT=28 + +[OPTPAR] +;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice +PZCOUNT_MODE=STD.DB15.DBDW2 +DISABLE_PZCOUNT=TRUE +ENABLE_SEND_PZC_BLOCK=TRUE +MIN_SEND_PZC_BLOCK=0 +MAX_SEND_PZC_BLOCK=100 +; gestione custom timer +timerIntMs=30 +; GEST DATI DYN +ENABLE_DYN_DATA=TRUE +FORCE_DYN_DATA=TRUE +; gestione scrittura string/char[]: true = string / false = char[] +WRITE_PRE=TRUE +; gestione emergenza forzata (ignora valore letto, mette sempre ARMED) +EMERGENCY_BYPASS=true + +; conf parametri memoria READ/WRITE +PARAM_CONF=GIACO_NWSE.json +; conf aree allarme +ALARM_CONF=GIACO_NWSE_alarm.json + +[BRANCH] +NAME=master \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_NWSE.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_NWSE.json new file mode 100644 index 00000000..4c8c25cf --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_NWSE.json @@ -0,0 +1,212 @@ +{ + "mMapWrite": { + "resetCountAcqua": { + "name": "resetCountAcqua", + "description": "Reset contatori acqua OSMOSI / DEPURAZIONE", + "tipoMem": "Int", + "memAddr": "DB101.DBB0", + "index": 0, + "size": 2 + } + }, + "mMapRead": { + "CondOsmosi": { + "name": "CondOsmosi", + "description": "Conducib. H2O Osmosi", + "memAddr": "DB100.DBB40", + "tipoMem": "Int", + "index": 40, + "size": 2, + "func": "MAX", + "period": 60, + "factor": 1 + }, + "VolOsmosi": { + "name": "VolOsmosi", + "description": "Volume H2O Osmosi mc", + "memAddr": "DB100.DBB42", + "tipoMem": "Int", + "index": 40, + "size": 2, + "func": "MAX", + "period": 60, + "factor": 1 + }, + "StatoOsmosi": { + "name": "StatoOsmosi", + "description": "Stato Osmosi Inversa", + "memAddr": "DB100.DBB20", + "tipoMem": "BitMap", + "index": 20, + "size": 2, + "func": "MAX", + "period": 60, + "factor": 1, + "decodeMap": [ + "Impianto in servizio" + ] + }, + "TorbDepuraz": { + "name": "TorbDepuraz", + "description": "Torb. H2O Depurazione", + "memAddr": "DB100.DBB44", + "tipoMem": "Int", + "index": 44, + "size": 2, + "func": "MAX", + "period": 60, + "factor": 1 + }, + "VolDepuraz": { + "name": "VolDepuraz", + "description": "Volume acqua Depurazione mc", + "memAddr": "DB100.DBB46", + "tipoMem": "Int", + "index": 40, + "size": 2, + "func": "MAX", + "period": 60, + "factor": 1 + }, + "StatoDepurazione": { + "name": "StatoDepurazione", + "description": "Stato Depurazione", + "memAddr": "DB100.DBB22", + "tipoMem": "BitMap", + "index": 22, + "size": 2, + "func": "MAX", + "period": 60, + "factor": 1, + "decodeMap": [ + "Basso Livello", + "Alto Livello" + ] + }, + "TorbFiltri": { + "name": "TorbFiltri", + "description": "Torb. H2O Filtri", + "memAddr": "DB100.DBB48", + "tipoMem": "Int", + "index": 44, + "size": 2, + "func": "MAX", + "period": 60, + "factor": 1 + }, + "StatoFiltro01": { + "name": "StatoFiltro01", + "description": "Stato Filtro 1", + "memAddr": "DB100.DBB24", + "tipoMem": "BitMap", + "index": 24, + "size": 2, + "func": "MAX", + "period": 60, + "factor": 1, + "decodeMap": [ + "Spazzola in salita", + "Spazzola in discesa", + "Valvola scarico Chiusa", + "Valvola scarico Aperta", + "Impianto in Servizio", + "Impianto in Lavaggio" + ] + }, + "StatoFiltro02": { + "name": "StatoFiltro02", + "description": "Stato Filtro 2", + "memAddr": "DB100.DBB26", + "tipoMem": "BitMap", + "index": 26, + "size": 2, + "func": "MAX", + "period": 60, + "factor": 1, + "decodeMap": [ + "Spazzola in salita", + "Spazzola in discesa", + "Valvola scarico Chiusa", + "Valvola scarico Aperta", + "Impianto in Servizio", + "Impianto in Lavaggio" + ] + }, + "StatoFiltro03": { + "name": "StatoFiltro03", + "description": "Stato Filtro 3", + "memAddr": "DB100.DBB28", + "tipoMem": "BitMap", + "index": 28, + "size": 2, + "func": "MAX", + "period": 60, + "factor": 1, + "decodeMap": [ + "Spazzola in salita", + "Spazzola in discesa", + "Valvola scarico Chiusa", + "Valvola scarico Aperta", + "Impianto in Servizio", + "Impianto in Lavaggio" + ] + }, + "StatoFiltro04": { + "name": "StatoFiltro04", + "description": "Stato Filtro 4", + "memAddr": "DB100.DBB30", + "tipoMem": "BitMap", + "index": 30, + "size": 2, + "func": "MAX", + "period": 60, + "factor": 1, + "decodeMap": [ + "Spazzola in salita", + "Spazzola in discesa", + "Valvola scarico Chiusa", + "Valvola scarico Aperta", + "Impianto in Servizio", + "Impianto in Lavaggio" + ] + }, + "StatoFiltro05": { + "name": "StatoFiltro05", + "description": "Stato Filtro 5", + "memAddr": "DB100.DBB32", + "tipoMem": "BitMap", + "index": 32, + "size": 2, + "func": "MAX", + "period": 60, + "factor": 1, + "decodeMap": [ + "Spazzola in salita", + "Spazzola in discesa", + "Valvola scarico Chiusa", + "Valvola scarico Aperta", + "Impianto in Servizio", + "Impianto in Lavaggio" + ] + }, + "StatoFiltro06": { + "name": "StatoFiltro06", + "description": "Stato Filtro 6", + "memAddr": "DB100.DBB34", + "tipoMem": "BitMap", + "index": 34, + "size": 2, + "func": "MAX", + "period": 60, + "factor": 1, + "decodeMap": [ + "Spazzola in salita", + "Spazzola in discesa", + "Valvola scarico Chiusa", + "Valvola scarico Aperta", + "Impianto in Servizio", + "Impianto in Lavaggio" + ] + } + } +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/GIACO_NWSE_alarm.json b/IOB-WIN-NEXT/DATA/CONF/GIACO_NWSE_alarm.json new file mode 100644 index 00000000..d8226c2d --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/GIACO_NWSE_alarm.json @@ -0,0 +1,202 @@ +[ + { + "description": "Allarmi Impianto Osmosi", + "tipoMem": "Boolean", + "memAddr": "DB100.DBB0", + "index": 0, + "size": 2, + "messages": [ + "Avaria pompa ingresso", + "Avaria pompa alta pressione", + "Livello basso vasca osmosi", + "Livello basso vasca acqua grezza", + "Impianto in allarme", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "Allarme comunicazione con Gateway" + ] + }, + { + "description": "Allarmi Impianto Depurazione", + "tipoMem": "Boolean", + "memAddr": "DB100.DBB2", + "index": 2, + "size": 2, + "messages": [ + "Avaria pompa 1", + "Avaria pompa 2", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "Allarme comunicazione con Gateway" + ] + }, + { + "description": "Allarmi Filtro 1", + "tipoMem": "Boolean", + "memAddr": "DB100.DBB4", + "index": 4, + "size": 2, + "messages": [ + "Avaria pompa", + "Livello basso vasca", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##" + ] + }, + { + "description": "Allarmi Filtro 2", + "tipoMem": "Boolean", + "memAddr": "DB100.DBB6", + "index": 6, + "size": 2, + "messages": [ + "Avaria pompa", + "Livello basso vasca", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##" + ] + }, + { + "description": "Allarmi Filtro 3", + "tipoMem": "Boolean", + "memAddr": "DB100.DBB8", + "index": 8, + "size": 2, + "messages": [ + "Avaria pompa", + "Livello basso vasca", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##" + ] + }, + { + "description": "Allarmi Filtro 4", + "tipoMem": "Boolean", + "memAddr": "DB100.DBB10", + "index": 10, + "size": 2, + "messages": [ + "Avaria pompa", + "Livello basso vasca", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##" + ] + }, + { + "description": "Allarmi Filtro 5", + "tipoMem": "Boolean", + "memAddr": "DB100.DBB12", + "index": 12, + "size": 2, + "messages": [ + "Avaria pompa", + "Livello basso vasca", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##" + ] + }, + { + "description": "Allarmi Filtro 6", + "tipoMem": "Boolean", + "memAddr": "DB100.DBB14", + "index": 14, + "size": 2, + "messages": [ + "Avaria pompa", + "Livello basso vasca", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##", + "##" + ] + } +] \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/MAIN.ini b/IOB-WIN-NEXT/DATA/CONF/MAIN.ini index cb0aa7c3..54d5fe95 100644 --- a/IOB-WIN-NEXT/DATA/CONF/MAIN.ini +++ b/IOB-WIN-NEXT/DATA/CONF/MAIN.ini @@ -19,8 +19,7 @@ NAME=master ;MPIP=192.168.1.14 ; Server Steamware -MPIP=192.168.1.14 -;MPIP=10.74.82.218 +MPIP=10.74.82.218 MPURL=/MP/IO CMDREBO=/IOB/sendRebootGateway?GWIP= CMDIOB2CALL=/IOB/getIob2call?GWIP= @@ -29,56 +28,16 @@ CMDIOB2CALL=/IOB/getIob2call?GWIP= CLI_INST=SteamWareSim [IOB] -;--- TEST sul campo -;STARTLIST=VL24 -;STARTLIST=3018,3019 -;STARTLIST=WPS - -;SAET TEMPRA -;STARTLIST=VL20 - -;COMUR DENTA -;STARTLIST=VL21 - -;LASCO -;STARTLIST=VL22 - -;PRESSOIL CEI -;STARTLIST=VL23 - -;SAET FORNO -;STARTLIST=VL24 - -;AUTOMAZIONE INGENIA -;STARTLIST=VL25 - -; INTERCLAYS FORNO -;STARTLIST=INTERCL_01 - -; INTERCLAYS MISCELA -;STARTLIST=INTERCL_02 - -; IMI REMOSA -;STARTLIST=IMI_50 - +;--- TEST sul campo ; SIMULAZIONE verso server ufficio ;STARTLIST=SIMUL_01,SIMUL_02,SIMUL_03,SIMUL_04 -;STARTLIST=TEST -;STARTLIST=SIM_DP_01 -;STARTLIST=SIMUL_01 -;STARTLIST=1032 -;STARTLIST=PIZ03 -;STARTLIST=PIZ04 -;STARTLIST=OPC_UA -;STARTLIST=FOV062 -;STARTLIST=FP_TR2 -;STARTLIST=SIM_PIZ03 -;STARTLIST=MECART_80 -;STARTLIST=PING ;STARTLIST=PIZ09 ;STARTLIST=VL25 ;STARTLIST=SIMUL_03 -;STARTLIST=GIACO_CEDAX_01 -STARTLIST=GIACO_ICOEL_002 +;STARTLIST=GIACO_CEDAX_001 +;STARTLIST=GIACO_ICOEL_002 +;STARTLIST=GIACO_CENTERFRIGO +;STARTLIST=GIACO_NWSE +STARTLIST=SIMUL_01 MAXCNC=10 \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/SIMUL_01.ini b/IOB-WIN-NEXT/DATA/CONF/SIMUL_01.ini index 67eae433..187454cf 100644 --- a/IOB-WIN-NEXT/DATA/CONF/SIMUL_01.ini +++ b/IOB-WIN-NEXT/DATA/CONF/SIMUL_01.ini @@ -43,10 +43,10 @@ MIN_SEND_PZC_BLOCK=0 MAX_SEND_PZC_BLOCK=100 ; gestione cambio ODL automatico (minuti minimi durata) MIN_DURATA_ODL=240 -; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 1 secondo) -PER_BASE=10100 +; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 10 secondi) +PER_BASE=10100 SIM_PZCNT=5|1 -SIM_ALARM=1000|20 +SIM_ALARM=100|10 SIM_MANU=50|6 ; indica gestione e simulazione bit 5 --> slow SIM_SLOW=3600|20 diff --git a/IOB-WIN-NEXT/DATA/CONF/SIMUL_02.ini b/IOB-WIN-NEXT/DATA/CONF/SIMUL_02.ini index bca734ed..1d29f7ce 100644 --- a/IOB-WIN-NEXT/DATA/CONF/SIMUL_02.ini +++ b/IOB-WIN-NEXT/DATA/CONF/SIMUL_02.ini @@ -37,7 +37,7 @@ CHANGE_ODL_IDLE_MIN=0 ;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice PZCOUNT_MODE=BIT ENABLE_PZ_RESET=TRUE -; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 1 secondo) +; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 10 secondi) PER_BASE=9500 SIM_PZCNT=8|1 SIM_ALARM=900|15 diff --git a/IOB-WIN-NEXT/DATA/CONF/SIMUL_03.ini b/IOB-WIN-NEXT/DATA/CONF/SIMUL_03.ini index 08296d7e..bf726ca2 100644 --- a/IOB-WIN-NEXT/DATA/CONF/SIMUL_03.ini +++ b/IOB-WIN-NEXT/DATA/CONF/SIMUL_03.ini @@ -38,7 +38,7 @@ CHANGE_ODL_IDLE_MIN=0 ;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice PZCOUNT_MODE=BIT ENABLE_PZ_RESET=TRUE -; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE, default 1 secondo) +; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 10 secondi) PER_BASE=10400 SIM_PZCNT=15|1 SIM_ALARM=1000|20 diff --git a/IOB-WIN-NEXT/DATA/CONF/SIMUL_04.ini b/IOB-WIN-NEXT/DATA/CONF/SIMUL_04.ini index 403966e7..9cab64cb 100644 --- a/IOB-WIN-NEXT/DATA/CONF/SIMUL_04.ini +++ b/IOB-WIN-NEXT/DATA/CONF/SIMUL_04.ini @@ -37,7 +37,7 @@ CHANGE_ODL_IDLE_MIN=0 ;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice PZCOUNT_MODE=BIT ENABLE_PZ_RESET=TRUE -; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE, default 1 secondo) +; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 10 secondi) PER_BASE=10300 SIM_PZCNT=13|1 SIM_ALARM=1000|20 diff --git a/IOB-WIN-NEXT/DATA/CONF/SIMUL_05.ini b/IOB-WIN-NEXT/DATA/CONF/SIMUL_05.ini index 050dbbc5..de3910c9 100644 --- a/IOB-WIN-NEXT/DATA/CONF/SIMUL_05.ini +++ b/IOB-WIN-NEXT/DATA/CONF/SIMUL_05.ini @@ -37,7 +37,7 @@ CHANGE_ODL_IDLE_MIN=0 ;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice PZCOUNT_MODE=BIT ENABLE_PZ_RESET=TRUE -; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE, default 1 secondo) +; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 10 secondi) PER_BASE=10200 SIM_PZCNT=13|1 SIM_ALARM=1000|20 diff --git a/IOB-WIN-NEXT/DATA/CONF/SIMUL_06.ini b/IOB-WIN-NEXT/DATA/CONF/SIMUL_06.ini index 4e62781a..080f15ea 100644 --- a/IOB-WIN-NEXT/DATA/CONF/SIMUL_06.ini +++ b/IOB-WIN-NEXT/DATA/CONF/SIMUL_06.ini @@ -37,7 +37,7 @@ CHANGE_ODL_IDLE_MIN=0 ;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice PZCOUNT_MODE=BIT ENABLE_PZ_RESET=TRUE -; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE, default 1 secondo) +; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 10 secondi) PER_BASE=9600 SIM_PZCNT=13|1 SIM_ALARM=1000|20 diff --git a/IOB-WIN-NEXT/DATA/CONF/SIMUL_07.ini b/IOB-WIN-NEXT/DATA/CONF/SIMUL_07.ini index 344cbac7..d1d2e317 100644 --- a/IOB-WIN-NEXT/DATA/CONF/SIMUL_07.ini +++ b/IOB-WIN-NEXT/DATA/CONF/SIMUL_07.ini @@ -37,7 +37,7 @@ CHANGE_ODL_IDLE_MIN=0 ;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice PZCOUNT_MODE=BIT ENABLE_PZ_RESET=TRUE -; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE, default 1 secondo) +; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 10 secondi) PER_BASE=9900 SIM_PZCNT=13|1 SIM_ALARM=200|20 diff --git a/IOB-WIN-NEXT/DATA/CONF/SIMUL_08.ini b/IOB-WIN-NEXT/DATA/CONF/SIMUL_08.ini index 6acfc014..2050389c 100644 --- a/IOB-WIN-NEXT/DATA/CONF/SIMUL_08.ini +++ b/IOB-WIN-NEXT/DATA/CONF/SIMUL_08.ini @@ -37,7 +37,7 @@ CHANGE_ODL_IDLE_MIN=10 ;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice PZCOUNT_MODE=BIT ENABLE_PZ_RESET=TRUE -; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE, default 1 secondo) +; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 10 secondi) PER_BASE=9800 SIM_PZCNT=13|1 SIM_ALARM=200|10 diff --git a/IOB-WIN-NEXT/DATA/CONF/SIM_DP_01.ini b/IOB-WIN-NEXT/DATA/CONF/SIM_DP_01.ini index e94ec473..ed602c4d 100644 --- a/IOB-WIN-NEXT/DATA/CONF/SIM_DP_01.ini +++ b/IOB-WIN-NEXT/DATA/CONF/SIM_DP_01.ini @@ -44,7 +44,7 @@ ENABLE_SEND_PZC_BLOCK=TRUE MIN_SEND_PZC_BLOCK=0 MAX_SEND_PZC_BLOCK=100 MIN_DURATA_ODL=240 -; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 1 secondo) +; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 10 secondi) PER_BASE=10500 SIM_PZCNT=10|3 SIM_ALARM=1000|20 diff --git a/IOB-WIN-NEXT/DATA/CONF/SIM_DP_02.ini b/IOB-WIN-NEXT/DATA/CONF/SIM_DP_02.ini index ed26ab45..3b8d3b95 100644 --- a/IOB-WIN-NEXT/DATA/CONF/SIM_DP_02.ini +++ b/IOB-WIN-NEXT/DATA/CONF/SIM_DP_02.ini @@ -44,7 +44,7 @@ ENABLE_SEND_PZC_BLOCK=TRUE MIN_SEND_PZC_BLOCK=0 MAX_SEND_PZC_BLOCK=100 MIN_DURATA_ODL=240 -; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 1 secondo) +; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 10 secondi) PER_BASE=10400 SIM_PZCNT=10|2 SIM_ALARM=1000|20 diff --git a/IOB-WIN-NEXT/DATA/CONF/SIM_PIZ03.ini b/IOB-WIN-NEXT/DATA/CONF/SIM_PIZ03.ini index 370e9c26..769edb89 100644 --- a/IOB-WIN-NEXT/DATA/CONF/SIM_PIZ03.ini +++ b/IOB-WIN-NEXT/DATA/CONF/SIM_PIZ03.ini @@ -38,7 +38,7 @@ DISABLE_SIM_STATUS=true ;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice PZCOUNT_MODE=BIT ENABLE_PZ_RESET=TRUE -; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE, default 1 secondo) +; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 10 secondi) PER_BASE=9800 SIM_PZCNT=13|1 SIM_ALARM=200|10 diff --git a/IOB-WIN-NEXT/DATA/CONF/SIM_PIZ04.ini b/IOB-WIN-NEXT/DATA/CONF/SIM_PIZ04.ini index 370e9c26..769edb89 100644 --- a/IOB-WIN-NEXT/DATA/CONF/SIM_PIZ04.ini +++ b/IOB-WIN-NEXT/DATA/CONF/SIM_PIZ04.ini @@ -38,7 +38,7 @@ DISABLE_SIM_STATUS=true ;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice PZCOUNT_MODE=BIT ENABLE_PZ_RESET=TRUE -; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE, default 1 secondo) +; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 10 secondi) PER_BASE=9800 SIM_PZCNT=13|1 SIM_ALARM=200|10 diff --git a/IOB-WIN-NEXT/DATA/CONF/SIM_PIZ05.ini b/IOB-WIN-NEXT/DATA/CONF/SIM_PIZ05.ini index 370e9c26..769edb89 100644 --- a/IOB-WIN-NEXT/DATA/CONF/SIM_PIZ05.ini +++ b/IOB-WIN-NEXT/DATA/CONF/SIM_PIZ05.ini @@ -38,7 +38,7 @@ DISABLE_SIM_STATUS=true ;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice PZCOUNT_MODE=BIT ENABLE_PZ_RESET=TRUE -; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE, default 1 secondo) +; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 10 secondi) PER_BASE=9800 SIM_PZCNT=13|1 SIM_ALARM=200|10 diff --git a/IOB-WIN-NEXT/DATA/CONF/SIM_PIZ08.ini b/IOB-WIN-NEXT/DATA/CONF/SIM_PIZ08.ini index 370e9c26..769edb89 100644 --- a/IOB-WIN-NEXT/DATA/CONF/SIM_PIZ08.ini +++ b/IOB-WIN-NEXT/DATA/CONF/SIM_PIZ08.ini @@ -38,7 +38,7 @@ DISABLE_SIM_STATUS=true ;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice PZCOUNT_MODE=BIT ENABLE_PZ_RESET=TRUE -; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE, default 1 secondo) +; per il simulatore: 50|1 = WAIT 50, DURATION 1 con riferimento al PERIODO base (PER_BASE in ms, default 10 secondi) PER_BASE=9800 SIM_PZCNT=13|1 SIM_ALARM=200|10 diff --git a/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj b/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj index e5807f3c..7c8fcee7 100644 --- a/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj +++ b/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj @@ -1,5 +1,6 @@  + @@ -87,23 +88,32 @@ ..\packages\EasyModbusTCP.5.6.0\lib\net40\EasyModbus.dll - ..\packages\EgwProxy.Icoel.3.6.2205.2012\lib\EgwProxy.Icoel.dll + ..\packages\EgwProxy.Icoel.3.6.2206.2811\lib\EgwProxy.Icoel.dll + + + ..\packages\EgwProxy.Icoel.3.6.2206.2811\lib\EgwProxy.Icoel.DataLayer.dll - ..\packages\EgwProxy.MultiCncLib.3.6.2205.2012\lib\EgwProxy.MultiCncLib.dll + ..\packages\EgwProxy.MultiCncLib.3.6.2205.2319\lib\EgwProxy.MultiCncLib.dll - ..\packages\EgwProxy.OsaiCncLib.3.6.2205.2012\lib\EgwProxy.OsaiCncLib.dll + ..\packages\EgwProxy.OsaiCncLib.3.6.2205.2015\lib\EgwProxy.OsaiCncLib.dll - ..\packages\EgwProxy.OsaiCncLib.3.6.2205.2012\lib\EgwProxy.OsaiCncLib.XmlSerializers.dll + ..\packages\EgwProxy.OsaiCncLib.3.6.2205.2015\lib\EgwProxy.OsaiCncLib.XmlSerializers.dll + + + ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll + + + ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll False ExtLib\krcc.dll - - ..\packages\MapoSDK.6.14.2204.2616\lib\MapoSDK.dll + + ..\packages\MapoSDK.6.14.2206.2718\lib\MapoSDK.dll ..\packages\MathNet.Numerics.4.15.0\lib\net461\MathNet.Numerics.dll @@ -144,6 +154,7 @@ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + @@ -196,6 +207,7 @@ + @@ -203,6 +215,7 @@ + @@ -272,6 +285,57 @@ Always + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Always + + + Always + + + Always + + + Always + + + PreserveNewest + @@ -310,6 +374,21 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Always @@ -445,9 +524,6 @@ Always - - Always - Always @@ -493,21 +569,12 @@ Always - - Always - - - Always - Always Always - - Always - Always @@ -911,9 +978,12 @@ + + + \ No newline at end of file diff --git a/IOB-WIN-NEXT/IobConfiguration.cs b/IOB-WIN-NEXT/IobConfiguration.cs index 98af38be..b29b8739 100644 --- a/IOB-WIN-NEXT/IobConfiguration.cs +++ b/IOB-WIN-NEXT/IobConfiguration.cs @@ -147,7 +147,7 @@ namespace IOB_WIN_NEXT /// Comando x reboot /// Comando x check data avvio ODL /// Comando x forzare split ODL - public serverMapo(string MPIP_, string MPURL_ = "/MP/IO", string CMDBASE_ = "/IOB/input/", string CMDFLOG_ = "/IOB/flog/", string CMDULOG_ = "/IOB/ulog/", string CMDALIVE_ = "IOB", string CMDENABLED_ = "/IOB/enabled/", string CMDREBO_ = "/sendReboot.aspx?idxMacchina=", string CMD_ODL_STARTED_ = "/IOB/getCurrOdlStart/", string CLI_INST_ = "SteamWare", string CMD_FORCLE_SPLIT_ODL_ = "/IOB/forceSplitOdlFull/", string CMD_IDLE_TIME_ = "/IOB/getIdlePeriod/") + public serverMapo(string MPIP_, string MPURL_ = "/MP/IO", string CMDBASE_ = "/IOB/input/", string CMDFLOG_ = "/IOB/flog/", string CMDULOG_ = "/IOB/ulog/", string CMDALIVE_ = "IOB", string CMDENABLED_ = "/IOB/enabled/", string CMDREBO_ = "/sendReboot.aspx?idxMacchina=", string CMD_ODL_STARTED_ = "/IOB/getCurrOdlStart/", string CLI_INST_ = "SteamWare", string CMD_FORCLE_SPLIT_ODL_ = "/IOB/forceSplitOdlFull/", string CMD_IDLE_TIME_ = "/IOB/getIdlePeriod/", string CMDRAWTRANSFJSON_ = "/IOB/rawTransfJson/") { if (!string.IsNullOrEmpty(MPIP_)) { @@ -160,6 +160,7 @@ namespace IOB_WIN_NEXT MPURL = MPURL_; CMDBASE = CMDBASE_; CMDFLOG = CMDFLOG_; + CMDRAWTRANSF_JSON = CMDRAWTRANSFJSON_; CMDULOG = CMDULOG_; if (!string.IsNullOrEmpty(CMDBASE_)) { @@ -241,6 +242,11 @@ namespace IOB_WIN_NEXT ///
public string CMDULOG { get; set; } = ""; + /// + /// comando base x Raw Transf LOG - salvataggio valori generici in modalità JSON payload come lista + /// + public string CMDRAWTRANSF_JSON { get; set; } = ""; + /// /// comando base x USER LOG - salvataggio parametri extra sistema MAPO in modalità JSON payload come lista /// diff --git a/IOB-WIN-NEXT/IobFanuc.cs b/IOB-WIN-NEXT/IobFanuc.cs index 8a171a92..d3657864 100644 --- a/IOB-WIN-NEXT/IobFanuc.cs +++ b/IOB-WIN-NEXT/IobFanuc.cs @@ -212,7 +212,7 @@ namespace IOB_WIN_NEXT } catch (Exception exc) { - lgError(exc, "Errore in contapezzi FANUC"); + lgError(exc, "Errore in contapezzi FANUC 01"); } } // finisco INIT ADAPTER @@ -587,6 +587,23 @@ namespace IOB_WIN_NEXT // salvo valore answ = outputVal.ToString(); } + // 2022.05.23 gestione MACRO da testare (Jetco) + else if (memAddr.StartsWith("MACRO.")) + { + lgTrace($"Decodifica memoria MACRO | memAddr: {memAddr}"); + // recupero parametro... + int.TryParse(memAddr.Replace("MACRO.", ""), out cntAddr); + // processo parametro + stopwatch.Restart(); + double macroVal = 0; + FANUC_ref.F_Read_macro(cntAddr, ref macroVal); + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-MACRO", 5), stopwatch.ElapsedTicks); + } + // salvo valore + answ = macroVal.ToString(); + } // altrimenti se legge da area memoria specifica leggo da li... formto tipo STD.D.1604.DW else { @@ -1012,7 +1029,6 @@ namespace IOB_WIN_NEXT { cntAddr = 6711; } - // processo parametro contapezzi (lavorati) stopwatch.Restart(); FANUC_ref.F_RW_Param_Integer(false, cntAddr, 3, ref outputVal); @@ -1020,22 +1036,38 @@ namespace IOB_WIN_NEXT { TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-PAR", 4), stopwatch.ElapsedTicks); } - // salvo ultimo conteggio rilevato int newVal = -1; Int32.TryParse(outputVal.ToString(), out newVal); contapezziPLC = newVal > -1 ? newVal : contapezziPLC; } + // 2022.05.23 gestione MACRO da testare (Jetco) + else if (memAddr.StartsWith("MACRO.")) + { + lgTrace($"Decodifica memoria MACRO | memAddr: {memAddr}"); + // recupero parametro... + int.TryParse(memAddr.Replace("MACRO.", ""), out cntAddr); + // processo parametro + stopwatch.Restart(); + double macroVal = 0; + FANUC_ref.F_Read_macro(cntAddr, ref macroVal); + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-MACRO", 5), stopwatch.ElapsedTicks); + } + // salvo ultimo conteggio rilevato + int newVal = -1; + Int32.TryParse($"{macroVal}", out newVal); + contapezziPLC = newVal > -1 ? newVal : contapezziPLC; + } // altrimenti se legge da area memoria specifica leggo da li... formto tipo STD.D.1604.DW else { memAddressFanuc areaCounter = new memAddressFanuc(memAddr); - if (isVerboseLog) { lgInfo("[0] area memoria: {0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType); } - // leggo! stopwatch.Restart(); // switch x tipo dati --> tipo lettura... e salvo ultimo conteggio rilevato @@ -1076,7 +1108,6 @@ namespace IOB_WIN_NEXT { TimingData.addResult(cIobConf.codIOB, string.Format("R-{0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType), stopwatch.ElapsedTicks); } - // salvo... int newVal = -1; Int32.TryParse(outputVal.ToString(), out newVal); @@ -1093,7 +1124,7 @@ namespace IOB_WIN_NEXT } catch (Exception exc) { - lgError(exc, "Errore in contapezzi FANUC"); + lgError(exc, "Errore in contapezzi FANUC 02"); connectionOk = false; } } diff --git a/IOB-WIN-NEXT/IobGeneric.cs b/IOB-WIN-NEXT/IobGeneric.cs index 743edaa8..a662ab24 100644 --- a/IOB-WIN-NEXT/IobGeneric.cs +++ b/IOB-WIN-NEXT/IobGeneric.cs @@ -22,173 +22,6 @@ namespace IOB_WIN_NEXT { public class IobGeneric { - #region Protected Fields - - /// - /// wrapper di log - /// - protected static Logger lg; - - protected bool _connOk = false; - - /// - /// valore booleano di check se sia in fase di COMUNICAZIONE ATTIVA con il PLC/NC - /// - protected bool adpCommAct; - - /// - /// porta x adapter (x restart) - /// - protected int adpPortNum; - - /// - /// DataOra ultimo avvio adapter x watchdog - /// - protected DateTime adpStartRun; - - /// - /// Vettore 32 BIT valori in ingresso al filtro - /// - protected int B_input; - - /// - /// Vettore 32 BIT valori in uscita dal filtro - /// - protected int B_output; - - /// - /// Vettore 32 BIT valori precedenti - /// - protected int B_previous; - - /// - /// Num errori check alive - /// - protected int currAliveErrors = 0; - - /// - /// Variabile numero errori vari (in lettura) --> se supera soglia maxErroriCheck --> disconnette - /// - protected int numErroriCheck = 0; - - /// - /// Soglia massima errori priam di disconnesisone automatica - /// - protected int maxErroriCheck = 100; - - /// - /// Dizionario valori impostati x produzione - /// - protected Dictionary currProdData = new Dictionary(); - - /// - /// num corrente errori read PLC - /// - protected int currReadErrors = 0; - - /// - /// num errori send - /// - protected int currSendErrors = 0; - - /// - /// Periodo wathdog di default (2 sec se non specificato) - /// - protected int watchDogPeriod = 2; - - /// - /// Array dei contatori x segnali blinking - /// - protected int[] i_counters; - - /// - /// Indica impianto IN SETUP (fino a quando SMETTE di esserlo...) - /// - protected bool inSetup = false; - - /// - /// ultimo tentativo connessione... - /// - protected DateTime lastConnectTry; - - /// - /// Dizionario ULTIMI valori impostati x produzione - /// - protected Dictionary lastProdData = new Dictionary(); - - /// - /// Ultimo invio contapezzi (x invio delayed) - /// - protected DateTime lastPzCountSend; - - - /// - /// Ultimo LOG registrazione avvio (x ridurre log notturni...) - /// - protected DateTime lastLogStartup = DateTime.Today.AddHours(-1); - - /// - /// Veto per registrazione completa log di startup (minuti) - /// - protected int vetoLogStartupDuration = 60; - - /// - /// Dizionario ultimi valori (double) delle TSVC - /// - protected Dictionary LastTSVC = new Dictionary(); - - /// - /// Ultima registrazione warning x ODL mancante (x scrivere solo ogni 15 secondi) - /// - protected DateTime lastWarnODL; - - /// - /// Num massimo di errori in funzionalità check alive - /// - protected int maxAliveErrors = utils.CRI("maxAliveErrors"); - - /// - /// Num massimo di errori di rete read (dal PLC) - /// - protected int maxReadErrors = utils.CRI("maxReadErrors"); - - /// - /// Num massimodi errori di rete send al server - /// - protected int maxSendErrors = utils.CRI("maxSendErrors"); - - /// - /// indica se serva refresh parametri e quindi PLC... - /// - protected bool needRefresh = true; - - /// - /// Form chiamante - /// - protected AdapterForm parentForm; - - /// - /// Timeout x ping al server - /// - protected int pingServerMsTimeout = utils.CRI("pingMsTimeout"); - - /// - /// Ritardo minimo x invio contapezzi - /// - protected int pzCountDelay; - - /// - /// Dizionario di VC da trattare come TimeSeries (con conf decodificata + processing successivo...) - /// - protected Dictionary TSVC_Data = new Dictionary(); - - /// - /// Dizionario di VARIABILI da trattare come eventi (da inviare quando cambiano oppure a scadenza periodo...) - /// - protected Dictionary VarArray = new Dictionary(); - - #endregion Protected Fields - #region Public Fields /// @@ -196,11 +29,6 @@ namespace IOB_WIN_NEXT /// public bool adpRunning = false; - /// - /// Valore di attesa (random) dopo ogni invio x evitare congestione send... - /// - protected static int urlRandWait = 0; - /// /// valore booleano di check se l'adapter STIA SALVANDO /// @@ -309,7 +137,7 @@ namespace IOB_WIN_NEXT /// /// dataOra ultimo PING inviato verso il PLC... /// - public DateTime lastPING; + public DateTime lastPING = DateTime.Now.AddHours(-1); /// /// DataOra ultima lettura da PLC @@ -362,7 +190,8 @@ namespace IOB_WIN_NEXT public Dictionary persistenceLayer; /// - /// Determina se utilizzare blocchi di memoria IOT contigui (e quindi processing "monoblocco" semplificato"= + /// Determina se utilizzare blocchi di memoria IOT contigui (e quindi processing + /// "monoblocco" semplificato"= /// public bool procIotMem = false; @@ -387,7 +216,7 @@ namespace IOB_WIN_NEXT public ConcurrentQueue QueueMessages = new ConcurrentQueue(); /// - /// Oggetto della coda degli elementi di tipo RawTransf (e non ancora trasmessi) + /// Oggetto della coda degli elementi di tipo RawTransf (e non ancora trasmessi) /// NB: sono salvati serializzati come stringhe /// public ConcurrentQueue QueueRawTransf = new ConcurrentQueue(); @@ -497,383 +326,6 @@ namespace IOB_WIN_NEXT #endregion Public Events - #region Private Properties - - /// - /// Verifica se la IOB sia ENABLED (da server o Demo) - /// - private bool checkIobEnabled - { - get - { - bool answ = false; - // controllo se ho veto al check... - if (dtVetoCheckIOB < DateTime.Now) - { - if (DemoOut) - { - answ = (QueueIN.Count + QueueFLog.Count >= nMaxSend); - IobOnline = answ; - } - else - { - try - { - // chiamo URL, se restituisce "OK" è enabled! - string callResp = callUrl(urlIobEnabled, true); - answ = (callResp == "OK"); - // attesa casuale se necessario - var rand = new Random(); - // primi 2 test - int maxTry = 2; - while (maxTry > 0 && !answ) - { - Thread.Sleep(rand.Next(250, 500)); - callResp = callUrl(urlIobEnabled, true); - answ = (callResp == "OK"); - maxTry--; - } - // se NON OK riprovo ANCORA 1 volta... - if (!answ) - { - resetWebClients(); - Thread.Sleep(rand.Next(250, 1000)); - callResp = callUrl(urlIobEnabled, false); - answ = (callResp == "OK"); - } - // altri 2 - maxTry = 2; - while (maxTry > 0 && !answ) - { - Thread.Sleep(rand.Next(250, 500)); - callResp = callUrl(urlIobEnabled, false); - answ = (callResp == "OK"); - maxTry--; - } - // salvo status... - IobOnline = answ; - // se online imposto veto check a 5 x tempo reinvio... - if (answ) - { - lastIobOnline = DateTime.Now; - } - dtVetoCheckIOB = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 5); - } - catch - { } - } - // verifico SE è variato stato online/offline... - if (IobOnline != answ) - { - // se ORA sono online riporto... - if (answ) - { - lgInfo("IOB ONLINE for server MP/IO"); - } - else - { - lgInfo("IOB OFFLINE for server MP/IO"); - } - } - // fix colore - if (answ) - { - parentForm.commSrvActive = 2; - } - else - { - parentForm.commSrvActive = 1; - } - } - else - { - // altrimenti passo ultimo valore noto - answ = IobOnline; - } - return answ; - } - } - - /// - /// test ping all'indirizzo impostato nei parametri - /// - /// - private IPStatus testPingServer - { - get - { - IPStatus answ = IPStatus.Unknown; - // se disabilitato salto... - if (pingDisabled) - { - answ = IPStatus.Success; - } - else - { - IPAddress address; - PingReply reply; - var rand = new Random(); - int pingTOut = 500; - using (Ping pingSender = new Ping()) - { - address = IPAddress.Loopback; - int maxRetry = maxPingRetry + 1; - int numRetry = 1; - string ipAddr = cIobConf.serverData.MPIP.Replace($"{cIobConf.serverData.TRANSP}://", ""); - // fix se fosse ip + porta... - if (ipAddr.IndexOf(":") >= 0) - { - ipAddr = ipAddr.Substring(0, ipAddr.IndexOf(":")); - } - IPAddress.TryParse(ipAddr, out address); - // se null --> provo DNS... - if (address == null) - { - var rawAddresses = Dns.GetHostAddresses(ipAddr); - if (rawAddresses.Length > 0) - { - address = rawAddresses[0]; - } - } - try - { - // se != null --> uso address... - if (address != null) - { - pingTOut = rand.Next(200, 400); - reply = pingSender.Send(address, pingTOut); - } - else - { - pingTOut = rand.Next(300, 600); - reply = pingSender.Send(cIobConf.cncIpAddr, pingTOut); - } - } - catch (Exception exc) - { - pingTOut = rand.Next(100, 200); - reply = pingSender.Send(IPAddress.Loopback, pingTOut); - lgError($"ping to loopback addres per eccezione:{Environment.NewLine}{exc}"); - } - // se ho timeout riprovo... - while (reply.Status != IPStatus.Success && numRetry < maxRetry) - { - Thread.Sleep(rand.Next(50, 200)); - pingTOut = pingServerMsTimeout * numRetry / 2; - reply = pingSender.Send(address, pingTOut); - numRetry++; - if (reply.Status == IPStatus.Success) - { - lgInfo("Server PING OK!"); - break; - } - else - { - lgInfo($"Server Ping KO | reply: {reply.Status} --> retry | TimeOut: {pingTOut}"); - } - } - } - answ = reply.Status; - } - return answ; - } - } - - #endregion Private Properties - - #region Protected Properties - - /// - /// Valore del num max invii consecutivi da coda... - /// - protected static int nMaxSend - { - get - { - int answ = 5; - try - { - answ = utils.CRI("nMaxSend"); - } - catch - { } - return answ; - } - } - - /// - /// Indica il counter della key richiesta attiva - /// - gestito tramite Redis - /// - a scadenza 25h - /// - incrementato ogni invio di auto ODL - /// - protected int countKeyRichiesta - { - get - { - // calcolo key odierna - int answ = redisMan.getKReqCount(dailyKey); - return answ; - } - set - { - // calcolo key odierna - redisMan.setKReqCount(dailyKey, value); - } - } - - protected string dailyKey - { - get - { - return DateTime.Today.ToString("yyMMdd"); - } - } - - /// - /// Variabile di appoggio GLOBALE x indicare che si può forzare reset contapezzi con macchina in RUN - /// - protected bool forceResetInRun { get; set; } = false; - - /// - /// Variabile di appoggio GLOBALE x indicare macchina RUN (es x gestione su reset pezzi) - /// - protected bool isRunning { get; set; } = false; - - /// - /// Valore limite MASSIMO di invio di dati come array Json - /// - protected int maxJsonData { get; set; } = utils.CRI("maxJsonData"); - - /// - /// Valore limite MASSIMO di invio di dati come array Json x EVENTI - /// - protected int maxJsonDataEv { get; set; } = utils.CRI("maxJsonDataEv"); - - /// - /// Max tentativi ping permessi (default: 5) - /// - protected int maxPingRetry { get; set; } = 5; - - /// - /// Coda massima ammessa per FLog (se <=0 disattivata...) - /// - protected int maxQueueFLog { get; set; } = utils.CRI("maxQueueFLog"); - - /// - /// Valore MINIMO limite x decidere invio di dati come array Json - /// - protected int minJsonData { get; set; } = utils.CRI("minJsonData"); - - protected string nextKeyRich - { - get - { - return $"{dailyKey}{countKeyRichiesta:00}"; - } - } - - /// - /// Numero letture IN da avvio - /// - protected int nReadFilt { get; set; } - - /// - /// Numero letture IN da avvio - /// - protected int nReadIN { get; set; } - - /// - /// Numero invii OUT (svuotamento coda) - /// - protected int nSendOut { get; set; } - - /// - /// Numero simulazioni ammesse... - /// - protected int numSim { get; set; } - - /// - /// Indica se sia stato resettato un contapezzi - /// - protected bool pzCountResetted { get; set; } = false; - - /// - /// Fornisce il valore letto da BITMAP in formato valido x messa in coda nel formato dtEve#value#cont - /// - protected string qEncodeIN - { - get - { - string answ = ""; - try - { - answ = string.Format("{0:yyyyMMddHHmmssfff}#{1:X2}#{2}", DateTime.Now, B_output, counterSigIN); - } - catch - { } - return answ; - } - } - - /// - /// Indica se vada inviata la key richiesta con lo split/autoODL - /// - protected bool sendKeyRichiesta { get; set; } = false; - - /// - /// test ping all'indirizzo PLC/CNC impostato nei parametri - /// - /// - protected IPStatus testPingMachine - { - get - { - IPStatus answ = IPStatus.Unknown; - // se disabilitato salto... - if (pingDisabled) - { - answ = IPStatus.Success; - } - else - { - IPAddress address; - PingReply reply; - using (Ping pingSender = new Ping()) - { - address = IPAddress.Loopback; - int pingMsTimeout = cIobConf.pingMsTimeout; - IPAddress.TryParse(cIobConf.cncIpAddr, out address); - try - { - // se != null --> uso address... - if (address != null) - { - reply = pingSender.Send(address, pingMsTimeout); - } - else - { - reply = pingSender.Send(cIobConf.cncIpAddr, pingMsTimeout); - } - } - catch - { - reply = pingSender.Send(IPAddress.Loopback, pingMsTimeout); - } - answ = reply.Status; - } - } - return answ; - } - } - - /// - /// Secondi standard x veto check status e log - /// - protected int vetoSeconds { get; set; } = utils.CRI("vetoSeconds"); - - #endregion Protected Properties - #region Public Properties /// @@ -1108,6 +560,11 @@ namespace IOB_WIN_NEXT /// public int counterFLog { get; set; } + /// + /// Contatore x invio dati RawTransf + /// + public int counterRawTransf { get; set; } + /// /// Contatore x invio dati SignalIN /// @@ -1119,7 +576,7 @@ namespace IOB_WIN_NEXT public int counterULog { get; set; } /// - /// Verifica se sia in modalità DEMO --> da tipo IOB SIMULA... + /// Verifica se sia in modalità DEMO --> da tipo IOB SIMULA... /// public bool DemoIn { @@ -1218,7 +675,8 @@ namespace IOB_WIN_NEXT public string lastUrl { get; set; } /// - /// Valore massimo accettato x incremento pezzi letti dal PLC (valore moltiplicato per 100... 200% --> 200) + /// Valore massimo accettato x incremento pezzi letti dal PLC (valore moltiplicato per + /// 100... 200% --> 200) /// public int maxPzDeltaPerc { @@ -1713,751 +1171,2978 @@ namespace IOB_WIN_NEXT #endregion Public Properties - #region Private Methods + #region Public Methods /// - /// Verifica e se necessario comprime directory log... + /// Effettua chiamata URL e restituisce risultato /// - private void checkShrinkDir() + /// + /// invio in modalità async (NON GARANTITO ordine...) + /// + public static string callUrl(string URL, bool doAsync) { - string path = string.Format("{0}logs\\{1}", AppDomain.CurrentDomain.BaseDirectory, cIobConf.codIOB); - baseUtils.shrinkDir(path); - } - - /// - /// Mostra i dati grezzi letti in esadecimale - /// Parametri da aggiornare x display in form - /// - private void displayRawData(ref newDisplayData currDispData) - { - // mostro update... - string newString = string.Format("{0:X}", B_input); - currDispData.newInData = newString; - } - - /// - /// Esegue filtraggio dati x bit blinking!!! - /// - private void filterData() - { - // effettuo filtraggio dei valori letti... inizializzo OUT! - B_output = 0; - // in primis verifico SE ci siano bit blinkng... se non ci sono OUT=IN... - if (cIobConf.BLINK_FILT == 0) + string answ = ""; + // Chiamata ASINCRONA + if (doAsync) { - B_output = B_input; + //Task resp = utils.callUrlAsync(URL); + //answ = resp.Result; + answ = utils.callUrlAsync(URL); + if (urlRandWait > 0) + { + Random rnd = new Random(); + Thread.Sleep(rnd.Next(urlRandWait / 10, urlRandWait)); + } + } + // chiamata SOLO NORMALE SINCRONA... + else + { + answ = utils.callUrl(URL); + if (urlRandWait > 0) + { + Random rnd = new Random(); + Thread.Sleep(rnd.Next(urlRandWait / 10, urlRandWait)); + } + } + return answ; + } + + /// + /// Effettua chiamata URL e restituisce risultato + /// + /// + /// + /// invio in modalità async (NON GARANTITO ordine...) + /// + public static string callUrlWithPayload(string URL, string payload, bool doAsync) + { + string answ = ""; + // Chiamata ASINCRONA + if (doAsync) + { + answ = utils.callUrlAsync(URL, payload); + if (urlRandWait > 0) + { + Random rnd = new Random(); + Thread.Sleep(rnd.Next(urlRandWait / 10, urlRandWait)); + } + } + // chiamata SOLO NORMALE SINCRONA... + else + { + answ = utils.callUrl(URL, payload); + if (urlRandWait > 0) + { + Random rnd = new Random(); + Thread.Sleep(rnd.Next(urlRandWait / 10, urlRandWait)); + } + } + return answ; + } + + /// + /// processa dataLayer e se necessario salva/mostra + /// + public static void checkSavePersDataLayer() + { + } + + public static string GetMACAddress() + { + NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); + String sMacAddress = string.Empty; + foreach (NetworkInterface adapter in nics) + { + if (string.IsNullOrEmpty(sMacAddress))// only return MAC Address from first card + { + IPInterfaceProperties properties = adapter.GetIPProperties(); + //sMacAddress = adapter.GetPhysicalAddress().ToString(); + sMacAddress = string.Join(":", (from z in adapter.GetPhysicalAddress().GetAddressBytes() select z.ToString("X2")).ToArray()); + } + } + return sMacAddress; + } + + public static void resetDebugConsole() + { + } + + /// + /// Reset dei webclients + /// + public static void resetWebClients() + { + utils.resetWebClients(); + } + + /// + /// Accumula in coda i valori ALARM e logga... + /// + /// VALORE RAW (x display) + /// VALORE già processato con qEncodeFLog(...) + public void accodaAlarmLog(string val, string encodedVal) + { + // mostro dati variati letti... + displayOtherData(val); + // accodo IN PRIMIS al FluxLog --> accodo (valore già formattato)! + QueueFLog.Enqueue(encodedVal); + // accodo ANCHE alla coda allarmi che trasmetterò SOLO SE a scadenza impostata (10 sec?) + // ho allarmi perdurati... + + // loggo! + lgInfo(string.Format("[QUEUE-ALARM-LOG] {0}", encodedVal)); + counterFLog++; + if (counterFLog > 9999) + { + counterFLog = 0; + } + } + + /// + /// Accumula in coda i valori Flux Log e logga... + /// + /// VALORE RAW (x display) + /// VALORE già processato con qEncodeFLog(...) + public void accodaFLog(string val, string encodedVal) + { + // mostro dati variati letti... + displayOtherData(val); + // --> accodo (valore già formattato)! + QueueFLog.Enqueue(encodedVal); + // se abilitato controllo coda FLog (superiore a 0...) + if (maxQueueFLog > 0) + { + // se ho una coda superiore a max ammesso + if (QueueFLog.Count > maxQueueFLog) + { + // elimino valori iniziali fino a tornare al max ammesso... + while (QueueFLog.Count > maxQueueFLog) + { + string currVal = ""; + QueueFLog.TryDequeue(out currVal); + lgInfo($"Eliminazione da coda FLog per superamento maxLengh: {currVal}"); + } + } + } + // loggo! + lgTrace(string.Format("[QUEUE-FLOG] {0}", encodedVal)); + counterFLog++; + if (counterFLog > 9999) + { + counterFLog = 0; + } + } + + /// + /// Accoda (visualizzando in cima allo stack) la nuova stringa di output per area OTHER DATA + /// + /// + public void accodaOtherData(string newLine) + { + // inserisco in cima allo stack, trimmo e aggiorno display + string strOtherData = limitLine2show(string.Format("{0}{1}{2}", newLine, Environment.NewLine, parentForm.dataMonitor_3)); + //parentForm.dataMonitor_3 = strOtherData; + parentForm.WriteTextSafe(strOtherData); + } + + /// + /// Accumula in coda i valori RawData + log + /// + /// + /// + public void accodaRawData(rawTransfType mesType, object mesContent) + { + /*-------------------------------- + * nuova gestione coda dictionary + * fixme todo da fare !!! + * + * - conterrà una lista di oggetti baseRawTransf + * - i dati vanno poi "scodati" dal + vecchio ed inviati a MP/IO + * - mostra un sunto delle info da inviare + * - accodamento vero e proprio + * - verifica (opzionale) coda massima x gestire roundRobin ultimi eventi + * - trace della coda + * - counter invio??? valutare se c'è dataora e poi sono da salvare su MongoDb / Redis + * + * */ + + // serializzo il valore... + BaseRawTransf newVal = new BaseRawTransf(DateTime.Now, mesContent, mesType); + string encodedVal = JsonConvert.SerializeObject(newVal); + // --> accodo (valore già formattato)! + QueueRawTransf.Enqueue(encodedVal); + // se abilitato controllo coda Max (superiore a 0...) + if (maxQueueRawTransf > 0) + { + // se ho una coda superiore a max ammesso + if (QueueRawTransf.Count > maxQueueRawTransf) + { + // elimino valori iniziali fino a tornare al max ammesso... + while (QueueRawTransf.Count > maxQueueRawTransf) + { + string currVal = ""; + QueueRawTransf.TryDequeue(out currVal); + lgInfo($"Eliminazione da coda RawTransf per superamento maxLengh: {currVal}"); + } + } + } + // loggo! + lgTrace(string.Format("[QUEUE-RTRANSF] {0}", encodedVal)); + counterRawTransf++; + if (counterRawTransf > 9999) + { + counterRawTransf = 0; + } + } + + /// + /// Accumula in coda i valori Signal IN e logga... Parametri + /// da aggiornare x display in form + /// + public void accodaSigIN(ref newDisplayData currDispData) + { + // mostro dati variati letti... + displayInData(ref currDispData); + // verifico veto a invio status macchina + string keyName = "VETO_SIG_IN"; + if (getOptPar(keyName).ToUpper() == "TRUE") + { + lgTrace($"Filtrato accodamento valore da conf IOB | {keyName} | [QUEUE-IN] {qEncodeIN}"); } else { - // incomincio con i valori NON blinking: questi "passano invariati", inizio a sommare nel valore OUT... - B_output = B_input & ~cIobConf.BLINK_FILT; - // calcolo il valore dei BIT che "passano la maschera" - int iBlink = B_input & cIobConf.BLINK_FILT; - // ...aggiungo i "bit che passano" - B_output += iBlink; + // --> accodo (valore già formattato)! + QueueIN.Enqueue(qEncodeIN); + // loggo! + lgTrace(string.Format("[QUEUE-IN] {0}", qEncodeIN)); + } + // aggiorno counters ed eventuale reset + nReadFilt++; + if (nReadFilt > int.MaxValue - 1) + { + nReadFilt = 0; // per evitare buffer overflow... + } - // calcolo QUALI valori (tra quelli blink) siano PASSATI da 0 a 1 --> init counters... - BitArray bBlinkStart = new BitArray(new byte[] { Convert.ToByte(iBlink) }); - int[] bitsUp = bBlinkStart.Cast().Select(bit => bit ? 1 : 0).ToArray(); - for (int i = 0; i < bitsUp.Length; i++) + counterSigIN++; + if (counterSigIN > 9999) + { + counterSigIN = 0; + } + } + + /// + /// Accumula in coda i valori USER LOG e logga... + /// + /// VALORE RAW (x display) + /// VALORE già processato con qEncodeULog(...) + public void accodaUserLog(string val, string encodedVal) + { + // mostro dati variati letti... + displayOtherData(val); + // accodo IN PRIMIS al FluxLog --> accodo (valore già formattato)! + QueueULog.Enqueue(encodedVal); + + // loggo! + lgInfo(string.Format("[QUEUE-USER-LOG] {0}", encodedVal)); + counterULog++; + if (counterULog > 9999) + { + counterFLog = 0; + } + } + + /// + /// Update visualizzaizone BIT in ingresso Parametri da + /// aggiornare x display in form + /// + public void displayInData(ref newDisplayData currDispData) + { + if (currDispData != null) + { + // mostro update... + string newString = string.Format("{0:0000}|{1}", counterSigIN, utils.IntToBinStr(B_output, 8)); + currDispData.newSignalData = newString; + } + } + + /// + /// Mostra cosa ha/avrebbe inviato + /// + /// + public void displayOtherData(string newData) + { + // mostro update... + accodaOtherData(newData); + } + + /// + /// Esecuzione dei task richiesti e pulizia coda richieste eseguite + /// + /// + public virtual Dictionary executeTasks(Dictionary task2exe) + { + // Verificare il protocollo: dovrebbe togliere SOLO i task eseguiti... + Dictionary taskDone = new Dictionary(); + if (task2exe != null) + { + // controllo se memMap != null... + if (memMap != null) { - // SE 1... impostiamo contatori al MAX - if (bitsUp[i] == 1) + bool taskOk = false; + string taskVal = ""; + // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4 + foreach (var item in task2exe) { - // se era zero indico START blink... - if (i_counters[i] == 0) + taskOk = false; + taskVal = ""; + // converto richiesta in enum... + taskType tName = taskType.nihil; + Enum.TryParse(item.Key, out tName); + // controllo sulla KEY... + switch (tName) { - lgTrace("START BLINK: B{0}", i); + case taskType.setArt: + case taskType.setComm: + case taskType.setProg: + case taskType.setPzComm: + // recupero dati da memMap... + if (memMap != null && memMap.mMapWrite != null) + { + if (memMap.mMapWrite.ContainsKey(item.Key)) + { + dataConf currMem = memMap.mMapWrite[item.Key]; + string addr = currMem.memAddr; + taskVal = $"SET task: {item.Key} --> {item.Value} | mem: {currMem.memAddr} - {currMem.size} byte"; + // salvo il nuovo valore nella memoria... così prox invio lo trasmetterà + memMap.mMapWrite[item.Key].value = item.Value; + } + else + { + taskVal = $"NO DATA MEM, SET task: {item.Key} --> {item.Value}"; + } + } + else + { + taskVal = $"NO MemMap found, SET task: {item.Key} --> {item.Value}"; + } + // salvo in currProd.. + saveProdData(new KeyValuePair(item.Key, item.Value)); + + break; + + case taskType.forceResetPzCount: + // reset contapezzi inizio setup + taskOk = resetcontapezziPLC(); + taskVal = taskOk ? "RESET PZ COUNT OK" : "PZ RESET DISABLED | NO EXEC"; + lgInfo($"Chiamata forceResetPzCount: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + + case taskType.startSetup: + // reset contapezzi inizio setup + taskOk = resetcontapezziPLC(); + taskVal = taskOk ? "RESET: SETUP START" : "PZ RESET DISABLED | NO EXEC"; + lgInfo($"Chiamata startSetup: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + + case taskType.stopSetup: + // reset contapezzi fine setup SE ESPLICITAMENTE IMPOSTATO + if (cIobConf.optPar.Count > 0 && getOptPar("ENABLE_PZ_RESET_stopSetup") == "TRUE") + { + taskOk = resetcontapezziPLC(); + } + taskVal = taskOk ? "RESET: SETUP END" : "PZ RESET DISABLED | NO EXEC"; + lgInfo($"Chiamata stopSetup: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + + case taskType.setParameter: + // richiedo da URL i parametri WRITE da popolare + lgInfo("Chiamata setParameter --> processMemWriteRequests"); + taskVal = processMemWriteRequests(); + // se restituiscce "" faccio altra prova... + if (string.IsNullOrEmpty(taskVal)) + { + // i parametri me li aspetto come stringa composta paramName|paramvalue + if (item.Value.Contains("|")) + { + string[] paramsJob = item.Value.Split('|'); + taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}"; + } + else + { + taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value"; + } + } + break; + + default: + taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; + lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); + break; } - // imposto comunque contatore al cambio fronte... - i_counters[i] = cIobConf.MAX_COUNTER_BLINK; + // aggiungo task! + taskDone.Add(item.Key, taskVal); } } - - // quelli che sono zero... LI RECUPERO E LI PROCESSO... - int iZero = ~B_input & cIobConf.BLINK_FILT; - BitArray bBlinkEnd = new BitArray(new byte[] { Convert.ToByte(iZero) }); - int[] bitsDown = bBlinkEnd.Cast().Select(bit => bit ? 1 : 0).ToArray(); - for (int i = 0; i < bitsDown.Length; i++) + else { - // se era a zero (invertito...) - if (bitsDown[i] == 1) + lgError($"Attenzione! memMap è nullo, non posso eseguire task2exe!"); + } + } + + return taskDone; + } + + /// + /// Effettua verifica delle memorie WRITE, se ci siano variazioni da riportare verso il PLC + /// Da impiegare ad esempio in caso di chiamate complesse (ad 2 aree di memoria condivise + /// sul PLC; coem commessa + articolo EWON) + /// + /// + /// Cerca parametri opzionali in modalità "like" del nome + /// + /// + /// + public Dictionary findOptPar(string keyStartSearch = "") + { + Dictionary answ = new Dictionary(); + // controllo SE keySearch !="" + if (!string.IsNullOrWhiteSpace(keyStartSearch)) + { + if (cIobConf.optPar.Count > 0) + { + // ciclo su tutti e cerco occorrenze che INIZINO... + foreach (var item in cIobConf.optPar) { - // SE è in corso il conteggio... - if (i_counters[i] > 0) + if (item.Key.StartsWith(keyStartSearch)) { - // decremento! - i_counters[i] -= 1; - // se è zero NON faccio nulla, altrimenti SOMMO... - if (i_counters[i] > 0) - { - B_output += 1 << i; - } - else - { - lgTrace("END BLINK: B{0}", i); - } + answ.Add(item.Key, item.Value); } } } } + return answ; } /// - /// Imposta eventuali altri valori default + /// forza reset ODL /// - private void fixDefaultPar() + public void forceResetOdl() { - // parametro max tentativi PING... - string s_maxPingRetry = getOptPar("MAX_PING_RETRY"); - if (!string.IsNullOrEmpty(s_maxPingRetry)) - { - int numRetry = 5; - int.TryParse(s_maxPingRetry, out numRetry); - maxPingRetry = numRetry; - } - - string s_maxErrCheck = getOptPar("MAX_ERR_CHECK"); - if (!string.IsNullOrEmpty(s_maxErrCheck)) - { - int numErr = 50; - int.TryParse(s_maxErrCheck, out numErr); - maxErroriCheck = numErr; - } - - string s_watchDogPer = getOptPar("WATCHDOG_PERIOD"); - if (!string.IsNullOrEmpty(s_watchDogPer)) - { - int numPer = 3; - int.TryParse(s_watchDogPer, out numPer); - watchDogPeriod = numPer; - } + lgInfo("Registrato richiesta forzatura reset ODL"); + pzCountResetted = true; } /// - /// recupera valore salvato in persistence layer (se non c'è crea...) + /// Effettua chiamata x split ODL /// - /// /// - private string getStoredVal(string keyVal) + public bool forceSplitOdl() { - string value = ""; - try + bool fatto = false; + if (vetoSplit < DateTime.Now) { - if (persistenceLayer != null) + lgInfo("Richiesto forceSplitOdl"); + // imposto veto x 1 minuto ad altre chiamate... + vetoSplit = DateTime.Now.AddMinutes(1); + // eseguo SOLO SE sono online... + if (MPOnline && IobOnline) { - if (!persistenceLayer.TryGetValue(keyVal, out value)) + string fullUrl = ""; + string rawSplit = ""; + string IOB_MULTI_CNAME = ""; + string[] elencoMulti = null; + + try { - persistenceLayer.Add(keyVal, "0"); + /*************************************************** + * Descrizione procedura (OK X SIMULATORI...) + * + * - chiamata su MP/IO + * - verifica che su DB sia abilitato AUTO ODL + * - il server inserisce un evento fine prod HW 1 minuto prima e inizio setup HW + * - viene duplicato e chiuso ODL corrente + * - viene fatto partire ODL nuovo ADESSO + * - num pezzi come ODL precedente (o da media 3 ODL precedenti) + * - conferme pezzi & co... gestione NULL (NON SERVONO si tratta di impianti SENZA gestione vera ODL) + * - reset contapezzi PLC locale... + * + * + * + * DA VALUTARE (x macchine tipo linea con + impianti... es valvital) SE + * - creare una gestione ALTERNATIVA sul server che preveda impianto LEADER e impianti follower (RIGIDAMENTE CONFIGURATI) + * - ogni volta che si fa setup LEADER --> si ripete su impianti FOLLOWER (eventi!!!) + * - viene fatto reset contapezzi sui follower (+ altre operazioni opzionali, ES imposstazione nome commessa, quantità, articolo...) + * - viene fatto reset + nuovo ODL (con stessi articoli e quantità) su follower, SENZA avere gestione x ODL di un codice esterno (quindi registra TUTTO ma NON RITORNERA' dati non avendo link verso esterno) + * - serve NUOVA TABELLA delle macchine LEADER | FOLLOWER (1:n) e gestione da MP/IO + * + * ***************************************************/ + + if (isMulti) + { + // devo chiamare cambio ODL x OGNI tavola: mi servono i parametri opzionali... + IOB_MULTI_CNAME = getOptPar("IOB_MULTI_CNAME"); + elencoMulti = IOB_MULTI_CNAME.Split(','); + } + // se normale splitto! + if (!isMulti) + { + // invio chiamata URL x reset ODL su macchina + rawSplit = callUrl(urlForceSplit, false); + fatto = (rawSplit != "KO") ? true : false; + } + // se multi gestisco il bit delle tavole... + else + { + foreach (string item in elencoMulti) + { + // invio chiamata URL x reset ODL su macchina, ATTENZIONE scriviamo + // | al posto di "#" che in URL sarebbe filtrato... + fullUrl = $"{urlForceSplit}&multi={item}"; + rawSplit = callUrl(fullUrl, false); + lgDebug($"Esecuzione forceSplit | URL: {fullUrl} | esito: {rawSplit}"); + } + fatto = (rawSplit == "OK") ? true : false; + } + } + catch (Exception exc) + { + lgError($"Eccezione in forceSplitOdl{Environment.NewLine}{exc}"); + } + // se fatto --> resetto contapezzi!!! + if (fatto) + { + contapezziPLC = 0; + contapezziIOB = 0; } } + else + { + lgError("Richiesto forceSplitOdl ma MP/IOB offline --> NON eseguito"); + } } - catch (Exception exc) + else { - lgError(string.Format("Eccezione in getStoredVal: {0}{1}", Environment.NewLine, exc)); + lgError("Richiesto forceSplitOdl ma veto attivo --> NON eseguito"); } - return value; + return fatto; } /// - /// recupera valore salvato in persistence layer (se non c'è crea...) come double + /// Effettua conversione da valore bitmap ai valori configurati x allarme /// - /// + /// Configurazione banco allarmi + /// BitState allarmi /// - private double getStoredValDouble(string keyVal) + public string getAlarmState(BaseAlarmConf memConf, byte[] bState) { - double answ = 0; - try + string valTransl = ""; + List descAttivi = new List(); + BitArray bitAttivi = new BitArray(bState); + bool[] bitStati = new bool[bitAttivi.Count]; + bitAttivi.CopyTo(bitStati, 0); + // cerco bit attivi + int idx = 0; + foreach (var item in bitStati) { - answ = Convert.ToDouble(getStoredVal(keyVal)); + if (item && memConf.messages.Count > idx) + { + string currState = memConf.messages[idx]; + descAttivi.Add(currState); + } + idx++; } - catch (Exception exc) - { - lgError(string.Format("Eccezione in getStoredValDouble: {0}{1}", Environment.NewLine, exc)); - } - answ = (answ < (double.MaxValue / 10 * 9)) ? answ : 0; - return answ; + // combino string + valTransl = string.Join(",", descAttivi); + return valTransl; } /// - /// recupera valore salvato in persistence layer (se non c'è crea...) come INT + /// effettua recupero dati ed invio valori modificati... /// - /// - /// - private long getStoredValLong(string keyVal) - { - long answ = 0; - try - { - answ = Convert.ToInt64(getStoredVal(keyVal)); - } - catch - { } - // verifico che il valore sia minore di 9/10 del valore massimo... - answ = (answ < (long.MaxValue / 10 * 9)) ? answ : 0; - return answ; - } - - /// - /// recupera valore salvato in persistence layer (se non c'è crea...) come UINT - /// - /// - /// - private uint getStoredValUInt(string keyVal) - { - uint answ = 0; - try - { - answ = Convert.ToUInt32(getStoredVal(keyVal)); - } - catch (Exception exc) - { - lgError(string.Format("Eccezione in getStoredValUInt: {0}{1}", Environment.NewLine, exc)); - } - // verifico che il valore sia minore di 9/10 del valore massimo... - answ = (answ < (uint.MaxValue / 10 * 9)) ? answ : 0; - return answ; - } - - /// - /// Classe fittizia in caso di processing GLOBALE di tutto in 1 solo colpo... - /// - private void processAllMemory() + /// + public void getAndSend(gatherCycle ciclo) { // init obj display newDisplayData currDispData = new newDisplayData(); - // in primis SALVO valori previous/precedenti - B_previous = B_output; - // poi faccio lettura NUOVI valori - readAllData(ref currDispData); - // eseguo il filtering dei valori (per i bit "blinking") - filterData(); - // effettuo confronto valori vecchi/nuovi... SE trovo variazione OPPURE se è passato + di un timeout di controllo... - if (B_output != B_previous) + // IN OGNI CASO a prima di tutto EFFETTUO GESTIONE INVII dati da code!!! + try { - accodaSigIN(ref currDispData); + trySendValues(); + } + catch (Exception exc) + { + lgError(exc, "Errore in gestione svuotamento/invio preliminare code memoria"); + currDispData.semOut = Semaforo.SR; + } + // controllo connessione/connettività + if (connectionOk) + { + // controllo non sia già in esecuzione... + if (!adpCommAct) + { + // provo ad avviare + try + { + // imposto flag adapter running.. + adpCommAct = true; + adpStartRun = DateTime.Now; + } + catch (Exception exc) + { + string errore = $"Adapter NOT STARTED!!!{Environment.NewLine}{exc}"; + adpCommAct = false; + adpStartRun = DateTime.Now; + currDispData.newLiveLogData = errore; + } + if (adpCommAct) + { + // try / catch generale altrimenti segno che è disconnesso... + try + { + bool showDebugData = false; + if (ciclo == gatherCycle.VHF) + { + processVHF(); + } + // processing dati memoria (lettura, filtraggio, enqueque) + else if (ciclo == gatherCycle.HF) + { + processWhatchDog(); + processAllMemory(); + processMode(); + } + else if (ciclo == gatherCycle.MF) + { + processServerRequests(); + processOverride(); + processContapezzi(); + processCncAlarms(); + processDynData(); + processMem2Write(); + } + else if (ciclo == gatherCycle.LF) + { + processCustomTaskLF(); + processOtherCounters(); + processProgram(); + // verifico se devo gestire cambio ODL in modo automatico + processAutoOdl(); + } + else if (ciclo == gatherCycle.VLF) + { + if (utils.CRB("enableContapezzi")) + { + // rilettura contapezzi da server... + lgTrace("Ciclo VLF: pzCntReload(true)"); + if (!isMulti) + { + pzCntReload(true); + } + // refresh associazione Macchina - IOB + sendM2IOB(); + } + // recupero dati SETUP (sysinfo) e li invio/mostro se variati... + processSysInfo(); + // checkLogDir x shrink! + checkShrinkDir(); + // eventuale log! + if (utils.CRB("recTime")) + { + logTimeResults(); + } + } + // mostra eventuali altri dati di processo... + reportDataProc(); + if (showDebugData) + { + // verifica se debba salvare e mostrare dati + checkSavePersDataLayer(); + } + } + catch (Exception exc) + { + // segnalo eccezione e indico disconnesso... + lgError(exc, string.Format("Errore in gestione ciclo principale ADP, fermo adapter{0}{1}", Environment.NewLine, exc)); + parentForm.fermaAdapter(true, false, true); + } + // tolgo flag running + adpCommAct = false; + } + else + { + if (periodicLog) + { + lgDebug("ADP not running..."); + } + } + } + else + { + // log ADP running + lgError("Non eseguo chiamata: ADP ancora in running"); + // se è bloccato da oltre maxSec lo sblocco... + if (DateTime.Now.Subtract(adpStartRun).TotalSeconds > utils.CRI("maxAdapterLockSec")) + { + // tolgo flag running + adpCommAct = false; + adpStartRun = DateTime.Now; + } + } + } + else + { + // provo a riconnettere SE abilitato tryRestart... + if (adpTryRestart && !connectionOk) + { + // controllo se sia scaduto periodi di veto al tryConnect... + int waitRecMSec = utils.CRI("waitRecMSec") * 2; + DateTime dtVeto = lastConnectTry.AddMilliseconds(waitRecMSec); + if (DateTime.Now > dtVeto) + { + lgInfo($"Veto Time Elapsed | lastConnectTry: {lastConnectTry} | waitRecMSec {waitRecMSec} ms) | NOW tryConnect"); + lastConnectTry = DateTime.Now; + tryConnect(); + } + } + currDispData.semIn = Semaforo.SR; + processDisconnectedTask(); } raiseRefresh(currDispData); } - private void processMem2Write() + /// + /// Effettua conversione da valore bitmap ai valori configurati + /// + /// + /// + /// + public string getBitmapState(dataConfTSVC memConf, byte[] bState) { - List updatedPar = new List(); - // ciclo tutti gli oggetti write x vedere se modificati... - foreach (var item in currProdData) + string valTransl = ""; + List descAttivi = new List(); + BitArray bitAttivi = new BitArray(bState); + bool[] bitStati = new bool[bitAttivi.Count]; + bitAttivi.CopyTo(bitStati, 0); + // cerco bit attivi + int idx = 0; + foreach (var item in bitStati) { - bool needWrite = false; - // li cerco su last... se non ci sono o modificati --> salvo da scrivere e copio - if (lastProdData.ContainsKey(item.Key)) + if (item && memConf.decodeMap.Count > idx) { - // verifico se variato... - if (!item.Value.Equals(lastProdData[item.Key])) - { - needWrite = true; - lastProdData[item.Key] = item.Value; - } + string currState = memConf.decodeMap[idx]; + descAttivi.Add(currState); } - // aggiungo - else + idx++; + } + // combino string + valTransl = string.Join(",", descAttivi); + return valTransl; + } + + /// + /// Recupera eventuali allarmi CNC... + /// + public virtual Dictionary getCncAlarms() + { + Dictionary outVal = new Dictionary(); + return outVal; + } + + /// + /// Restituisce info DINAMICHE + /// + /// + public virtual Dictionary getDynData() + { + Dictionary outVal = new Dictionary(); + return outVal; + } + + /// + /// Cerca se esiste il parametro opzionale e lo restituisce + /// + /// + /// + public string getOptPar(string key) + { + string answ = ""; + if (cIobConf.optPar.Count > 0) + { + // controllo SE HO il parametro + if (cIobConf.optPar.ContainsKey(key)) { - needWrite = true; - lastProdData.Add(item.Key, item.Value); - } - // se devo scrivere --> riporto - if (needWrite) - { - if (memMap.mMapWrite.ContainsKey(item.Key)) - { - // preparo obj da scrivere - objItem newWrite = new objItem() - { - uid = item.Key, - name = item.Key, - reqValue = memMap.mMapWrite[item.Key].value, - lastRequest = DateTime.Now, - writable = true - }; - updatedPar.Add(newWrite); - } + answ = cIobConf.optPar[key]; } } - // se ho da scrivere... scrivo TUTTI! - if (updatedPar.Count > 0) + return answ; + } + + /// + /// Restituisce info OVERRIDES + /// + /// + public virtual Dictionary getOverrides() + { + Dictionary outVal = new Dictionary(); + return outVal; + } + + /// + /// Restituisce programma in esecuzione + /// + public virtual string getPrgName() + { + return ""; + } + + /// + /// Restituisce info sistema + /// + /// + public virtual Dictionary getSysInfo() + { + Dictionary outVal = new Dictionary(); + return outVal; + } + + /// + /// Recupera la VC x TS, svuotando lista e resettando periodo partenza + /// + /// Nome della VC + /// Reimposta e resetta array VC + /// + public double getVal_TSVC(string VCName, bool doReset) + { + double answ = -999999; + // cerco VC... + if (TSVC_Data.ContainsKey(VCName)) { - // scrivo valore! - lgInfo("Chiamata di plcWriteParams da processMem2Write"); - plcWriteParams(ref updatedPar); - // invio su cloud parametri! - string rawData = JsonConvert.SerializeObject(updatedPar); - utils.callUrl($"{urlUpdateWriteParams}", rawData); - lgInfo($"Notificato a server scrittura {updatedPar.Count} parametri"); + try + { + switch (TSVC_Data[VCName].Funzione) + { + case VC_func.POINT: + // prendo PRIMO + answ = TSVC_Data[VCName].dataArray.FirstOrDefault(); + break; + + case VC_func.AVG: + answ = TSVC_Data[VCName].dataArray.Average(); + break; + + case VC_func.MEDIAN: + answ = TSVC_Data[VCName].dataArray.Median(); + break; + + case VC_func.MIN: + answ = TSVC_Data[VCName].dataArray.Min(); + break; + + case VC_func.MAX: + default: + answ = TSVC_Data[VCName].dataArray.Max(); + break; + } + } + catch + { } + // ora resetto... SE richiesto... + if (doReset) + { + TSVC_Data[VCName].dataArray = new List(); + TSVC_Data[VCName].DTStart = DateTime.Now; + } + } + return answ; + } + + /// + /// Recupera la VC x TS, svuotando lista e resettando periodo partenza + /// + /// Nome della VC + /// Reimposta e resetta array VC + /// + public int getVal_TSVC_int(string VCName, bool doReset) + { + int answ = 0; + // cerco VC... + if (TSVC_Data.ContainsKey(VCName)) + { + // !!!FARE!!! vero calcolo... x ora FIX a MAX... + foreach (var item in TSVC_Data[VCName].dataArray) + { + answ = (int)item > answ ? (int)item : answ; + } + // ora resetto... SE richiesto.. + if (doReset) + { + TSVC_Data[VCName].dataArray = new List(); + TSVC_Data[VCName].DTStart = DateTime.Now; + } + } + return answ; + } + + /// + /// Restituisce un payload in formato json della lista di valori ricevuta + /// + /// Tipo di URL (eventi / FLog) + /// elenco di valori da coda string salvata + /// + public string jsonPayload(urlType tipoUrl, List elencoValori) + { + string answ = ""; + if (elencoValori != null) + { + string[] valori; + int counter = 0; + DateTime dtEve = DateTime.Now; + switch (tipoUrl) + { + case urlType.FLog: + flogData currFlData = new flogData(); + flogJsonPayload fullFlObj = new flogJsonPayload(); + fullFlObj.fluxData = new List(); + // inizio processando ogni valore + foreach (var item in elencoValori) + { + valori = qDecodeIN(item); + CultureInfo provider = CultureInfo.InvariantCulture; + DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve); + int.TryParse(valori[3], out counter); + currFlData = new flogData() + { + flux = valori[1], + valore = valori[2], + dtEve = dtEve, + dtCurr = DateTime.Now, + cnt = counter + }; + fullFlObj.fluxData.Add(currFlData); + } + // conversione finale + try + { + answ = JsonConvert.SerializeObject(fullFlObj); + } + catch (Exception exc) + { + lgError($"FLog Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); + } + break; + + case urlType.SignIN: + evData currSigData = new evData(); + evJsonPayload fullEvObj = new evJsonPayload(); + fullEvObj.eventList = new List(); + // inizio processando ogni valore + foreach (var item in elencoValori) + { + valori = qDecodeIN(item); + CultureInfo provider = CultureInfo.InvariantCulture; + DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve); + int.TryParse(valori[2], out counter); + currSigData = new evData() + { + valore = valori[1], + dtEve = dtEve, + dtCurr = DateTime.Now, + cnt = counter + }; + fullEvObj.eventList.Add(currSigData); + } + // conversione finale + try + { + answ = JsonConvert.SerializeObject(fullEvObj); + } + catch (Exception exc) + { + lgError($"SignIN Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); + } + break; + + case urlType.RawTransf: + BaseRawTransf currRTData = new BaseRawTransf(); +#if false + rawTransfJsonPayload fullRTObj = new rawTransfJsonPayload(); + fullRTObj.rawTransfData = new List(); + // inizio processando ogni valore + foreach (var item in elencoValori) + { + try + { + currRTData = JsonConvert.DeserializeObject(item); + } + catch (Exception exc) + { + lgError($"Eccezione in deserializzazione BaseRawTransf:{Environment.NewLine}{exc}"); + } + fullRTObj.rawTransfData.Add(currRTData); + } + // conversione finale + try + { + answ = JsonConvert.SerializeObject(fullRTObj); + } + catch (Exception exc) + { + lgError($"RawTransf Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); + } +#endif + + // provo una serializzazione "brutale", ovvero aggiungo alla stringa il + // valore di testa... + string rawResult = ""; + foreach (var item in elencoValori) + { + rawResult += $"{item},"; + } + if (rawResult.Length > 0) + { + rawResult = rawResult.Substring(0, rawResult.Length - 1); + } + answ = "{" + $"\"rawTransfData\":[{rawResult}]" + "}"; + + break; + + case urlType.ULog: + int numVal = 0; + int matrOp = 0; + ulogData currUlData = new ulogData(); + ulogJsonPayload fullUlObj = new ulogJsonPayload(); + fullUlObj.fluxData = new List(); + // inizio processando ogni valore + foreach (var item in elencoValori) + { + valori = qDecodeIN(item); + CultureInfo provider = CultureInfo.InvariantCulture; + DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve); + int.TryParse(valori[3], out matrOp); + int.TryParse(valori[5], out numVal); + int.TryParse(valori[6], out counter); + currUlData = new ulogData() + { + flux = valori[1], + valore = valori[2], + dtEve = dtEve, + dtCurr = DateTime.Now, + cnt = counter, + matrOpr = matrOp, + label = valori[4], + valNum = numVal + }; + fullUlObj.fluxData.Add(currUlData); + } + // conversione finale + try + { + answ = JsonConvert.SerializeObject(fullUlObj); + } + catch (Exception exc) + { + lgError($"ULog Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); + } + break; + + default: + break; + } + } + return answ; + } + + /// + /// Effettua un trim della stringa al numero max di linee da mostrare a video + /// + /// + /// + public string limitLine2show(string newString) + { + // se num righe superiore a limite trimmo... + if (newString.Split('\n').Length > parentForm.nLine2show) + { + //int idx = newString.LastIndexOf('\r'); + int idx = newString.LastIndexOf(Environment.NewLine); + newString = newString.Substring(0, idx); + } + return newString; + } + + /// + /// riporta il log di tutti i dati di results temporali registrati + /// + public void logTimeResults() + { + if (TimingData.results.Count > 0) + { + lgInfo("{0}--------------- START TIMING DATA ---------------", Environment.NewLine); + int globNumCall = 0; + TimeSpan globAvgMsec = new TimeSpan(0); + foreach (TimeRec item in TimingData.results) + { + // loggo SOLO se del mio IOB corrente... + if (item.classCall == cIobConf.codIOB) + { + lgInfo("{4}|Chiamate {0}: effettuate {1}, tempo medio {2:N2} msec | impegno canale {3:P3}", item.codCall, item.numCall, item.avgMsec, item.totMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds, cIobConf.codIOB); + globNumCall += item.numCall; + globAvgMsec += item.totMsec; + } + } + // riporto conteggio medio al secondo... + lgInfo("{4}|Chiamate GLOBALI: {0}, periodo: {1:N2} minuti.cent, tempo medio {2:N2} msec | impegno canale {3:P3}", globNumCall, DateTime.Now.Subtract(dtAvvioAdp).TotalMinutes, globAvgMsec.TotalMilliseconds / globNumCall, globAvgMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds, cIobConf.codIOB); + lgInfo("{0}--------------- STOP TIMING DATA ---------------{0}", Environment.NewLine); + // mostro in form statistiche globali! + parentForm.updateComStats(string.Format("Periodo: {0:N2}min | {1} x {2:N2}ms | canale {3:P3}", DateTime.Now.Subtract(dtAvvioAdp).TotalMinutes, globNumCall, globAvgMsec.TotalMilliseconds / globNumCall, globAvgMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds)); } } /// - /// Effettua gestioen programma: legge e mostra su display... + /// Processa un monitoredItem, e ritorna boolean SE richiede invio (cambio o scadenza) /// - private void processProgram() + /// + /// + /// + public bool monItem2Send(string newVal, DynDataItem item) { - string currPrgName = ""; - // se abilitata lettura prgName - if (enablePrgName) + bool answ = false; + if (item != null) { - if (connectionOk) + // controllo in base al tipo di function... + switch (item.func) { - currPrgName = getPrgName(); + case "SAMPLE": + // controllo se scaduto sample period... + if (item.DTScad < DateTime.Now) + { + answ = true; + } + break; + + case "CHANGE": + default: + // controllo se scaduto o se variato... + if (newVal != item.actVal || item.DTScad < DateTime.Now) + { + // aggiorno scadenza e che vada inviato + answ = true; + } + break; + } + } + return answ; + } + + /// + /// Verifica e processing x gestione ODL automatica + /// + public void processAutoOdl() + { + bool fatto = false; + if (!string.IsNullOrEmpty(getOptPar("AUTO_CHANGE_ODL"))) + { + lgTrace("Richiesta processAutoOdl"); + string IOB_MULTI_CNAME = ""; + string[] elencoMulti = null; + string fullUrl = ""; + if (isMulti) + { + // devo chiamare cambio ODL x OGNI tavola: mi servono i parametri opzionali... + IOB_MULTI_CNAME = getOptPar("IOB_MULTI_CNAME"); + elencoMulti = IOB_MULTI_CNAME.Split(','); + } + // controllo SIA abilitato... + bool doProc = false; + DateTime adesso = DateTime.Now; + bool.TryParse(getOptPar("AUTO_CHANGE_ODL"), out doProc); + if (doProc) + { + lgTrace("AUTO_CHANGE_ODL abilitato"); + bool callChangeODL = false; + // modalità change ODL + string CHANGE_ODL_MODE = "TIME"; + if (!string.IsNullOrEmpty(getOptPar("CHANGE_ODL_MODE"))) + { + CHANGE_ODL_MODE = getOptPar("CHANGE_ODL_MODE"); + } + if (CHANGE_ODL_MODE == "PZCOUNT_RESET") + { + /* verifico se sia "armato" il reset cambio ODL, DEVO essere : + * - NON in produzione + * - contapezzi ACT < contapezzi LAST + * */ + lgTrace("processAutoOdl: caso PZCOUNT_RESET"); + if ((!isRunning || forceResetInRun) && pzCountResetted) + { + callChangeODL = true; + lgInfo("Attivato cambio ODL da PZCOUNT_RESET"); + } + else + { + lgInfo($"isRunning: {isRunning} | pzCountResetted: {pzCountResetted} | forceResetInRun: {forceResetInRun} | contapezziIOB: {contapezziIOB} | contapezziPLC: {contapezziPLC}"); + } + } + else if (CHANGE_ODL_MODE == "TIME") + { + // carico i parametri di configurazione x reset ODL... + string CHANGE_ODL_HOURS = getOptPar("CHANGE_ODL_HOURS"); + string CHANGE_ODL_IDLE_MIN = getOptPar("CHANGE_ODL_IDLE_MIN"); + if (!string.IsNullOrEmpty(CHANGE_ODL_HOURS) && !string.IsNullOrEmpty(CHANGE_ODL_IDLE_MIN)) + { + int minOdlDurHours = -1; + int minPlcIdelMin = -1; + int.TryParse(CHANGE_ODL_HOURS, out minOdlDurHours); + int.TryParse(CHANGE_ODL_IDLE_MIN, out minPlcIdelMin); + // controllo parametri validi + if (minOdlDurHours > 0 && minPlcIdelMin >= 0) + { + // leggo da server inizio ODL... se non multi 1 solo... + DateTime inizioOdl = DateTime.Now; + string rawDataInizio = ""; + if (!isMulti) + { + rawDataInizio = callUrl(urlInizioOdlIob, false); + DateTime.TryParse(rawDataInizio, out inizioOdl); + } + else + { + DateTime tmpData = DateTime.Now; + // prendo il + vecchio... + foreach (var item in elencoMulti) + { + fullUrl = $"{urlInizioOdlIob}|{item}"; + rawDataInizio = callUrl(fullUrl, false); + DateTime.TryParse(rawDataInizio, out tmpData); + inizioOdl = (tmpData < inizioOdl) ? tmpData : inizioOdl; + } + } + // verifico se sia scaduto... + if (inizioOdl.AddHours(minOdlDurHours) < adesso) + { + string rawIdle = ""; + int idlePeriod = 0; + if (!isMulti) + { + // controllo SE sono fermo (spento o in manuale) per il + // periodo minimo richiesto... + rawIdle = callUrl(urlIdleTime, false); + int.TryParse(rawIdle, out idlePeriod); + } + else + { + int tmpIdle = 0; + // prendo il + grande... + foreach (var item in elencoMulti) + { + fullUrl = $"{urlIdleTime}|{item}"; + rawIdle = callUrl(fullUrl, false); + int.TryParse(rawIdle, out tmpIdle); + idlePeriod = tmpIdle > idlePeriod ? tmpIdle : idlePeriod; + } + } + if (idlePeriod >= minPlcIdelMin) + { + callChangeODL = true; + } + } + } + } + } + + // vero processing... + if (callChangeODL) + { + lgTrace("Chiamata: processAutoOdl --> forceSplitODL"); + fatto = forceSplitOdl(); + pzCountResetted = false; + lgInfo("Esecuzione processAutoOdl completata --> pzCountResetted = false"); + } } else { - lgError("Errore connessione mancante x getPrgName"); + lgTrace("AUTO_CHANGE_ODL DISABILITATO"); + } + } + // loggo se fatto + if (fatto) + { + lgTrace("Effettuato processAutoOdl"); + } + } + + /// + /// Effettua processing degli allarmi CNC SE disponibili + /// + public void processCncAlarms() + { + if (utils.CRB("enableAlarms")) + { + Dictionary currAlarms = new Dictionary(); + if (connectionOk) + { + currAlarms = getCncAlarms(); + } + else + { + lgError("Errore connessione mancante x getCncAlarms"); + } + // verifico SE sia cambiato il programma... + if (currAlarms.Count > 0) + { + try + { + string sVal = ""; + if (lastAlarm != currAlarms["CNC_ALARM"]) + { + // salvo! + lastAlarm = currAlarms["CNC_ALARM"]; + // per ogni valore del dizionario mostro ed accodo! + foreach (var item in currAlarms) + { + sVal = string.Format("[CNC_ALARM]{0}|{1}", item.Key, item.Value); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + } + } + // accodo ALTRI allarmi NON CNC... + foreach (var item in currAlarms.Where(X => X.Key != "CNC_ALARM")) + { + sVal = $"{item.Key} | {item.Value}"; + accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + } + } + catch (Exception exc) + { + lgError("Eccezione in processCncAlarms{0}{1}", Environment.NewLine, exc); + } + } + } + } + + /// + /// Effettua processing contapezzi (ed eventualmente alza il bit di contapezzo...) + /// + public virtual void processContapezzi() + { } + + /// + /// Effettua processing CUSTOM x l'IOB corrente (ed invia ad IO) (task svolto tipicamente + /// ogni 5 sec se base timer 10ms, vedere app.config) + /// + public virtual void processCustomTaskLF() + { } + + /// + /// Task periodici SE disconnesso + /// + public virtual void processDisconnectedTask() + { + } + + /// + /// Effettua processing del recupero dei valori dinamici: + /// es: speed (RPM, feedrate) degli assi, valori pressioni, temeprature + /// + public void processDynData() + { + bool enableByApp = utils.CRB("enableDynData"); + bool enableByIob = (getOptPar("ENABLE_DYN_DATA") == "TRUE"); + bool forceSendByIob = (getOptPar("FORCE_DYN_DATA") == "TRUE"); + Dictionary currDynData = new Dictionary(); + + if (enableByApp || enableByIob) + { + // verifico se ho fattore demoltiplica... + if (demFactDynData > 1) + { + lgTrace($"Non eseguo processDynData: fatt veto {demFactDynData}"); + // ricudo... + demFactDynData--; + } + else + { + lgInfo("Inizio processDynData"); + // sistemo il valore di demoltiplica a default + fixDemFactDynData(); + // proseguo + if (connectionOk) + { + currDynData = getDynData(); + try + { + string sVal = ""; + // se richiesto send diretto... + if (forceSendByIob) + { + // per ogni valore del dizionario mostro ed accodo! + foreach (var item in currDynData) + { + sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + } + } + // altrimenti verifico SE sia cambiato il valore dei DynData... + else if (lastDynDataCtrlVal != currDynData["DYNDATA"]) + { + // salvo! + lastDynDataCtrlVal = currDynData["DYNDATA"]; + // per ogni valore del dizionario mostro ed accodo! + foreach (var item in currDynData) + { + sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + } + } + // salvo array... + lastDynData = currDynData; + } + catch (Exception exc) + { + lgError(exc, "Eccezione in processDynData"); + } + } + else + { + lgError("Errore connessione mancante x getDynData"); + } + } + } + } + + /// + /// Processa gestione memoria x invio dati QUANDO IOB è disconnesso da CNC... + /// + public void processMemoryDiscon() + { + // init obj display + newDisplayData currDispData = new newDisplayData(); + // controllo contatore invio "keepalive"... invio solo a scadenza + if (DateTime.Now.Subtract(lastDisconnCheck).TotalSeconds > utils.CRI("disconMaxSec")) + { + // resetto tutti i valori BYTE IN/PREV/OUT... così invio macchina spenta... + B_input = 0; + B_output = 0; + B_previous = 0; + accodaSigIN(ref currDispData); + // update controllo + lastDisconnCheck = DateTime.Now; + } + raiseRefresh(currDispData); + } + + /// + /// Effettua processing mode/status (EDIT/MDI/...) + /// + public virtual void processMode() + { } + + /// + /// Effettua processing ALTRI contatori/parametri (ed invia ad IO) + /// + public virtual void processOtherCounters() + { } + + /// + /// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid) + /// + public virtual void processOverride() + { + bool enableByApp = utils.CRB("enableOverrides"); + bool enableByIob = (getOptPar("ENABLE_OVERRIDES") == "TRUE"); + Dictionary currOverride = new Dictionary(); + if (enableByApp || enableByIob) + { + lgInfo("Inizio processOverride"); + if (connectionOk) + { + currOverride = getOverrides(); + } + else + { + lgError("Errore connessione mancante x getOverrides"); + } + + // SE sono connesso... + if (connectionOk) + { + // se HO dei valori override... + if (currOverride.Count > 0) + { + // verifico SE sia cambiato il programma... + if (lastOverrideFS != currOverride["FEED_OVER"] || lastOverrideRapid != currOverride["RAPID_OVER"]) + { + // salvo! + lastOverrideFS = currOverride["FEED_OVER"]; + lastOverrideRapid = currOverride["RAPID_OVER"]; + // per ogni valore del dizionario mostro ed accodo! + string sVal = ""; + foreach (var item in currOverride) + { + sVal = string.Format("[OVERRIDES]{0}|{1}", item.Key, item.Value); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + } + } + } + } + } + } + + /// + /// Effettua ciclo controllo richieste server + /// + public void processServerRequests() + { + Dictionary task2exe = new Dictionary(); + Dictionary taskDone = new Dictionary(); + // recupero elenco delle cose da fare + string resp = getTask2exe(); + if (!string.IsNullOrEmpty(resp)) + { + try + { + task2exe = JsonConvert.DeserializeObject>(resp); + // se ho da fare chiamo esecuzione.. + if (task2exe.Count > 0) + { + taskDone = processTask(task2exe); + } + } + catch (Exception exc) + { + lgError($"Eccezione in processServerRequests:{Environment.NewLine}{exc}"); + } + } + } + + public Dictionary processTask(Dictionary task2exe) + { + Dictionary taskDone = new Dictionary(); + if (task2exe != null) + { + lgInfo($"Task2Exe S01: {task2exe.Count} task ricevuti:"); + int idTask = 0; + foreach (var item in task2exe) + { + idTask++; + lgInfo($"[{idTask:00}] - {item.Key} --> {item.Value}"); + } + // chiamo procedura esecutiva (diversa x ogni IOB) + taskDone = executeTasks(task2exe); + lgInfo($"Task2Exe S02: eseguiti {taskDone.Count} task"); + // loggo tutti i task done... + foreach (var item in taskDone) + { + sendToTaskWatch(item.Key, item.Value); + } + // ora chiamo la cancellazione dei task eseguiti... + foreach (var item in taskDone) + { + remTask2exe(item.Key, item.Value); + } + } + return taskDone; + } + + /// + /// Classe fittizia in caso di processing task in VHF + /// + public virtual void processVHF() + { + } + + /// + /// Classe fittizia in caso di processing watchdog data + /// + public virtual void processWhatchDog() + { + } + + /// + /// Effettua rilettura del contapezzi dal server MP/IO + /// + /// Forza rilettura da DB tempi ciclo rilevati + public void pzCntReload(bool forceCountRec) + { + // legge da IO server ULTIMO valore CONTPEZZI al riavvio... + string currServerCount = ""; + string lastIdxODL = ""; + if (checkServerAlive) + { + // leggo PRIMA ODL .... + lastIdxODL = utils.callUrl(urlGetCurrODL); + lgTrace("Lettura ODL dall'url {0} --> {1}", urlGetCurrODL, lastIdxODL); + // se ho valori in coda da trasmettere uso dati REDIS + if (forceCountRec) + { + // uso dati da TCiclo registrati... + currServerCount = utils.callUrl(urlGetPzCountRec); + lgInfo("Lettura contapezzi da TCiclo dall'url {0} --> num pz: {1}", urlGetPzCountRec, currServerCount); + } + else + { + // uso il contapezzi dichiarato dall'IOB stesso + currServerCount = utils.callUrl(urlGetPzCount); + lgInfo("Lettura contapezzi dall'url {0}", urlGetPzCount); + } + // controllo: SE NON HO ODL... + if (string.IsNullOrEmpty(lastIdxODL) || lastIdxODL == "0") + { + // NON AGGIORNO + contapezziIOB = contapezziPLC; + lgError($"Errore lettura ODL (vuoto) resta tutto invariato contapezzi: {contapezziIOB} | contapezziPLC {contapezziPLC}"); + } + else + { + if (!string.IsNullOrEmpty(currServerCount)) + { + // se "-1" resto a ultimo... + if (currServerCount != "-1") + { + int newVal = -1; + Int32.TryParse(currServerCount, out newVal); + contapezziIOB = newVal > -1 ? newVal : contapezziIOB; + lgInfo("Ricevuta conferma da server di {0} pezzi registrati per ODL", currServerCount); + } + else + { + // NON AGGIORNO + contapezziIOB = contapezziPLC; + lgError($"Errore lettura contapezzi (-1) - uso contapezziPLC --> {contapezziPLC}"); + } + } + else + { + // registro che ho UN NUOVO ODL + lgInfo($"Lettura ODL in pzCntReload, currIdxODL {currIdxODL} --> lastIdxODL {lastIdxODL}"); + // se ODL differente e NUOVO è zero --> resetto! + if (currIdxODL.ToString() != lastIdxODL && lastIdxODL == "0") + { + // cambiato ODL quindi reset... + contapezziIOB = 0; + lgInfo("Nuovo ODL==0, RESET contapezzi (-->ZERO)"); + } + // provo a salvare nuovo ODL + int.TryParse(lastIdxODL, out currIdxODL); + } } } else { - currPrgName = lastPrgName; - } - // verifico SE sia cambiato il programma... - if (lastPrgName != currPrgName) - { - // salvo! - lastPrgName = currPrgName; - string sVal = string.Format("[PROG]{0}", currPrgName); - - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog("PROG", currPrgName)); + // se server NON pronto... + contapezziIOB = contapezziPLC; + lgError("Errore server NON pronto in pzCntReload"); } } /// - /// Processo lettura dati sysinfo + /// Fornisce il valore di flusso e valore in formato valido x messa in coda nel formato + /// dtEve#flusso#valore#cont Flusso datiValore da salvare /// - private void processSysInfo() + public string qEncodeFLog(string flusso, string valore) { - if (utils.CRB("enableSysInfo")) + string answ = ""; + try { - Dictionary currSysInfo = new Dictionary(); + answ = $"{DateTime.Now:yyyyMMddHHmmssfff}#{flusso}#{valore}#{counterULog}"; + } + catch + { } + return answ; + } + /// + /// Fornisce il valore di flusso e valore in formato valido x messa in coda nel formato + /// dtEve#flux#value#cont DataOra evento + /// registratoFlusso datiValore da salvare + /// + public string qEncodeFLog(DateTime eventDT, string flusso, string valore) + { + string answ = ""; + try + { + answ = $"{eventDT:yyyyMMddHHmmssfff}#{flusso}#{valore}#{counterFLog}"; + } + catch + { } + return answ; + } + + /// + /// Fornisce il valore di UserLog e valore in formato valido x messa in coda nel formato: + /// dtEve#flusso#value#cont#matrOpr#label#valNum Flusso dati + /// (RC/RS/DI)Valore da inviare + /// (valStringMatricola operatoreValore etichetta: causale scarto / tagCodeValore numerico: esitoOk (0/1) / nuo scarti + /// + public string qEncodeULog(string flusso, string valore, int matrOpr, string label, int valNum) + { + string answ = ""; + try + { + answ = $"{DateTime.Now:yyyyMMddHHmmssfff}#{flusso}#{valore}#{matrOpr}#{label}#{valNum}#{counterULog}"; + } + catch + { } + return answ; + } + + /// + /// Effettua lettura dati Parametri da aggiornare x display in form + /// + public virtual void readAllData(ref newDisplayData currDispData) + { + if (currDispData == null) + { + currDispData = new newDisplayData(); + } + try + { + if (DemoIn) + { + // segnalo che sono in Demo + currDispData.semIn = Semaforo.SV; + } if (connectionOk) { - currSysInfo = getSysInfo(); + readSemafori(ref currDispData); } else { - lgError("Errore connessione mancante x getSysInfo"); + lgError("Errore connessione mancante x readSemafori"); } - // verifico SE sia cambiato il programma... - if (lastSysInfo != currSysInfo["SYSINFO"]) + + nReadIN++; + // aggiorno valore mostrato... + displayRawData(ref currDispData); + } + catch + { + currDispData.semIn = Semaforo.SR; + } + raiseRefresh(currDispData); + } + + /// + /// Effettua lettura semafori principale Parametri da + /// aggiornare x display in form + /// + public virtual void readSemafori(ref newDisplayData currDispData) + { + lastReadPLC = DateTime.Now; + } + + /// + /// Aggiunge ai dati da inviare alla parentform i valori di RawInput rilevati (32bit) + /// 2021.08.27: filtrati secondo i valori setup start/size RawDataInput + /// + public virtual void reportRawInput(ref newDisplayData currDispData) + { + // processo eventualmente aggiungendo ad elementi esistenti... + if (currDispData == null) + { + currDispData = new newDisplayData(); + } + try + { + StringBuilder sb = new StringBuilder(); + sb.Append($"B_input --> {(short)B_input}{Environment.NewLine}"); + sb.Append($"{baseUtils.binaryForm(B_input)}{Environment.NewLine}"); + sb.Append($"{Environment.NewLine}"); + sb.Append($"----------- RAW Data Memory -----------{Environment.NewLine}"); + // Do x scontato siano VALIDI i valori di RawDataInputStart / size --> filtro... + var filtRawData = new byte[RawDataInputSize]; + Array.Copy(RawInput, RawDataInputStart, filtRawData, 0, RawDataInputSize); + int i = RawDataInputStart; + foreach (var item in filtRawData) { - // salvo! - lastSysInfo = currSysInfo["SYSINFO"]; - // per ogni valore del dizionario mostro ed accodo! - string sVal = ""; - foreach (var item in currSysInfo) + sb.Append($"B{i:00} --> {baseUtils.binaryForm(item)} = {(short)item}{Environment.NewLine}"); + i++; + } + sb.Append("-------------------------------"); + currDispData.currBitmap = sb.ToString(); + } + catch + { } + } + + /// + /// Metodo generico di reset contapezzi... + /// + /// + public virtual bool resetcontapezziPLC() + { + return false; + } + + /// + /// metodo dummy x salvataggio aree memoria conf x CN + /// + /// tipo di DUMP + public virtual void saveMemDump(dumpType tipo) + { + } + + /// + /// Salva valori indicati in prod data + /// + /// Item KVP di cui salvare i dati in currProdData come chiave/valore + /// + public void saveProdData(KeyValuePair item) + { + // imposto i valori... + if (currProdData.ContainsKey(item.Key)) + { + currProdData[item.Key] = item.Value; + } + else + { + currProdData.Add(item.Key, item.Value); + } + } + + /// + /// Effettua salvataggio in LUT del valore ricevuto (valori numerici) + /// + /// + /// + /// + /// + public virtual void saveValue(ref Dictionary outVal, double valore, string chiave) + { + //check obj preliminare + if (outVal == null) + { + outVal = new Dictionary(); + } + bool scaduto = stackVal_TSVC(chiave, valore); + // recupero VC + valore = getVal_TSVC(chiave, scaduto); + if (scaduto) + { + // limite a 3 digit x valore float + outVal.Add(chiave, $"{valore:N3}"); + } + LastTSVC[chiave] = valore; + } + + /// + /// Effettua salvataggio in LUT del valore ricevuto (valori string) + /// - non serve calcolo medie o altro + /// - accoda in out val e basta + /// + /// Array eventi da popolare + /// valore da salvare + /// ID/chiave di riferimento + /// + public virtual void saveAlarmString(ref Dictionary outVal, string valore, string chiave) + { + DateTime adesso = DateTime.Now; + //check obj preliminare + if (outVal == null) + { + outVal = new Dictionary(); + } + // default invio: blindato a 120 sec (rivedere da conf?) + int vetoSendAlarms = 120; + // verifico se sia scaduto OVVERO variato rispetto a prima oppure oltre tempo + bool scaduto = !LastTSSSend.ContainsKey(chiave) || (LastTSSSend[chiave].AddSeconds(vetoSendAlarms) < adesso); + bool cambiato = !LastTSS.ContainsKey(chiave) || !LastTSS[chiave].Equals(valore); + if (scaduto || cambiato) + { + outVal.Add(chiave, valore); + LastTSS[chiave] = valore; + LastTSSSend[chiave] = adesso; + } + } + + /// + /// Effettua salvataggio in LUT del valore ricevuto (valori string) + /// - non serve calcolo medie o altro + /// - accoda in out val e basta + /// + /// Array eventi da popolare + /// valore da salvare + /// ID/chiave di riferimento + /// + public virtual void saveValueString(ref Dictionary outVal, string valore, string chiave) + { + DateTime adesso = DateTime.Now; + //check obj preliminare + if (outVal == null) + { + outVal = new Dictionary(); + } + int maxVetoSeconds = 60; + + // cerco VC... + if (TSVC_Data.ContainsKey(chiave)) + { + maxVetoSeconds = TSVC_Data[chiave].Period; + } + // verifico se sia scaduto OVVERO variato rispetto a prima oppure oltre tempo + bool scaduto = !LastTSSSend.ContainsKey(chiave) || (LastTSSSend[chiave].AddSeconds(maxVetoSeconds) < adesso); + bool cambiato = !LastTSS.ContainsKey(chiave) || !LastTSS[chiave].Equals(valore); + if (scaduto || cambiato) + { + outVal.Add(chiave, valore); + LastTSS[chiave] = valore; + LastTSSSend[chiave] = adesso; + } + } + + /// + /// Invio la variazione dello stato allarmi (se avvenuta) + /// + /// COD memoria allarmi + /// Indice memoria allarmi + /// ultimo stato rilevato + /// stato corrente + /// Lista allarmi validi per l'area + /// + public bool sendAlarmVariations(string memAddr, int index, uint lastStatus, uint currStatus, List AlarmList) + { + bool fatto = false; + if (lastStatus != currStatus) + { + List ActiveAlarmList = new List(); + // invio GET del MemoryAddress, del banco e del valore currStatus + lastUrl = $"{urlSendAlarm}?memAddr={memAddr}&index={index}&currStatus={currStatus}"; + if (currStatus == 0) + { + ActiveAlarmList.Add("ALL OK"); + } + else + { + // calcolo quali allarmi mostrare dato currStatus ed elenco allarmi + string bitMap = Convert.ToString(currStatus, 2); + int bitLen = bitMap.Length; + // ciclo x associare tutti gli allarmi + for (int i = 0; i < bitLen; i++) { - sVal = string.Format("[SYSINFO]{0}|{1}", item.Key, item.Value); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + // se è 1 --> aggiungo! + if (bitMap[bitLen - i - 1] == '1') + { + // se sono entro limiti + if (AlarmList.Count >= i) + { + ActiveAlarmList.Add($"{i:000}-{AlarmList.ElementAt(i)}"); + } + //else + //{ + // ActiveAlarmList.Add($"Unknown Bit.{i}"); + //} + } } } - } - } - private void reportDataProc() - { - // update valori visualizzazione... - parentForm.dataProcLabel = string.Format("RAW: {0} --> IN: {1} --> OUT: {2}", nReadIN, nReadFilt, nSendOut); - } + string rawData = JsonConvert.SerializeObject(ActiveAlarmList); - /// - /// Imposto alcuni valori di default - /// - /// indica se sia richeisto di SVUOTARE le code delel info - private void setDefaults(bool resetQueue) - { - numSim = utils.CRI("numSim"); - lastPrgName = ""; - nReadIN = 0; - nReadFilt = 0; - nSendOut = 0; - currMode = 0; - lastAlarm = ""; - doStartMemDump = utils.CRB("doStartMemDump"); - doSampleMemory = utils.CRB("doSampleMemory"); - // fix url wait random... - urlRandWait = utils.CRI("urlRandWait"); - - // svuoto code se richiesto - if (resetQueue) - { - QueueAlarm = new ConcurrentQueue(); - QueueIN = new ConcurrentQueue(); - QueueFLog = new ConcurrentQueue(); - QueueMessages = new ConcurrentQueue(); - QueueRawTransf = new ConcurrentQueue(); - QueueULog = new ConcurrentQueue(); - } - // imposto contatori blink a zero... - i_counters = new int[32]; - lastPeriodicLog = DateTime.Now; - // fix parametri generali... - enablePrgName = true; - } - - private void svuotaCodaContapezzi() - { - // permetto al max 2 tentativi infruttuosi... - int maxTry = 2; - int oldContapezzi = contapezziIOB; - // se ho contapezzi OLTRE limite... - while ((MPOnline) && (contapezziPLC > contapezziIOB + minSendPzCountBlock)) - { - lgInfo($"Ciclo svuotaCodaContapezzi --> contapezziPLC: {contapezziPLC} | contapezziIOB: {contapezziIOB}"); - if (!isMulti) + //string resp = utils.callUrlNow(lastUrl, rawData); + string resp = utils.callUrlAsync(lastUrl, rawData); + if (!string.IsNullOrEmpty(resp)) { - pzCntReload(true); - } - // provo invio - trySendPzCountBlock(); - // verifica per evitare loop infinito invio fallito - if (oldContapezzi == contapezziIOB) - { - maxTry--; + if (resp.ToUpper() == "OK") + { + // segnalo fatto + fatto = true; + } } else { - maxTry = 2; - oldContapezzi = contapezziIOB; + lgError($"Errore in invio richiesta registrazione allarme: URL: {lastUrl}{Environment.NewLine}Payload:{Environment.NewLine}{rawData}"); } - // verifico maxTry: se li ho esauriti esco! - if (maxTry <= 0) - { - return; - } - // aspetto x dare tempo calcolo - Thread.Sleep(400); } + return fatto; } /// - /// Processo la coda FLog... + /// Invia una LISTA di valori /// - private void svuotaCodaFLog() + /// + /// + public void sendDataBlock(urlType tipoUrl, List listQueueVal) { - // controllo se è passato oltre watchdog e non ho inviato nulla --> RE-INVIO (ultimo inviato)!!!! - if (DateTime.Now.Subtract(lastWatchDog).TotalSeconds > utils.CRI("watchdogMaxSec")) + // init obj display + newDisplayData currDispData = new newDisplayData(); + if (listQueueVal != null) { - string wdStatus = "elapsed"; - string sVal = string.Format("[WDST]{0}", wdStatus); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog("WDST", wdStatus)); - lastWatchDog = DateTime.Now; - } - // verifico SE la coda abbia dei valori... - if (QueueFLog.Count > 0) - { - // invio pacchetto di dati (max da conf) - for (int i = 0; i < nMaxSend; i++) + try { - // SE ho qualcosa in coda... - if (QueueFLog.Count > 0) + // recupero e formatto URL dati da coda... + lastUrl = urlDataBlock(tipoUrl); + // in base al tipo di dato compongo il payload Json da inviare + string payload = jsonPayload(tipoUrl, listQueueVal); + // async a true SE FLog + bool doAsync = tipoUrl == urlType.FLog ? true : false; + // se NON sono in demo effettuo invio! + if (!DemoOut) { - string currVal = ""; - if (MPOnline) + // SE server alive... + if (checkServerAlive) { - if (IobOnline) + // chiamo URL! + string answ = callUrlWithPayload(lastUrl, payload, doAsync); + // attesa opzionale se configurata + + // loggo! + lgInfo($"[SEND payload] TipoURL: {tipoUrl} | {listQueueVal.Count} records --> {answ}"); + // se "OK" verde, altrimenti errore --> ROSSO + if (answ.Contains("OK")) { - // se ho + di 2 elementi in coda --> uso invio JSON in blocco... - if (QueueFLog.Count > 1) + currDispData.semOut = Semaforo.SV; + // se oltre 1 min NON era online --> check pezzi! + if (DateTime.Now.Subtract(lastIobOnline).TotalMinutes > 1 && !isMulti) { - List listaValori = new List(); - // se ho + di maxJsonData elementi --> invio un set di dati alla volta - if (QueueFLog.Count > maxJsonData) - { - // prendoi primi maxJsonDataValori - for (int j = 0; j < maxJsonData; j++) - { - QueueFLog.TryDequeue(out currVal); - listaValori.Add(currVal); - } - sendDataBlock(urlType.FLog, listaValori); - lastWatchDog = DateTime.Now; - } - else - { - // invio in blocco - listaValori = QueueFLog.ToList(); - // invio - sendDataBlock(urlType.FLog, listaValori); - // svuoto! - QueueFLog = new ConcurrentQueue(); - lastWatchDog = DateTime.Now; - } - } - else - { - // INVIO SINGOLO...!!! - QueueFLog.TryDequeue(out currVal); - sendToMoonPro(urlType.FLog, currVal); - lastWatchDog = DateTime.Now; + lgInfo($"sendDataBlock --> offline timeout ({lastIobOnline}) --> pzCntReload(true)"); + pzCntReload(true); } + lastIobOnline = DateTime.Now; } else { - break; + currDispData.semOut = Semaforo.SR; } } else { - break; + lgInfo($"[SERVER KO] {listQueueVal.Count}"); } } else { - break; + currDispData.semOut = Semaforo.SV; + // loggo! + lgInfo($"{listQueueVal.Count} records --> [SIM]"); } + nSendOut += listQueueVal.Count; + // riporto cosa inviato + currDispData.newUrlCallData = lastUrl; + // aggiorno data ultimo watchdog... + lastWatchDog = DateTime.Now; } - } - } - - // - /// Processo la coda UserLog... - /// - private void svuotaCodaULog() - { - // verifico SE la coda abbia dei valori... - if (QueueULog.Count > 0) - { - // invio pacchetto di dati (max da conf) - for (int i = 0; i < nMaxSend; i++) + catch { - // SE ho qualcosa in coda... - if (QueueULog.Count > 0) - { - string currVal = ""; - if (MPOnline) - { - if (IobOnline) - { - List listaValori = new List(); - // se ho + di maxJsonData elementi --> invio un set di dati alla volta - if (QueueULog.Count > maxJsonData) - { - // prendoi primi maxJsonDataValori - for (int j = 0; j < maxJsonData; j++) - { - QueueULog.TryDequeue(out currVal); - listaValori.Add(currVal); - } - sendDataBlock(urlType.ULog, listaValori); - } - else - { - // invio in blocco - listaValori = QueueULog.ToList(); - // invio - sendDataBlock(urlType.ULog, listaValori); - // svuoto! - QueueULog = new ConcurrentQueue(); - } - } - else - { - break; - } - } - else - { - break; - } - } - else - { - break; - } + currDispData.semOut = Semaforo.SR; } } + raiseRefresh(currDispData); } /// - /// Cerca di inviare su un altro thread i vari dati accumulati... + /// Effettua invio a MoonPro del valore richiesto /// - private void trySendValues() + /// + /// + /// Valore da trasmettere: es + /// INPUT: lo status rilevato in HEX + /// FLog: il valore da trasmettere per il flusso indicato + /// + public void sendToMoonPro(urlType tipoUrl, string queueVal) { // init obj display newDisplayData currDispData = new newDisplayData(); try { - // verifico se risponde il server... - if (checkServerAlive) + // recupero e formatto URL dati da coda... + switch (tipoUrl) { - bool iobOk = false; - if (utils.CRB("sendDataByThread")) + case urlType.FLog: + lastUrl = urlFLog(queueVal); + break; + + case urlType.SignIN: + lastUrl = urlInput(queueVal); + break; + + default: + lastUrl = ""; + break; + } + // se NON sono in demo effettuo invio! + if (!DemoOut) + { + // SE server alive... + if (checkServerAlive) { - Task taskCheck = Task.Run(() => iobOk = checkIobEnabled); - } - else - { - iobOk = checkIobEnabled; - } - // verifico SE posso inviare dati - if (iobOk) - { - currDispData.semOut = Semaforo.SV; - // verificare come gestire il task secondario senza interferenza (chiamate update su FORM da thread secondari danno errori) - if (utils.CRB("sendDataByThread")) + // chiamo URL! + string answ = callUrl(lastUrl, false); + // loggo! + lgDebug(string.Format("[SEND] {0} -> {1}", queueVal, answ)); + // se oltre 1 min NON era online --> check pezzi! + if (DateTime.Now.Subtract(lastIobOnline).TotalMinutes > 1 && !isMulti) { - // invio con thread separato... - Task taskSigIN = Task.Run(() => svuotaCodaSignIN()); - Task taskFLog = Task.Run(() => svuotaCodaFLog()); - Task taskULog = Task.Run(() => svuotaCodaULog()); + lgInfo($"sendToMoonPro --> offline timeout ({lastIobOnline}) --> pzCntReload(true)"); + pzCntReload(true); + } + // se richiesto effettuo refresh contapezzi + if (needRefreshPzCount && !isMulti) + { + pzCntReload(true); + needRefreshPzCount = false; + } + lastIobOnline = DateTime.Now; + // se "OK" verde, altrimenti errore --> ROSSO + if (answ == "OK") + { + currDispData.semOut = Semaforo.SV; } else { - // gestione queue SignalIN (invio, display) - svuotaCodaSignIN(); - currDispData.counter = contapezziIOB; - raiseRefresh(currDispData); - // provo a svuotare coda contapezzi - svuotaCodaContapezzi(); - currDispData.counter = contapezziIOB; - raiseRefresh(currDispData); - // gestione queue FluxLog (invio, display) - svuotaCodaFLog(); - // coda UserLog - svuotaCodaULog(); - // refresh - raiseRefresh(currDispData); + currDispData.semOut = Semaforo.SR; } - // se arrivo è tutto ok... - currSendErrors = 0; } else { - // mostro VETO-SEND x invio... GIALLO - currDispData.semOut = Semaforo.SG; - if (periodicLog) - { - lgInfo("IOB - VETO SEND"); - } + lgError(string.Format("[SERVER KO] {0}", queueVal)); } } else { - // mostro SERVER KO x invio... ROSSO - currDispData.semOut = Semaforo.SR; - if (periodicLog) - { - lgError("IOB - SERVER NOT READY"); - } + currDispData.semOut = Semaforo.SV; + // loggo! + lgDebug(string.Format("{0} -> [SIM]", queueVal)); } + nSendOut++; + currDispData.newUrlCallData = lastUrl; + // aggiorno data ultimo watchdog... + lastWatchDog = DateTime.Now; } - catch (Exception exc) + catch { - lgError($"Errore in fase trySendValues | currSendErrors: {currSendErrors}{Environment.NewLine}{exc}"); currDispData.semOut = Semaforo.SR; } raiseRefresh(currDispData); } /// - /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce + /// Metodo generico di IMPOSTAZIONE FORZATA del contapezzi... /// - /// - /// - /// - /// Nuovo valore incrementato - private double updateValDoubleByIncr(int i, double delta, string searchString) + /// Pezzi richiesti + /// + public virtual bool setcontapezziPLC(int newPzCount) { - // stringa da cercare.. - string keyVal = string.Format(searchString, i + 1); - // recupero valore precedente... - double contAct = getStoredValDouble(keyVal); - // nuovo valore... - contAct += delta; - // salvo in ram! - persistenceLayer[keyVal] = contAct.ToString(); - // rendo il valore! - return contAct; + return false; } /// - /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce + /// Processing di Variabili Campionarie x TimeSeries, accoda valori x la VC (se esiste) e + /// restituisce bool val se SCADUTO periodo controllo /// - /// - /// - /// - /// Nuovo valore incrementato - private long updateValLongByIncr(int i, long delta, string searchString) + /// Nome della VC + /// Valore (nuovo) delal VC + /// + public bool stackVal_TSVC(string VCName, double VCVal) { - // stringa da cercare.. - string keyVal = string.Format(searchString, i + 1); - // recupero valore precedente... - long contAct = getStoredValLong(keyVal); - // nuovo valore... - contAct += delta; - // salvo in ram! - persistenceLayer[keyVal] = contAct.ToString(); - // rendo il valore! - return contAct; + bool answ = false; + // cerco VC... + if (TSVC_Data.ContainsKey(VCName)) + { + TSVC_Data[VCName].dataArray.Add(VCVal); + // ora verifico scadenza... + if (TSVC_Data[VCName].DTStart.AddSeconds(TSVC_Data[VCName].Period) < DateTime.Now) + { + answ = true; + } + } + return answ; } /// - /// Aggiorna un valore del dizionario in SOSTITUZIONE + /// Avvia l'adapter sulla porta richiesta /// - /// - /// - /// - /// Nuovo valore incrementato - private void updateValString(int i, string newVal, string searchString) + /// indica se sia richeisto di SVUOTARE le code delel info + public virtual void startAdapter(bool resetQueue) { - // stringa da cercare.. - string keyVal = string.Format(searchString, i + 1); - // salvo in ram! - persistenceLayer[keyVal] = newVal; + DateTime adesso = DateTime.Now; ; + DateTime scaduto = adesso.AddMinutes(-10); + lgInfo("Starting adapter..."); + maxJsonData = utils.CRI("maxJsonData"); + maxJsonDataEv = utils.CRI("maxJsonDataEv"); + parentForm.commPlcActive = false; + adpRunning = true; + dtAvvioAdp = adesso; + lastWatchDog = scaduto; + lastPING = scaduto; + lastReadPLC = scaduto; + lastDisconnCheck = scaduto; + TimingData.resetData(); + // aggiungo altri defaults + setDefaults(resetQueue); + adpTryRestart = true; + lgDebug("startAdapter completed"); } /// - /// Aggiorna un valore del dizionario in SOSTITUZIONE e lo restituisce + /// ferma l'adapter... /// - /// - /// - /// - /// Nuovo valore incrementato - private void updateValUInt(int i, uint newVal, string searchString) + /// + /// indica se si debba tentare di riavviare l'adapter (con caduta connessione viene fermato + /// in automatico) + /// + /// indica se sia richeisto di SVUOTARE le code delel info + public virtual void stopAdapter(bool tryRestart, bool forceDequeue) { - // stringa da cercare.. - string keyVal = string.Format(searchString, i + 1); - // salvo in ram! - persistenceLayer[keyVal] = newVal.ToString(); + if (forceDequeue) + { + // svuoto le code dei valori letti e non ancora trasmessi... + parentForm.displayTaskAndLog("[CLOSING] Svuotamento FORZATO coda segnali..."); + while (QueueIN.Count > 0) + { + // INVIO COMUNQUE...!!! + string valore = ""; + QueueIN.TryDequeue(out valore); + sendToMoonPro(urlType.SignIN, valore); + } + parentForm.displayTaskAndLog("[CLOSING] Svuotamento FORZATO coda FluxLOG..."); + // se ho + di 2 elementi in coda --> uso invio JSON in blocco... + if (QueueFLog.Count > minJsonData) + { + while (QueueFLog.Count > 0) + { + List listaValori = new List(); + // se ho + di maxJsonData elementi --> invio un set di dati alla volta + if (QueueFLog.Count > maxJsonData) + { + string currVal = ""; + // prendoi primi maxJsonDataValori + for (int i = 0; i < maxJsonData; i++) + { + QueueFLog.TryDequeue(out currVal); + listaValori.Add(currVal); + } + sendDataBlock(urlType.FLog, listaValori); + } + else + { + // invio in blocco + listaValori = QueueFLog.ToList(); + // invio + sendDataBlock(urlType.FLog, listaValori); + // svuoto! + QueueFLog = new ConcurrentQueue(); + } + } + // HO FINITO invio di FLog... + } + else + { + string currVal = ""; + while (QueueFLog.Count > 0) + { + // INVIO COMUNQUE...!!! + QueueFLog.TryDequeue(out currVal); + sendToMoonPro(urlType.FLog, currVal); + } + } + + // svuoto coda ULog + while (QueueULog.Count > 0) + { + List listaValori = new List(); + // se ho + di maxJsonData elementi --> invio un set di dati alla volta + if (QueueULog.Count > maxJsonData) + { + string currVal = ""; + // prendoi primi maxJsonDataValori + for (int i = 0; i < maxJsonData; i++) + { + QueueULog.TryDequeue(out currVal); + listaValori.Add(currVal); + } + sendDataBlock(urlType.ULog, listaValori); + } + else + { + // invio in blocco + listaValori = QueueULog.ToList(); + // invio + sendDataBlock(urlType.ULog, listaValori); + // svuoto! + QueueULog = new ConcurrentQueue(); + } + } + } + parentForm.displayTaskAndLog("[STOP] Stopping adapter..."); + adpTryRestart = false; + + parentForm.displayTaskAndLog("[STOP] Stopping adapter - last periodic data read..."); + + // chiudo la connessione all'adapter... + tryDisconnect(); + dtStopAdp = DateTime.Now; + adpTryRestart = tryRestart; + adpRunning = false; + // chiudo! + parentForm.displayTaskAndLog("Adapter Stopped."); + parentForm.commPlcActive = false; } /// - /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce + /// Processo la coda SignalIN... /// - /// - /// - /// - /// Nuovo valore incrementato - private uint updateValUIntByIncr(int i, uint delta, string searchString) + public void svuotaCodaSignIN() { - // stringa da cercare.. - string keyVal = string.Format(searchString, i + 1); - // recupero valore precedente... - uint contAct = getStoredValUInt(keyVal); - // nuovo valore... - contAct += delta; - // salvo in ram! - persistenceLayer[keyVal] = contAct.ToString(); - // rendo il valore! - return contAct; + // verifico SE la coda abbia dei valori... + if (QueueIN.Count > 0) + { + // invio pacchetto di dati (max da conf) + for (int i = 0; i < nMaxSend; i++) + { + if (QueueIN.Count > 0) + { + string currVal = ""; + // se online provo + if (MPOnline) + { + if (IobOnline) + { + // se ho + di 2 elementi in coda --> uso invio JSON in blocco... + if (QueueIN.Count > 1) + { + List listaValori = new List(); + // se ho + di maxJsonData elementi --> invio un set di dati alla volta + if (QueueIN.Count > maxJsonDataEv) + { + // prendoi primi maxJsonDataValori + for (int j = 0; j < maxJsonDataEv; j++) + { + QueueIN.TryDequeue(out currVal); + listaValori.Add(currVal); + } + sendDataBlock(urlType.SignIN, listaValori); + } + else + { + // invio in blocco + listaValori = QueueIN.ToList(); + // invio + sendDataBlock(urlType.SignIN, listaValori); + // svuoto! + QueueIN = new ConcurrentQueue(); + } + } + else + { + // INVIO SINGOLO...!!! + QueueIN.TryDequeue(out currVal); + sendToMoonPro(urlType.SignIN, currVal); + } + // salvo come last signal in il currVal ultimo... SE !="" + if (!string.IsNullOrEmpty(currVal)) + { + lastSignInVal = currVal; + } + } + else + { + break; + } + } + else + { + break; + } + } + else + { + break; + } + } + } } - #endregion Private Methods + /// + /// Metodo base connessione... + /// + public virtual void tryConnect() + { + dtAvvioAdp = DateTime.Now; + } + + /// + /// Metodo base disconnessione... + /// + public virtual void tryDisconnect() + { + } + + /// + /// Effettua verifica se abilitato invio pezzi in blocco e nel caso + /// - invio in blocco pezzi + /// - aggiornamento del contapezzi (passato come ref) x nuovo valore post invio + /// + public void trySendPzCountBlock() + { + // in primis HA SENSO procedere SOLO SE server MP è Online... + if (MPOnline) + { + // SOLO SE online la macchina... + if (IobOnline) + { + int numIncr = 0; + int qtyAdded = 0; + // verifico se la funzione SIA abilitata + if (enableSendPzCountBlock) + { + int delta = contapezziPLC - contapezziIOB; + // se è abilitata verifico differenza: se ho DELTA > minSendPzCountBlock --> + // invio un blocco <= maxSendPzCountBlock + if (delta > minSendPzCountBlock) + { + // init obj display + newDisplayData currDispData = new newDisplayData(); + // resta indietro di ALMENO minSendPzCountBlock pezzi x recuperare 1:1... + numIncr = delta > maxSendPzCountBlock + minSendPzCountBlock ? maxSendPzCountBlock : delta - minSendPzCountBlock; + // invio il num max di pezzi ammesso in blocco! + lastUrl = $"{urlAddPzCount}{numIncr}"; + string resp = utils.callUrlNow(lastUrl); + if (!string.IsNullOrEmpty(resp)) + { + // dalla risposta (come numero) capisco SE ha aggiunto i pezzi (e quanti) + int.TryParse(resp, out qtyAdded); + if (qtyAdded > 0) + { + // aggiorno IL MIO contapezzi... + contapezziIOB += qtyAdded; + lgInfo($"Inviato incremento contapezzi: send: {numIncr} | resp: {qtyAdded} | contapezziIOB: {contapezziIOB}"); + // invio conferma contapezzi.. + string retVal = utils.callUrl($"{urlSetPzCount}{contapezziIOB}"); + // verifica se tutto OK + if (retVal != contapezziIOB.ToString()) + { + // errore salvataggio contapezzi + lgError($"trySendPzCountBlock: errore salvataggio contapezzi: contapezziIOB {contapezziIOB} | risposta: {retVal}"); + } + } + else + { + lgError($"Richiesto incremento {numIncr} ma NON registrato su server MP-IO"); + } + } + currDispData.newUrlCallData = lastUrl; + currDispData.counter = contapezziIOB; + currDispData.semOut = Semaforo.SV; + raiseRefresh(currDispData); + } + } + } + else + { + lgError("Impossibile trySendPzCountBlock: IobOnline è false"); + } + } + else + { + lgError("Impossibile trySendPzCountBlock: MPOnline è false"); + } + } + + /// + /// Inserimento/aggiornamento chiavi/valore in currProdData + /// + /// + /// + public void upsertKey(string chiave, string valore) + { + if (currProdData.ContainsKey(chiave)) + { + currProdData[chiave] = valore; + } + else + { + currProdData.Add(chiave, valore); + } + } + + /// + /// Formatta URL x invio in DataBlock Json dei dati FLog / eventi + /// + /// + /// + public string urlDataBlock(urlType tipoUrl) + { + // verifico la parte di link "tipoComando" + string tipoComando = ""; + switch (tipoUrl) + { + case urlType.FLog: + tipoComando = cIobConf.serverData.CMDFLOG_JSON; + break; + + case urlType.SignIN: + tipoComando = cIobConf.serverData.CMDBASE_JSON; + break; + + case urlType.RawTransf: + tipoComando = cIobConf.serverData.CMDRAWTRANSF_JSON; + break; + + case urlType.ULog: + tipoComando = cIobConf.serverData.CMDULOG_JSON; + break; + + default: + break; + } + // URL base x input + string answ = $@"{cIobConf.serverData.TRANSP}://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{tipoComando}{cIobConf.codIOB}"; + return answ; + } + + /// + /// Fornisce URL di tipo FluxLog + /// + /// valore salvato in coda nel formato dtEve#flux#valore#counter + /// + public string urlFLog(string queueVal) + { + // URL base x input + string answ = $@"{cIobConf.serverData.TRANSP}://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDFLOG}"; + // decodifica valore! + string[] valori = qDecodeIN(queueVal); + // aggiungo macchina e valore... + answ += string.Format(@"{0}?flux={1}&&valore={2}", cIobConf.codIOB, valori[1], valori[2]); + // aggiondo dataOra evento e corrente + contatore... + answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[3]); + return answ; + } + + /// + /// Fornisce URL INPUT per i parametri richiesti + /// + /// valore salvato in coda formato dtEve#valore#counter + /// + public string urlInput(string queueVal) + { + // URL base x input + string answ = $@"{cIobConf.serverData.TRANSP}://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDBASE}"; + // decodifica valore! + string[] valori = qDecodeIN(queueVal); + // aggiungo macchina e valore... + answ += string.Format(@"{0}?valore={1}", cIobConf.codIOB, valori[1]); + // aggiondo dataOra evento e corrente + contatore... + answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[2]); + return answ; + } + + /// + /// Fornisce URL di tipo UserLog + /// + /// valore salvato in coda nel formato dtEve#flux#valore#counter + /// + public string urlULog(string queueVal) + { + // URL base x input + string answ = $@"{cIobConf.serverData.TRANSP}://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDULOG}"; + // decodifica valore! + string[] valori = qDecodeIN(queueVal); + // aggiungo macchina e valore... + answ += string.Format(@"{0}?flux={1}&&valore={2}", cIobConf.codIOB, valori[1], valori[2]); + // aggiondo dataOra evento e corrente + contatore... + answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[3]); + return answ; + } + + #endregion Public Methods + + #region Internal Properties + + internal bool disDynDataRangeCheck { get; set; } = false; + + #endregion Internal Properties + + #region Protected Fields + + /// + /// wrapper di log + /// + protected static Logger lg; + + /// + /// Valore di attesa (random) dopo ogni invio x evitare congestione send... + /// + protected static int urlRandWait = 0; + + protected bool _connOk = false; + + /// + /// valore booleano di check se sia in fase di COMUNICAZIONE ATTIVA con il PLC/NC + /// + protected bool adpCommAct; + + /// + /// porta x adapter (x restart) + /// + protected int adpPortNum; + + /// + /// DataOra ultimo avvio adapter x watchdog + /// + protected DateTime adpStartRun; + + /// + /// Vettore 32 BIT valori in ingresso al filtro + /// + protected int B_input; + + /// + /// Vettore 32 BIT valori in uscita dal filtro + /// + protected int B_output; + + /// + /// Vettore 32 BIT valori precedenti + /// + protected int B_previous; + + /// + /// Num errori check alive + /// + protected int currAliveErrors = 0; + + /// + /// Dizionario valori impostati x produzione + /// + protected Dictionary currProdData = new Dictionary(); + + /// + /// num corrente errori read PLC + /// + protected int currReadErrors = 0; + + /// + /// num errori send + /// + protected int currSendErrors = 0; + + /// + /// Fattore di demoltiplicazione dei DynData x ridurre campionamento + /// + protected int demFactDynData = 1; + + /// + /// Array dei contatori x segnali blinking + /// + protected int[] i_counters; + + /// + /// Indica impianto IN SETUP (fino a quando SMETTE di esserlo...) + /// + protected bool inSetup = false; + + /// + /// ultimo tentativo connessione... + /// + protected DateTime lastConnectTry; + + /// + /// Ultimo LOG registrazione avvio (x ridurre log notturni...) + /// + protected DateTime lastLogStartup = DateTime.Today.AddHours(-1); + + /// + /// Dizionario ULTIMI valori impostati x produzione + /// + protected Dictionary lastProdData = new Dictionary(); + + /// + /// Ultimo invio contapezzi (x invio delayed) + /// + protected DateTime lastPzCountSend; + + /// + /// Dizionario ultimi valori (string) delle TSS + /// + protected Dictionary LastTSS = new Dictionary(); + + /// + /// Dizionario ultimi valori (string) delle TSS + /// + protected Dictionary LastTSSSend = new Dictionary(); + + /// + /// Dizionario ultimi valori (double) delle TSVC + /// + protected Dictionary LastTSVC = new Dictionary(); + + /// + /// Ultima registrazione warning x ODL mancante (x scrivere solo ogni 15 secondi) + /// + protected DateTime lastWarnODL; + + /// + /// Num massimo di errori in funzionalità check alive + /// + protected int maxAliveErrors = utils.CRI("maxAliveErrors"); + + /// + /// Soglia massima errori priam di disconnesisone automatica + /// + protected int maxErroriCheck = 100; + + /// + /// Num massimo di errori di rete read (dal PLC) + /// + protected int maxReadErrors = utils.CRI("maxReadErrors"); + + /// + /// Num massimodi errori di rete send al server + /// + protected int maxSendErrors = utils.CRI("maxSendErrors"); + + /// + /// indica se serva refresh parametri e quindi PLC... + /// + protected bool needRefresh = true; + + /// + /// Variabile numero errori vari (in lettura) --> se supera soglia maxErroriCheck --> disconnette + /// + protected int numErroriCheck = 0; + + /// + /// Form chiamante + /// + protected AdapterForm parentForm; + + /// + /// Timeout x ping al server + /// + protected int pingServerMsTimeout = utils.CRI("pingMsTimeout"); + + /// + /// Ritardo minimo x invio contapezzi + /// + protected int pzCountDelay; + + /// + /// Dizionario di VC da trattare come TimeSeries (con conf decodificata + processing successivo...) + /// + protected Dictionary TSVC_Data = new Dictionary(); + + /// + /// Dizionario di VARIABILI da trattare come eventi (da inviare quando cambiano oppure a + /// scadenza periodo...) + /// + protected Dictionary VarArray = new Dictionary(); + + /// + /// Veto per registrazione completa log di startup (minuti) + /// + protected int vetoLogStartupDuration = 60; + + /// + /// Periodo wathdog di default (2 sec se non specificato) + /// + protected int watchDogPeriod = 2; + + #endregion Protected Fields + + #region Protected Properties + + /// + /// Valore del num max invii consecutivi da coda... + /// + protected static int nMaxSend + { + get + { + int answ = 5; + try + { + answ = utils.CRI("nMaxSend"); + } + catch + { } + return answ; + } + } + + /// + /// Indica il counter della key richiesta attiva + /// - gestito tramite Redis + /// - a scadenza 25h + /// - incrementato ogni invio di auto ODL + /// + protected int countKeyRichiesta + { + get + { + // calcolo key odierna + int answ = redisMan.getKReqCount(dailyKey); + return answ; + } + set + { + // calcolo key odierna + redisMan.setKReqCount(dailyKey, value); + } + } + + protected string dailyKey + { + get + { + return DateTime.Today.ToString("yyMMdd"); + } + } + + /// + /// Variabile di appoggio GLOBALE x indicare che si può forzare reset contapezzi con + /// macchina in RUN + /// + protected bool forceResetInRun { get; set; } = false; + + /// + /// Variabile di appoggio GLOBALE x indicare macchina RUN (es x gestione su reset pezzi) + /// + protected bool isRunning { get; set; } = false; + + /// + /// Valore limite MASSIMO di invio di dati come array Json + /// + protected int maxJsonData { get; set; } = utils.CRI("maxJsonData"); + + /// + /// Valore limite MASSIMO di invio di dati come array Json x EVENTI + /// + protected int maxJsonDataEv { get; set; } = utils.CRI("maxJsonDataEv"); + + /// + /// Max tentativi ping permessi (default: 5) + /// + protected int maxPingRetry { get; set; } = 5; + + /// Coda massima ammessa per FLog (se <=0 disattivata...) + protected int maxQueueFLog { get; set; } = utils.CRI("maxQueueFLog"); + + /// Coda massima ammessa per FLog (se <=0 disattivata...) + protected int maxQueueRawTransf { get; set; } = utils.CRI("maxQueueRawTransf"); + + /// + /// Valore MINIMO limite x decidere invio di dati come array Json + /// + protected int minJsonData { get; set; } = utils.CRI("minJsonData"); + + protected string nextKeyRich + { + get + { + return $"{dailyKey}{countKeyRichiesta:00}"; + } + } + + /// + /// Numero letture IN da avvio + /// + protected int nReadFilt { get; set; } + + /// + /// Numero letture IN da avvio + /// + protected int nReadIN { get; set; } + + /// + /// Numero invii OUT (svuotamento coda) + /// + protected int nSendOut { get; set; } + + /// + /// Numero simulazioni ammesse... + /// + protected int numSim { get; set; } + + /// + /// Indica se sia stato resettato un contapezzi + /// + protected bool pzCountResetted { get; set; } = false; + + /// + /// Fornisce il valore letto da BITMAP in formato valido x messa in coda nel formato dtEve#value#cont + /// + protected string qEncodeIN + { + get + { + string answ = ""; + try + { + answ = string.Format("{0:yyyyMMddHHmmssfff}#{1:X2}#{2}", DateTime.Now, B_output, counterSigIN); + } + catch + { } + return answ; + } + } + + /// + /// Indica se vada inviata la key richiesta con lo split/autoODL + /// + protected bool sendKeyRichiesta { get; set; } = false; + + /// + /// test ping all'indirizzo PLC/CNC impostato nei parametri + /// + /// + protected IPStatus testPingMachine + { + get + { + IPStatus answ = IPStatus.Unknown; + // se disabilitato salto... + if (pingDisabled) + { + answ = IPStatus.Success; + } + else + { + IPAddress address; + PingReply reply; + using (Ping pingSender = new Ping()) + { + address = IPAddress.Loopback; + int pingMsTimeout = cIobConf.pingMsTimeout; + IPAddress.TryParse(cIobConf.cncIpAddr, out address); + try + { + // se != null --> uso address... + if (address != null) + { + reply = pingSender.Send(address, pingMsTimeout); + } + else + { + reply = pingSender.Send(cIobConf.cncIpAddr, pingMsTimeout); + } + } + catch + { + reply = pingSender.Send(IPAddress.Loopback, pingMsTimeout); + } + answ = reply.Status; + } + } + return answ; + } + } + + /// + /// Secondi standard x veto check status e log + /// + protected int vetoSeconds { get; set; } = utils.CRI("vetoSeconds"); + + #endregion Protected Properties #region Protected Methods /// - /// Decodifica file MAP (caso .bit) + /// Decodifica file MAP (caso .bit) /// /// /// @@ -2519,10 +4204,7 @@ namespace IOB_WIN_NEXT } /// - /// Decodifica valore della coda IN nel formato - /// answ[0]=dtEve - /// answ[1]=valore - /// answ[2]=counter + /// Decodifica valore della coda IN nel formato answ[0]=dtEve answ[1]=valore answ[2]=counter /// /// dtEve + '#' + value + '#' + cont /// @@ -2555,7 +4237,7 @@ namespace IOB_WIN_NEXT } answ = utils.callUrlNow(url2call); // se vuoto faccio seconda prova... - if (string.IsNullOrEmpty(answ)) + if (string.IsNullOrEmpty(answ) || answ == "[]") { answ = utils.callUrlNow(url2call); } @@ -2567,8 +4249,8 @@ namespace IOB_WIN_NEXT /// - formato Json /// - array di KVP / Dictionary /// - formato definito da API x MP/IO/: - /// - KEY: task - /// - VALUE: array JSon KVP + /// - KEY: task + /// - VALUE: array JSon KVP /// protected string getTask2exe() { @@ -2708,6 +4390,19 @@ namespace IOB_WIN_NEXT sendToLogWatch("INFO", message); } } + + /// + /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + /// + protected void lgInfo(string message, params object[] args) + { + lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; + lg.Info(message, args); + sendToLogWatch("INFO", message, args); + } + protected void lgInfoStartup(string message, bool sendToForm = true) { lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; @@ -2728,17 +4423,6 @@ namespace IOB_WIN_NEXT } } - /// - /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere... - /// - /// - /// - protected void lgInfo(string message, params object[] args) - { - lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; - lg.Info(message, args); - sendToLogWatch("INFO", message, args); - } /// /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere... /// @@ -2863,8 +4547,7 @@ namespace IOB_WIN_NEXT } /// - /// Lettura memorie conf speciali (json) - /// ...SE inserito in [OPTPAR] come PARAM_CONF=nome.json + /// Lettura memorie conf speciali (json) ...SE inserito in [OPTPAR] come PARAM_CONF=nome.json /// protected virtual void loadMemConf() { @@ -2886,11 +4569,19 @@ namespace IOB_WIN_NEXT lgError("loadMemConf: parametro ENABLE_SEND_PZC_BLOCK non trovato, verificare anche MAX_SEND_PZC_BLOCK e MIN_SEND_PZC_BLOCK"); } + // disabilitazione controllo range valori DynData + if (!string.IsNullOrEmpty(getOptPar("disDynDataRangeCheck"))) + { + bool checkDis = false; + bool.TryParse(getOptPar("disDynDataRangeCheck"), out checkDis); + disDynDataRangeCheck = checkDis; + } + // inizializzo LUT decodifica PARAMETRI string jsonParams = getOptPar("PARAM_CONF"); if (!string.IsNullOrEmpty(jsonParams)) { - string jsonFileName = $"{Application.StartupPath}/DATA/CONF/{jsonParams}"; + string jsonFileName = $"{Application.StartupPath}\\DATA\\CONF\\{jsonParams}"; lgInfoStartup($"Apertura file {jsonFileName}"); StreamReader reader = new StreamReader(jsonFileName); string jsonData = reader.ReadToEnd(); @@ -3186,6 +4877,7 @@ namespace IOB_WIN_NEXT /// protected void setupMemMap() { + bool serverOk = testPingServer == IPStatus.Success; lgInfo($"setupMemMap | trovati {memMap.mMapRead.Count} parametri Read (TSVC)"); lgInfo($"setupMemMap | trovati {memMap.mMapWrite.Count} parametri Write"); if (utils.CRB("verbose")) @@ -3228,7 +4920,15 @@ namespace IOB_WIN_NEXT { // invio su cloud conf memoria... string rawData = JsonConvert.SerializeObject(memMap, Formatting.Indented); - var resp = utils.callUrlNow($"{urlSaveMemMap}", rawData); + // controllo ping al server... + if (serverOk) + { + var resp = utils.callUrlNow($"{urlSaveMemMap}", rawData); + } + else + { + lgInfo($"Mancata risposta ping da server, salato step invio memMpa a {urlSaveMemMap}"); + } // salvo ANCHE come parametri i valori... objItem currItem = new objItem(); List allParam = new List(); @@ -3249,22 +4949,34 @@ namespace IOB_WIN_NEXT // valori READ foreach (var item in memMap.mMapRead) { - currItem = new objItem() + // se non ci fosse aggiungo + var trovato = allParam.FirstOrDefault(x => x.uid == item.Value.name); + if (trovato == null) { - uid = item.Value.name, - name = !string.IsNullOrEmpty(item.Value.description) ? item.Value.description : item.Value.name, - writable = false, - UM = item.Value.unit, - valMin = item.Value.minVal, - valMax = item.Value.maxVal - }; - allParam.Add(currItem); + currItem = new objItem() + { + uid = item.Value.name, + name = !string.IsNullOrEmpty(item.Value.description) ? item.Value.description : item.Value.name, + writable = false, + UM = item.Value.unit, + valMin = item.Value.minVal, + valMax = item.Value.maxVal + }; + allParam.Add(currItem); + } } - // invio su cloud parametri SE sono connesso... - if (connectionOk) + // invio su cloud parametri SE sono connesso all'OPC-ua... + if (serverOk) { rawData = JsonConvert.SerializeObject(allParam, Formatting.Indented); - utils.callUrl($"{urlSaveAllParams}", rawData); + if (serverOk) + { + var resp = utils.callUrl($"{urlSaveAllParams}", rawData); + } + else + { + lgInfo($"Mancata risposta ping server, non effettuata chiamata {urlSaveAllParams}"); + } } lgInfo($"setupMemMap | salvata conf memoria R/W"); } @@ -3272,2193 +4984,701 @@ namespace IOB_WIN_NEXT #endregion Protected Methods - #region Public Methods + #region Private Properties /// - /// Effettua chiamata URL e restituisce risultato + /// Verifica se la IOB sia ENABLED (da server o Demo) /// - /// - /// invio in modalità async (NON GARANTITO ordine...) - /// - public static string callUrl(string URL, bool doAsync) + private bool checkIobEnabled { - string answ = ""; - // Chiamata ASINCRONA - if (doAsync) + get { - //Task resp = utils.callUrlAsync(URL); - //answ = resp.Result; - answ = utils.callUrlAsync(URL); - if (urlRandWait > 0) + bool answ = false; + // controllo se ho veto al check... + if (dtVetoCheckIOB < DateTime.Now) { - Random rnd = new Random(); - Thread.Sleep(rnd.Next(urlRandWait / 10, urlRandWait)); - } - } - // chiamata SOLO NORMALE SINCRONA... - else - { - answ = utils.callUrl(URL); - if (urlRandWait > 0) - { - Random rnd = new Random(); - Thread.Sleep(rnd.Next(urlRandWait / 10, urlRandWait)); - } - } - return answ; - } - - /// - /// Effettua chiamata URL e restituisce risultato - /// - /// - /// - /// invio in modalità async (NON GARANTITO ordine...) - /// - public static string callUrlWithPayload(string URL, string payload, bool doAsync) - { - string answ = ""; - // Chiamata ASINCRONA - if (doAsync) - { - answ = utils.callUrlAsync(URL, payload); - if (urlRandWait > 0) - { - Random rnd = new Random(); - Thread.Sleep(rnd.Next(urlRandWait / 10, urlRandWait)); - } - } - // chiamata SOLO NORMALE SINCRONA... - else - { - answ = utils.callUrl(URL, payload); - if (urlRandWait > 0) - { - Random rnd = new Random(); - Thread.Sleep(rnd.Next(urlRandWait / 10, urlRandWait)); - } - } - return answ; - } - - /// - /// processa dataLayer e se necessario salva/mostra - /// - public static void checkSavePersDataLayer() - { - } - - public static string GetMACAddress() - { - NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); - String sMacAddress = string.Empty; - foreach (NetworkInterface adapter in nics) - { - if (string.IsNullOrEmpty(sMacAddress))// only return MAC Address from first card - { - IPInterfaceProperties properties = adapter.GetIPProperties(); - //sMacAddress = adapter.GetPhysicalAddress().ToString(); - sMacAddress = string.Join(":", (from z in adapter.GetPhysicalAddress().GetAddressBytes() select z.ToString("X2")).ToArray()); - } - } - return sMacAddress; - } - - public static void resetDebugConsole() - { - } - - /// - /// Reset dei webclients - /// - public static void resetWebClients() - { - utils.resetWebClients(); - } - - /// - /// Accumula in coda i valori ALARM e logga... - /// - /// VALORE RAW (x display) - /// VALORE già processato con qEncodeFLog(...) - public void accodaAlarmLog(string val, string encodedVal) - { - // mostro dati variati letti... - displayOtherData(val); - // accodo IN PRIMIS al FluxLog --> accodo (valore già formattato)! - QueueFLog.Enqueue(encodedVal); - // accodo ANCHE alla coda allarmi che trasmetterò SOLO SE a scadenza impostata (10 sec?) ho allarmi perdurati... - - // loggo! - lgInfo(string.Format("[QUEUE-ALARM-LOG] {0}", encodedVal)); - counterFLog++; - if (counterFLog > 9999) - { - counterFLog = 0; - } - } - - /// - /// Accumula in coda i valori Flux Log e logga... - /// - /// VALORE RAW (x display) - /// VALORE già processato con qEncodeFLog(...) - public void accodaFLog(string val, string encodedVal) - { - // mostro dati variati letti... - displayOtherData(val); - // --> accodo (valore già formattato)! - QueueFLog.Enqueue(encodedVal); - // se abilitato controllo coda FLog (superiore a 0...) - if (maxQueueFLog > 0) - { - // se ho una coda superiore a max ammesso - if (QueueFLog.Count > maxQueueFLog) - { - // elimino valori iniziali fino a tornare al max ammesso... - while (QueueFLog.Count > maxQueueFLog) + if (DemoOut) { - string currVal = ""; - QueueFLog.TryDequeue(out currVal); - lgInfo($"Eliminazione da coda FLog per superamento maxLengh: {currVal}"); - } - } - } - // loggo! - lgTrace(string.Format("[QUEUE-FLOG] {0}", encodedVal)); - counterFLog++; - if (counterFLog > 9999) - { - counterFLog = 0; - } - } - - /// - /// Accumula in coda i valori RawData logga... - /// - /// Dictionary pronto x invio - public void accodaRawData(Dictionary sendObj) - { - // - - /*-------------------------------- - * nuova gestione coda dictionary - * fixme todo da fare !!! - * - * - conterrà una lista di oggetti baseRawTransf - * - i dati vanno poi "scodati" dal + vecchio ed inviati a MP/IO - * - mostra un sunto delle info da inviare - * - accodamento vero e proprio - * - verifica (opzionale) coda massima x gestire roundRobin ultimi eventi - * - trace della coda - * - counter invio??? valutare se c'è dataora e poi sono da salvare su MongoDb / Redis - * - * */ - -#if false - // mostro dati variati letti... - displayOtherData(val); - // --> accodo (valore già formattato)! - QueueFLog.Enqueue(encodedVal); - // se abilitato controllo coda FLog (superiore a 0...) - if (maxQueueFLog > 0) - { - // se ho una coda superiore a max ammesso - if (QueueFLog.Count > maxQueueFLog) - { - // elimino valori iniziali fino a tornare al max ammesso... - while (QueueFLog.Count > maxQueueFLog) - { - string currVal = ""; - QueueFLog.TryDequeue(out currVal); - lgInfo($"Eliminazione da coda FLog per superamento maxLengh: {currVal}"); - } - } - } - // loggo! - lgTrace(string.Format("[QUEUE-FLOG] {0}", encodedVal)); - counterFLog++; - if (counterFLog > 9999) - { - counterFLog = 0; - } -#endif - } - - /// - /// Accoda (visualizzando in cima allo stack) la nuova stringa di output per area OTHER DATA - /// - /// - public void accodaOtherData(string newLine) - { - // inserisco in cima allo stack, trimmo e aggiorno display - string strOtherData = limitLine2show(string.Format("{0}{1}{2}", newLine, Environment.NewLine, parentForm.dataMonitor_3)); - //parentForm.dataMonitor_3 = strOtherData; - parentForm.WriteTextSafe(strOtherData); - } - - /// - /// Accumula in coda i valori Signal IN e logga... - /// Parametri da aggiornare x display in form - /// - public void accodaSigIN(ref newDisplayData currDispData) - { - // mostro dati variati letti... - displayInData(ref currDispData); - // verifico veto a invio status macchina - string keyName = "VETO_SIG_IN"; - if (getOptPar(keyName).ToUpper() == "TRUE") - { - lgTrace($"Filtrato accodamento valore da conf IOB | {keyName} | [QUEUE-IN] {qEncodeIN}"); - } - else - { - // --> accodo (valore già formattato)! - QueueIN.Enqueue(qEncodeIN); - // loggo! - lgTrace(string.Format("[QUEUE-IN] {0}", qEncodeIN)); - } - // aggiorno counters ed eventuale reset - nReadFilt++; - if (nReadFilt > int.MaxValue - 1) - { - nReadFilt = 0; // per evitare buffer overflow... - } - - counterSigIN++; - if (counterSigIN > 9999) - { - counterSigIN = 0; - } - } - - /// - /// Accumula in coda i valori USER LOG e logga... - /// - /// VALORE RAW (x display) - /// VALORE già processato con qEncodeULog(...) - public void accodaUserLog(string val, string encodedVal) - { - // mostro dati variati letti... - displayOtherData(val); - // accodo IN PRIMIS al FluxLog --> accodo (valore già formattato)! - QueueULog.Enqueue(encodedVal); - - // loggo! - lgInfo(string.Format("[QUEUE-USER-LOG] {0}", encodedVal)); - counterULog++; - if (counterULog > 9999) - { - counterFLog = 0; - } - } - - /// - /// Update visualizzaizone BIT in ingresso - /// Parametri da aggiornare x display in form - /// - public void displayInData(ref newDisplayData currDispData) - { - if (currDispData != null) - { - // mostro update... - string newString = string.Format("{0:0000}|{1}", counterSigIN, utils.IntToBinStr(B_output, 8)); - currDispData.newSignalData = newString; - } - } - - /// - /// Mostra cosa ha/avrebbe inviato - /// - /// - public void displayOtherData(string newData) - { - // mostro update... - accodaOtherData(newData); - } - - /// - /// Esecuzione dei task richiesti e pulizia coda richieste eseguite - /// - /// - public virtual Dictionary executeTasks(Dictionary task2exe) - { - // Verificare il protocollo: dovrebbe togliere SOLO i task eseguiti... - Dictionary taskDone = new Dictionary(); - if (task2exe != null) - { - // controllo se memMap != null... - if (memMap != null) - { - bool taskOk = false; - string taskVal = ""; - // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4 - foreach (var item in task2exe) - { - taskOk = false; - taskVal = ""; - // converto richiesta in enum... - taskType tName = taskType.nihil; - Enum.TryParse(item.Key, out tName); - // controllo sulla KEY... - switch (tName) - { - case taskType.nihil: - case taskType.fixStopSetup: - case taskType.forceSetPzCount: - case taskType.sendWatchDogMes2Plc: - taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; - lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - - case taskType.setArt: - case taskType.setComm: - case taskType.setProg: - case taskType.setPzComm: - // recupero dati da memMap... - if (memMap != null && memMap.mMapWrite != null) - { - if (memMap.mMapWrite.ContainsKey(item.Key)) - { - dataConf currMem = memMap.mMapWrite[item.Key]; - string addr = currMem.memAddr; - taskVal = $"SET task: {item.Key} --> {item.Value} | mem: {currMem.memAddr} - {currMem.size} byte"; - // salvo il nuovo valore nella memoria... così prox invio lo trasmetterà - memMap.mMapWrite[item.Key].value = item.Value; - } - else - { - taskVal = $"NO DATA MEM, SET task: {item.Key} --> {item.Value}"; - } - } - else - { - taskVal = $"NO MemMap found, SET task: {item.Key} --> {item.Value}"; - } - // salvo in currProd.. - saveProdData(new KeyValuePair(item.Key, item.Value)); - - break; - - case taskType.forceResetPzCount: - // reset contapezzi inizio setup - taskOk = resetcontapezziPLC(); - taskVal = taskOk ? "RESET PZ COUNT OK" : "PZ RESET DISABLED | NO EXEC"; - lgInfo($"Chiamata forceResetPzCount: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - - case taskType.startSetup: - // reset contapezzi inizio setup - taskOk = resetcontapezziPLC(); - taskVal = taskOk ? "RESET: SETUP START" : "PZ RESET DISABLED | NO EXEC"; - lgInfo($"Chiamata startSetup: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - - case taskType.stopSetup: - // reset contapezzi fine setup SE ESPLICITAMENTE IMPOSTATO - if (cIobConf.optPar.Count > 0 && getOptPar("ENABLE_PZ_RESET_stopSetup") == "TRUE") - { - taskOk = resetcontapezziPLC(); - } - taskVal = taskOk ? "RESET: SETUP END" : "PZ RESET DISABLED | NO EXEC"; - lgInfo($"Chiamata stopSetup: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - - case taskType.setParameter: - // richiedo da URL i parametri WRITE da popolare - lgInfo("Chiamata setParameter --> processMemWriteRequests"); - taskVal = processMemWriteRequests(); - // se restituiscce "" faccio altra prova... - if (string.IsNullOrEmpty(taskVal)) - { - // i parametri me li aspetto come stringa composta paramName|paramvalue - if (item.Value.Contains("|")) - { - string[] paramsJob = item.Value.Split('|'); - taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}"; - } - else - { - taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value"; - } - } - break; - - default: - taskVal = "SKIPPED | NO EXEC"; - lgInfo($"Chiamata default senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - } - // aggiungo task! - taskDone.Add(item.Key, taskVal); - } - } - else - { - lgError($"Attenzione! memMap è nullo, non posso eseguire task2exe!"); - } - } - - return taskDone; - } - - /// - /// Effettua verifica delle memorie WRITE, se ci siano variazioni da riportare verso il PLC - /// Da impiegare ad esempio in caso di chiamate complesse (ad 2 aree di memoria condivise sul PLC; coem commessa + articolo EWON) - /// - /// - /// Cerca parametri opzionali in modalità "like" del nome - /// - /// - /// - public Dictionary findOptPar(string keyStartSearch = "") - { - Dictionary answ = new Dictionary(); - // controllo SE keySearch !="" - if (!string.IsNullOrWhiteSpace(keyStartSearch)) - { - if (cIobConf.optPar.Count > 0) - { - // ciclo su tutti e cerco occorrenze che INIZINO... - foreach (var item in cIobConf.optPar) - { - if (item.Key.StartsWith(keyStartSearch)) - { - answ.Add(item.Key, item.Value); - } - } - } - } - return answ; - } - - /// - /// forza reset ODL - /// - public void forceResetOdl() - { - lgInfo("Registrato richiesta forzatura reset ODL"); - pzCountResetted = true; - } - - /// - /// Effettua chiamata x split ODL - /// - /// - public bool forceSplitOdl() - { - bool fatto = false; - if (vetoSplit < DateTime.Now) - { - lgInfo("Richiesto forceSplitOdl"); - // imposto veto x 1 minuto ad altre chiamate... - vetoSplit = DateTime.Now.AddMinutes(1); - // eseguo SOLO SE sono online... - if (MPOnline && IobOnline) - { - string fullUrl = ""; - string rawSplit = ""; - string IOB_MULTI_CNAME = ""; - string[] elencoMulti = null; - - try - { - /*************************************************** - * Descrizione procedura (OK X SIMULATORI...) - * - * - chiamata su MP/IO - * - verifica che su DB sia abilitato AUTO ODL - * - il server inserisce un evento fine prod HW 1 minuto prima e inizio setup HW - * - viene duplicato e chiuso ODL corrente - * - viene fatto partire ODL nuovo ADESSO - * - num pezzi come ODL precedente (o da media 3 ODL precedenti) - * - conferme pezzi & co... gestione NULL (NON SERVONO si tratta di impianti SENZA gestione vera ODL) - * - reset contapezzi PLC locale... - * - * - * - * DA VALUTARE (x macchine tipo linea con + impianti... es valvital) SE - * - creare una gestione ALTERNATIVA sul server che preveda impianto LEADER e impianti follower (RIGIDAMENTE CONFIGURATI) - * - ogni volta che si fa setup LEADER --> si ripete su impianti FOLLOWER (eventi!!!) - * - viene fatto reset contapezzi sui follower (+ altre operazioni opzionali, ES imposstazione nome commessa, quantità, articolo...) - * - viene fatto reset + nuovo ODL (con stessi articoli e quantità) su follower, SENZA avere gestione x ODL di un codice esterno (quindi registra TUTTO ma NON RITORNERA' dati non avendo link verso esterno) - * - serve NUOVA TABELLA delle macchine LEADER | FOLLOWER (1:n) e gestione da MP/IO - * - * ***************************************************/ - - if (isMulti) - { - // devo chiamare cambio ODL x OGNI tavola: mi servono i parametri opzionali... - IOB_MULTI_CNAME = getOptPar("IOB_MULTI_CNAME"); - elencoMulti = IOB_MULTI_CNAME.Split(','); - } - // se normale splitto! - if (!isMulti) - { - // invio chiamata URL x reset ODL su macchina - rawSplit = callUrl(urlForceSplit, false); - fatto = (rawSplit != "KO") ? true : false; - } - // se multi gestisco il bit delle tavole... - else - { - foreach (string item in elencoMulti) - { - // invio chiamata URL x reset ODL su macchina, ATTENZIONE scriviamo | al posto di "#" che in URL sarebbe filtrato... - fullUrl = $"{urlForceSplit}&multi={item}"; - rawSplit = callUrl(fullUrl, false); - lgDebug($"Esecuzione forceSplit | URL: {fullUrl} | esito: {rawSplit}"); - } - fatto = (rawSplit == "OK") ? true : false; - } - } - catch (Exception exc) - { - lgError($"Eccezione in forceSplitOdl{Environment.NewLine}{exc}"); - } - // se fatto --> resetto contapezzi!!! - if (fatto) - { - contapezziPLC = 0; - contapezziIOB = 0; - } - } - else - { - lgError("Richiesto forceSplitOdl ma MP/IOB offline --> NON eseguito"); - } - } - else - { - lgError("Richiesto forceSplitOdl ma veto attivo --> NON eseguito"); - } - return fatto; - } - - /// - /// effettua recupero dati ed invio valori modificati... - /// - /// - public void getAndSend(gatherCycle ciclo) - { - // init obj display - newDisplayData currDispData = new newDisplayData(); - // IN OGNI CASO a prima di tutto EFFETTUO GESTIONE INVII dati da code!!! - try - { - trySendValues(); - } - catch (Exception exc) - { - lgError(exc, "Errore in gestione svuotamento/invio preliminare code memoria"); - currDispData.semOut = Semaforo.SR; - } - // controllo connessione/connettività - if (connectionOk) - { - // controllo non sia già in esecuzione... - if (!adpCommAct) - { - // provo ad avviare - try - { - // imposto flag adapter running.. - adpCommAct = true; - adpStartRun = DateTime.Now; - } - catch (Exception exc) - { - string errore = $"Adapter NOT STARTED!!!{Environment.NewLine}{exc}"; - adpCommAct = false; - adpStartRun = DateTime.Now; - currDispData.newLiveLogData = errore; - } - if (adpCommAct) - { - // try / catch generale altrimenti segno che è disconnesso... - try - { - bool showDebugData = false; - if (ciclo == gatherCycle.VHF) - { - processVHF(); - } - // processing dati memoria (lettura, filtraggio, enqueque) - else if (ciclo == gatherCycle.HF) - { - processWhatchDog(); - processAllMemory(); - processMode(); - } - else if (ciclo == gatherCycle.MF) - { - processServerRequests(); - processOverride(); - processContapezzi(); - processCncAlarms(); - processDynData(); - processMem2Write(); - } - else if (ciclo == gatherCycle.LF) - { - processCustomTaskLF(); - processOtherCounters(); - processProgram(); - // verifico se devo gestire cambio ODL in modo automatico - processAutoOdl(); - } - else if (ciclo == gatherCycle.VLF) - { - if (utils.CRB("enableContapezzi")) - { - // rilettura contapezzi da server... - lgTrace("Ciclo VLF: pzCntReload(true)"); - if (!isMulti) - { - pzCntReload(true); - } - // refresh associazione Macchina - IOB - sendM2IOB(); - } - // recupero dati SETUP (sysinfo) e li invio/mostro se variati... - processSysInfo(); - // checkLogDir x shrink! - checkShrinkDir(); - // eventuale log! - if (utils.CRB("recTime")) - { - logTimeResults(); - } - } - // mostra eventuali altri dati di processo... - reportDataProc(); - if (showDebugData) - { - // verifica se debba salvare e mostrare dati - checkSavePersDataLayer(); - } - } - catch (Exception exc) - { - // segnalo eccezione e indico disconnesso... - lgError(exc, string.Format("Errore in gestione ciclo principale ADP, fermo adapter{0}{1}", Environment.NewLine, exc)); - parentForm.fermaAdapter(true, false, true); - } - // tolgo flag running - adpCommAct = false; + answ = (QueueIN.Count + QueueFLog.Count >= nMaxSend); + IobOnline = answ; } else { - if (periodicLog) - { - lgDebug("ADP not running..."); - } - } - } - else - { - // log ADP running - lgError("Non eseguo chiamata: ADP ancora in running"); - // se è bloccato da oltre maxSec lo sblocco... - if (DateTime.Now.Subtract(adpStartRun).TotalSeconds > utils.CRI("maxAdapterLockSec")) - { - // tolgo flag running - adpCommAct = false; - adpStartRun = DateTime.Now; - } - } - } - else - { - // provo a riconnettere SE abilitato tryRestart... - if (adpTryRestart && !connectionOk) - { - // controllo se sia scaduto periodi di veto al tryConnect... - int waitRecMSec = utils.CRI("waitRecMSec") * 2; - DateTime dtVeto = lastConnectTry.AddMilliseconds(waitRecMSec); - if (DateTime.Now > dtVeto) - { - lgInfo($"Veto Time Elapsed | lastConnectTry: {lastConnectTry} | waitRecMSec {waitRecMSec} ms) | NOW tryConnect"); - lastConnectTry = DateTime.Now; - tryConnect(); - } - } - currDispData.semIn = Semaforo.SR; - processDisconnectedTask(); - } - raiseRefresh(currDispData); - } - - /// - /// Effettua processing CUSTOM x l'IOB corrente (ed invia ad IO) - /// (task svolto tipicamente ogni 5 sec se base timer 10ms, vedere app.config) - /// - public virtual void processCustomTaskLF() - { } - - /// - /// Recupera eventuali allarmi CNC... - /// - public virtual Dictionary getCncAlarms() - { - Dictionary outVal = new Dictionary(); - return outVal; - } - - /// - /// Restituisce info DINAMICHE - /// - /// - public virtual Dictionary getDynData() - { - Dictionary outVal = new Dictionary(); - return outVal; - } - - /// - /// Cerca se esiste il parametro opzionale e lo restituisce - /// - /// - /// - public string getOptPar(string key) - { - string answ = ""; - if (cIobConf.optPar.Count > 0) - { - // controllo SE HO il parametro - if (cIobConf.optPar.ContainsKey(key)) - { - answ = cIobConf.optPar[key]; - } - } - return answ; - } - - /// - /// Restituisce info OVERRIDES - /// - /// - public virtual Dictionary getOverrides() - { - Dictionary outVal = new Dictionary(); - return outVal; - } - - /// - /// Restituisce programma in esecuzione - /// - public virtual string getPrgName() - { - return ""; - } - - /// - /// Restituisce info sistema - /// - /// - public virtual Dictionary getSysInfo() - { - Dictionary outVal = new Dictionary(); - return outVal; - } - - /// - /// Recupera la VC x TS, svuotando lista e resettando periodo partenza - /// - /// Nome della VC - /// Reimposta e resetta array VC - /// - public double getVal_TSVC(string VCName, bool doReset) - { - double answ = -999999; - // cerco VC... - if (TSVC_Data.ContainsKey(VCName)) - { - try - { - switch (TSVC_Data[VCName].Funzione) - { - case VC_func.POINT: - // prendo PRIMO - answ = TSVC_Data[VCName].dataArray.FirstOrDefault(); - break; - - case VC_func.AVG: - answ = TSVC_Data[VCName].dataArray.Average(); - break; - - case VC_func.MEDIAN: - answ = TSVC_Data[VCName].dataArray.Median(); - break; - - case VC_func.MIN: - answ = TSVC_Data[VCName].dataArray.Min(); - break; - - case VC_func.MAX: - default: - answ = TSVC_Data[VCName].dataArray.Max(); - break; - } - } - catch - { } - // ora resetto... SE richiesto... - if (doReset) - { - TSVC_Data[VCName].dataArray = new List(); - TSVC_Data[VCName].DTStart = DateTime.Now; - } - } - return answ; - } - - /// - /// Recupera la VC x TS, svuotando lista e resettando periodo partenza - /// - /// Nome della VC - /// Reimposta e resetta array VC - /// - public int getVal_TSVC_int(string VCName, bool doReset) - { - int answ = 0; - // cerco VC... - if (TSVC_Data.ContainsKey(VCName)) - { - // !!!FARE!!! vero calcolo... x ora FIX a MAX... - foreach (var item in TSVC_Data[VCName].dataArray) - { - answ = (int)item > answ ? (int)item : answ; - } - // ora resetto... SE richiesto.. - if (doReset) - { - TSVC_Data[VCName].dataArray = new List(); - TSVC_Data[VCName].DTStart = DateTime.Now; - } - } - return answ; - } - - /// - /// Restituisce un payload in formato json della lista di valori ricevuta - /// - /// Tipo di URL (eventi / FLog) - /// elenco di valori da coda string salvata - /// - public string jsonPayload(urlType tipoUrl, List elencoValori) - { - string answ = ""; - if (elencoValori != null) - { - string[] valori; - int counter = 0; - DateTime dtEve = DateTime.Now; - switch (tipoUrl) - { - case urlType.FLog: - flogData currFlData = new flogData(); - flogJsonPayload fullFlObj = new flogJsonPayload(); - fullFlObj.fluxData = new List(); - // inizio processando ogni valore - foreach (var item in elencoValori) - { - valori = qDecodeIN(item); - CultureInfo provider = CultureInfo.InvariantCulture; - DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve); - int.TryParse(valori[3], out counter); - currFlData = new flogData() - { - flux = valori[1], - valore = valori[2], - dtEve = dtEve, - dtCurr = DateTime.Now, - cnt = counter - }; - fullFlObj.fluxData.Add(currFlData); - } - // conversione finale try { - answ = JsonConvert.SerializeObject(fullFlObj); - } - catch (Exception exc) - { - lgError($"FLog Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); - } - break; - - case urlType.SignIN: - evData currSigData = new evData(); - evJsonPayload fullEvObj = new evJsonPayload(); - fullEvObj.eventList = new List(); - // inizio processando ogni valore - foreach (var item in elencoValori) - { - valori = qDecodeIN(item); - CultureInfo provider = CultureInfo.InvariantCulture; - DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve); - int.TryParse(valori[2], out counter); - currSigData = new evData() + // chiamo URL, se restituisce "OK" è enabled! + string callResp = callUrl(urlIobEnabled, true); + answ = (callResp == "OK"); + // attesa casuale se necessario + var rand = new Random(); + // primi 2 test + int maxTry = 2; + while (maxTry > 0 && !answ) { - valore = valori[1], - dtEve = dtEve, - dtCurr = DateTime.Now, - cnt = counter - }; - fullEvObj.eventList.Add(currSigData); - } - // conversione finale - try - { - answ = JsonConvert.SerializeObject(fullEvObj); - } - catch (Exception exc) - { - lgError($"SignIN Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); - } - break; - - case urlType.ULog: - int numVal = 0; - int matrOp = 0; - ulogData currUlData = new ulogData(); - ulogJsonPayload fullUlObj = new ulogJsonPayload(); - fullUlObj.fluxData = new List(); - // inizio processando ogni valore - foreach (var item in elencoValori) - { - valori = qDecodeIN(item); - CultureInfo provider = CultureInfo.InvariantCulture; - DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve); - int.TryParse(valori[3], out matrOp); - int.TryParse(valori[5], out numVal); - int.TryParse(valori[6], out counter); - currUlData = new ulogData() - { - flux = valori[1], - valore = valori[2], - dtEve = dtEve, - dtCurr = DateTime.Now, - cnt = counter, - matrOpr = matrOp, - label = valori[4], - valNum = numVal - }; - fullUlObj.fluxData.Add(currUlData); - } - // conversione finale - try - { - answ = JsonConvert.SerializeObject(fullUlObj); - } - catch (Exception exc) - { - lgError($"ULog Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); - } - break; - - default: - break; - } - } - return answ; - } - - /// - /// Effettua un trim della stringa al numero max di linee da mostrare a video - /// - /// - /// - public string limitLine2show(string newString) - { - // se num righe superiore a limite trimmo... - if (newString.Split('\n').Length > parentForm.nLine2show) - { - //int idx = newString.LastIndexOf('\r'); - int idx = newString.LastIndexOf(Environment.NewLine); - newString = newString.Substring(0, idx); - } - return newString; - } - - /// - /// riporta il log di tutti i dati di results temporali registrati - /// - public void logTimeResults() - { - if (TimingData.results.Count > 0) - { - lgInfo("{0}--------------- START TIMING DATA ---------------", Environment.NewLine); - int globNumCall = 0; - TimeSpan globAvgMsec = new TimeSpan(0); - foreach (TimeRec item in TimingData.results) - { - // loggo SOLO se del mio IOB corrente... - if (item.classCall == cIobConf.codIOB) - { - lgInfo("{4}|Chiamate {0}: effettuate {1}, tempo medio {2:N2} msec | impegno canale {3:P3}", item.codCall, item.numCall, item.avgMsec, item.totMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds, cIobConf.codIOB); - globNumCall += item.numCall; - globAvgMsec += item.totMsec; - } - } - // riporto conteggio medio al secondo... - lgInfo("{4}|Chiamate GLOBALI: {0}, periodo: {1:N2} minuti.cent, tempo medio {2:N2} msec | impegno canale {3:P3}", globNumCall, DateTime.Now.Subtract(dtAvvioAdp).TotalMinutes, globAvgMsec.TotalMilliseconds / globNumCall, globAvgMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds, cIobConf.codIOB); - lgInfo("{0}--------------- STOP TIMING DATA ---------------{0}", Environment.NewLine); - // mostro in form statistiche globali! - parentForm.updateComStats(string.Format("Periodo: {0:N2}min | {1} x {2:N2}ms | canale {3:P3}", DateTime.Now.Subtract(dtAvvioAdp).TotalMinutes, globNumCall, globAvgMsec.TotalMilliseconds / globNumCall, globAvgMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds)); - } - } - - /// - /// Processa un monitoredItem, e ritorna boolean SE richiede invio (cambio o scadenza) - /// - /// - /// - /// - public bool monItem2Send(string newVal, DynDataItem item) - { - bool answ = false; - if (item != null) - { - // controllo in base al tipo di function... - switch (item.func) - { - case "SAMPLE": - // controllo se scaduto sample period... - if (item.DTScad < DateTime.Now) - { - answ = true; - } - break; - - case "CHANGE": - default: - // controllo se scaduto o se variato... - if (newVal != item.actVal || item.DTScad < DateTime.Now) - { - // aggiorno scadenza e che vada inviato - answ = true; - } - break; - } - } - return answ; - } - - /// - /// Verifica e processing x gestione ODL automatica - /// - public void processAutoOdl() - { - bool fatto = false; - if (!string.IsNullOrEmpty(getOptPar("AUTO_CHANGE_ODL"))) - { - lgTrace("Richiesta processAutoOdl"); - string IOB_MULTI_CNAME = ""; - string[] elencoMulti = null; - string fullUrl = ""; - if (isMulti) - { - // devo chiamare cambio ODL x OGNI tavola: mi servono i parametri opzionali... - IOB_MULTI_CNAME = getOptPar("IOB_MULTI_CNAME"); - elencoMulti = IOB_MULTI_CNAME.Split(','); - } - // controllo SIA abilitato... - bool doProc = false; - DateTime adesso = DateTime.Now; - bool.TryParse(getOptPar("AUTO_CHANGE_ODL"), out doProc); - if (doProc) - { - lgTrace("AUTO_CHANGE_ODL abilitato"); - bool callChangeODL = false; - // modalità change ODL - string CHANGE_ODL_MODE = "TIME"; - if (!string.IsNullOrEmpty(getOptPar("CHANGE_ODL_MODE"))) - { - CHANGE_ODL_MODE = getOptPar("CHANGE_ODL_MODE"); - } - if (CHANGE_ODL_MODE == "PZCOUNT_RESET") - { - /* verifico se sia "armato" il reset cambio ODL, DEVO essere : - * - NON in produzione - * - contapezzi ACT < contapezzi LAST - * */ - lgTrace("processAutoOdl: caso PZCOUNT_RESET"); - if ((!isRunning || forceResetInRun) && pzCountResetted) - { - callChangeODL = true; - lgInfo("Attivato cambio ODL da PZCOUNT_RESET"); - } - else - { - lgInfo($"isRunning: {isRunning} | pzCountResetted: {pzCountResetted} | forceResetInRun: {forceResetInRun} | contapezziIOB: {contapezziIOB} | contapezziPLC: {contapezziPLC}"); - } - } - else if (CHANGE_ODL_MODE == "TIME") - { - // carico i parametri di configurazione x reset ODL... - string CHANGE_ODL_HOURS = getOptPar("CHANGE_ODL_HOURS"); - string CHANGE_ODL_IDLE_MIN = getOptPar("CHANGE_ODL_IDLE_MIN"); - if (!string.IsNullOrEmpty(CHANGE_ODL_HOURS) && !string.IsNullOrEmpty(CHANGE_ODL_IDLE_MIN)) - { - int minOdlDurHours = -1; - int minPlcIdelMin = -1; - int.TryParse(CHANGE_ODL_HOURS, out minOdlDurHours); - int.TryParse(CHANGE_ODL_IDLE_MIN, out minPlcIdelMin); - // controllo parametri validi - if (minOdlDurHours > 0 && minPlcIdelMin >= 0) - { - // leggo da server inizio ODL... se non multi 1 solo... - DateTime inizioOdl = DateTime.Now; - string rawDataInizio = ""; - if (!isMulti) - { - rawDataInizio = callUrl(urlInizioOdlIob, false); - DateTime.TryParse(rawDataInizio, out inizioOdl); - } - else - { - DateTime tmpData = DateTime.Now; - // prendo il + vecchio... - foreach (var item in elencoMulti) - { - fullUrl = $"{urlInizioOdlIob}|{item}"; - rawDataInizio = callUrl(fullUrl, false); - DateTime.TryParse(rawDataInizio, out tmpData); - inizioOdl = (tmpData < inizioOdl) ? tmpData : inizioOdl; - } - } - // verifico se sia scaduto... - if (inizioOdl.AddHours(minOdlDurHours) < adesso) - { - string rawIdle = ""; - int idlePeriod = 0; - if (!isMulti) - { - // controllo SE sono fermo (spento o in manuale) per il periodo minimo richiesto... - rawIdle = callUrl(urlIdleTime, false); - int.TryParse(rawIdle, out idlePeriod); - } - else - { - int tmpIdle = 0; - // prendo il + grande... - foreach (var item in elencoMulti) - { - fullUrl = $"{urlIdleTime}|{item}"; - rawIdle = callUrl(fullUrl, false); - int.TryParse(rawIdle, out tmpIdle); - idlePeriod = tmpIdle > idlePeriod ? tmpIdle : idlePeriod; - } - } - if (idlePeriod >= minPlcIdelMin) - { - callChangeODL = true; - } - } + Thread.Sleep(rand.Next(250, 500)); + callResp = callUrl(urlIobEnabled, true); + answ = (callResp == "OK"); + maxTry--; } - } - } - - // vero processing... - if (callChangeODL) - { - lgTrace("Chiamata: processAutoOdl --> forceSplitODL"); - fatto = forceSplitOdl(); - pzCountResetted = false; - lgInfo("Esecuzione processAutoOdl completata --> pzCountResetted = false"); - } - } - else - { - lgTrace("AUTO_CHANGE_ODL DISABILITATO"); - } - } - // loggo se fatto - if (fatto) - { - lgTrace("Effettuato processAutoOdl"); - } - } - - /// - /// Effettua processing degli allarmi CNC SE disponibili - /// - public void processCncAlarms() - { - if (utils.CRB("enableAlarms")) - { - Dictionary currAlarms = new Dictionary(); - if (connectionOk) - { - currAlarms = getCncAlarms(); - } - else - { - lgError("Errore connessione mancante x getCncAlarms"); - } - // verifico SE sia cambiato il programma... - if (currAlarms.Count > 0) - { - try - { - string sVal = ""; - if (lastAlarm != currAlarms["CNC_ALARM"]) - { - // salvo! - lastAlarm = currAlarms["CNC_ALARM"]; - // per ogni valore del dizionario mostro ed accodo! - foreach (var item in currAlarms) + // se NON OK riprovo ANCORA 1 volta... + if (!answ) { - sVal = string.Format("[CNC_ALARM]{0}|{1}", item.Key, item.Value); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + resetWebClients(); + Thread.Sleep(rand.Next(250, 1000)); + callResp = callUrl(urlIobEnabled, false); + answ = (callResp == "OK"); } - } - // accodo ALTRI allarmi NON CNC... - foreach (var item in currAlarms.Where(X => X.Key != "CNC_ALARM")) - { - sVal = $"{item.Key} | {item.Value}"; - accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); - } - } - catch (Exception exc) - { - lgError("Eccezione in processCncAlarms{0}{1}", Environment.NewLine, exc); - } - } - } - } - - /// - /// Effettua processing contapezzi (ed eventualmente alza il bit di contapezzo...) - /// - public virtual void processContapezzi() - { } - - /// - /// Task periodici SE disconnesso - /// - public virtual void processDisconnectedTask() - { - } - - /// - /// Effettua processing del recupero dei valori dinamici: - /// es: speed (RPM, feedrate) degli assi, valori pressioni, temeprature - /// - public void processDynData() - { - bool enableByApp = utils.CRB("enableDynData"); - bool enableByIob = (getOptPar("ENABLE_DYN_DATA") == "TRUE"); - bool forceSendByIob = (getOptPar("FORCE_DYN_DATA") == "TRUE"); - Dictionary currDynData = new Dictionary(); - - if (enableByApp || enableByIob) - { - lgInfo("Inizio processDynData"); - if (connectionOk) - { - currDynData = getDynData(); - try - { - string sVal = ""; - // se richiesto send diretto... - if (forceSendByIob) - { - // per ogni valore del dizionario mostro ed accodo! - foreach (var item in currDynData) + // altri 2 + maxTry = 2; + while (maxTry > 0 && !answ) { - sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + Thread.Sleep(rand.Next(250, 500)); + callResp = callUrl(urlIobEnabled, false); + answ = (callResp == "OK"); + maxTry--; } - } - // altrimenti verifico SE sia cambiato il valore dei DynData... - else if (lastDynDataCtrlVal != currDynData["DYNDATA"]) - { - // salvo! - lastDynDataCtrlVal = currDynData["DYNDATA"]; - // per ogni valore del dizionario mostro ed accodo! - foreach (var item in currDynData) + // salvo status... + IobOnline = answ; + // se online imposto veto check a 5 x tempo reinvio... + if (answ) { - sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); - } - } - // salvo array... - lastDynData = currDynData; - } - catch (Exception exc) - { - lgError(exc, "Eccezione in processDynData"); - } - } - else - { - lgError("Errore connessione mancante x getDynData"); - } - } - } - - /// - /// Processa gestione memoria x invio dati QUANDO IOB è disconnesso da CNC... - /// - public void processMemoryDiscon() - { - // init obj display - newDisplayData currDispData = new newDisplayData(); - // controllo contatore invio "keepalive"... invio solo a scadenza - if (DateTime.Now.Subtract(lastDisconnCheck).TotalSeconds > utils.CRI("disconMaxSec")) - { - // resetto tutti i vlaori BYTE IN/PREV/OUT... così invio macchina spenta... - B_input = 0; - B_output = 0; - B_previous = 0; - accodaSigIN(ref currDispData); - // update controllo - lastDisconnCheck = DateTime.Now; - } - raiseRefresh(currDispData); - } - - /// - /// Effettua processing mode/status (EDIT/MDI/...) - /// - public virtual void processMode() - { } - - /// - /// Effettua processing ALTRI contatori/parametri (ed invia ad IO) - /// - public virtual void processOtherCounters() - { } - - /// - /// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid) - /// - public virtual void processOverride() - { - bool enableByApp = utils.CRB("enableOverrides"); - bool enableByIob = (getOptPar("ENABLE_OVERRIDES") == "TRUE"); - Dictionary currOverride = new Dictionary(); - if (enableByApp || enableByIob) - { - lgInfo("Inizio processOverride"); - if (connectionOk) - { - currOverride = getOverrides(); - } - else - { - lgError("Errore connessione mancante x getOverrides"); - } - - // SE sono connesso... - if (connectionOk) - { - // se HO dei valori override... - if (currOverride.Count > 0) - { - // verifico SE sia cambiato il programma... - if (lastOverrideFS != currOverride["FEED_OVER"] || lastOverrideRapid != currOverride["RAPID_OVER"]) - { - // salvo! - lastOverrideFS = currOverride["FEED_OVER"]; - lastOverrideRapid = currOverride["RAPID_OVER"]; - // per ogni valore del dizionario mostro ed accodo! - string sVal = ""; - foreach (var item in currOverride) - { - sVal = string.Format("[OVERRIDES]{0}|{1}", item.Key, item.Value); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); - } - } - } - } - } - } - - /// - /// Effettua ciclo controllo richieste server - /// - public void processServerRequests() - { - Dictionary task2exe = new Dictionary(); - Dictionary taskDone = new Dictionary(); - // recupero elenco delle cose da fare - string resp = getTask2exe(); - if (!string.IsNullOrEmpty(resp)) - { - try - { - task2exe = JsonConvert.DeserializeObject>(resp); - // se ho da fare chiamo esecuzione.. - if (task2exe.Count > 0) - { - taskDone = processTask(task2exe); - } - } - catch (Exception exc) - { - lgError($"Eccezione in processServerRequests:{Environment.NewLine}{exc}"); - } - } - } - - public Dictionary processTask(Dictionary task2exe) - { - Dictionary taskDone = new Dictionary(); - if (task2exe != null) - { - lgInfo($"Task2Exe S01: {task2exe.Count} task ricevuti:"); - int idTask = 0; - foreach (var item in task2exe) - { - idTask++; - lgInfo($"[{idTask:00}] - {item.Key} --> {item.Value}"); - } - // chiamo procedura esecutiva (diversa x ogni IOB) - taskDone = executeTasks(task2exe); - lgInfo($"Task2Exe S02: eseguiti {taskDone.Count} task"); - // loggo tutti i task done... - foreach (var item in taskDone) - { - sendToTaskWatch(item.Key, item.Value); - } - // ora chiamo la cancellazione dei task eseguiti... - foreach (var item in taskDone) - { - remTask2exe(item.Key, item.Value); - } - } - return taskDone; - } - - /// - /// Classe fittizia in caso di processing task in VHF - /// - public virtual void processVHF() - { - } - - /// - /// Classe fittizia in caso di processing watchdog data - /// - public virtual void processWhatchDog() - { - } - - /// - /// Effettua rilettura del contapezzi dal server MP/IO - /// - /// Forza rilettura da DB tempi ciclo rilevati - public void pzCntReload(bool forceCountRec) - { - // legge da IO server ULTIMO valore CONTPEZZI al riavvio... - string currServerCount = ""; - string lastIdxODL = ""; - if (checkServerAlive) - { - // leggo PRIMA ODL .... - lastIdxODL = utils.callUrl(urlGetCurrODL); - lgTrace("Lettura ODL dall'url {0} --> {1}", urlGetCurrODL, lastIdxODL); - // se ho valori in coda da trasmettere uso dati REDIS - if (forceCountRec) - { - // uso dati da TCiclo registrati... - currServerCount = utils.callUrl(urlGetPzCountRec); - lgInfo("Lettura contapezzi da TCiclo dall'url {0} --> num pz: {1}", urlGetPzCountRec, currServerCount); - } - else - { - // uso il contapezzi dichiarato dall'IOB stesso - currServerCount = utils.callUrl(urlGetPzCount); - lgInfo("Lettura contapezzi dall'url {0}", urlGetPzCount); - } - // controllo: SE NON HO ODL... - if (string.IsNullOrEmpty(lastIdxODL) || lastIdxODL == "0") - { - // NON AGGIORNO - contapezziIOB = contapezziPLC; - lgError($"Errore lettura ODL (vuoto) resta tutto invariato contapezzi: {contapezziIOB} | contapezziPLC {contapezziPLC}"); - } - else - { - if (!string.IsNullOrEmpty(currServerCount)) - { - // se "-1" resto a ultimo... - if (currServerCount != "-1") - { - int newVal = -1; - Int32.TryParse(currServerCount, out newVal); - contapezziIOB = newVal > -1 ? newVal : contapezziIOB; - lgInfo("Ricevuta conferma da server di {0} pezzi registrati per ODL", currServerCount); - } - else - { - // NON AGGIORNO - contapezziIOB = contapezziPLC; - lgError($"Errore lettura contapezzi (-1) - uso contapezziPLC --> {contapezziPLC}"); - } - } - else - { - // registro che ho UN NUOVO ODL - lgInfo($"Lettura ODL in pzCntReload, currIdxODL {currIdxODL} --> lastIdxODL {lastIdxODL}"); - // se ODL differente e NUOVO è zero --> resetto! - if (currIdxODL.ToString() != lastIdxODL && lastIdxODL == "0") - { - // cambiato ODL quindi reset... - contapezziIOB = 0; - lgInfo("Nuovo ODL==0, RESET contapezzi (-->ZERO)"); - } - // provo a salvare nuovo ODL - int.TryParse(lastIdxODL, out currIdxODL); - } - } - } - else - { - // se server NON pronto... - contapezziIOB = contapezziPLC; - lgError("Errore server NON pronto in pzCntReload"); - } - } - - /// - /// Fornisce il valore di flusso e valore in formato valido x messa in coda nel formato - /// dtEve#flusso#valore#cont - /// Flusso dati - /// Valore da salvare - /// - public string qEncodeFLog(string flusso, string valore) - { - string answ = ""; - try - { - answ = $"{DateTime.Now:yyyyMMddHHmmssfff}#{flusso}#{valore}#{counterULog}"; - } - catch - { } - return answ; - } - - /// - /// Fornisce il valore di flusso e valore in formato valido x messa in coda nel formato dtEve#flux#value#cont - /// DataOra evento registrato - /// Flusso dati - /// Valore da salvare - /// - public string qEncodeFLog(DateTime eventDT, string flusso, string valore) - { - string answ = ""; - try - { - answ = $"{eventDT:yyyyMMddHHmmssfff}#{flusso}#{valore}#{counterFLog}"; - } - catch - { } - return answ; - } - - /// - /// Fornisce il valore di UserLog e valore in formato valido x messa in coda nel formato: - /// dtEve#flusso#value#cont#matrOpr#label#valNum - /// Flusso dati (RC/RS/DI) - /// Valore da inviare (valString - /// Matricola operatore - /// Valore etichetta: causale scarto / tagCode - /// Valore numerico: esitoOk (0/1) / nuo scarti - /// - public string qEncodeULog(string flusso, string valore, int matrOpr, string label, int valNum) - { - string answ = ""; - try - { - answ = $"{DateTime.Now:yyyyMMddHHmmssfff}#{flusso}#{valore}#{matrOpr}#{label}#{valNum}#{counterULog}"; - } - catch - { } - return answ; - } - - /// - /// Effettua lettura dati - /// Parametri da aggiornare x display in form - /// - public virtual void readAllData(ref newDisplayData currDispData) - { - if (currDispData == null) - { - currDispData = new newDisplayData(); - } - try - { - if (DemoIn) - { - // segnalo che sono in Demo - currDispData.semIn = Semaforo.SV; - } - if (connectionOk) - { - readSemafori(ref currDispData); - } - else - { - lgError("Errore connessione mancante x readSemafori"); - } - - nReadIN++; - // aggiorno valore mostrato... - displayRawData(ref currDispData); - } - catch - { - currDispData.semIn = Semaforo.SR; - } - raiseRefresh(currDispData); - } - - /// - /// Effettua lettura semafori principale - /// Parametri da aggiornare x display in form - /// - public virtual void readSemafori(ref newDisplayData currDispData) - { - lastReadPLC = DateTime.Now; - } - - /// - /// Aggiunge ai dati da inviare alla parentform i valori di RawInput rilevati (32bit) - /// 2021.08.27: filtrati secondo i valori setup start/size RawDataInput - /// - public virtual void reportRawInput(ref newDisplayData currDispData) - { - // processo eventualmente aggiungendo ad elementi esistenti... - if (currDispData == null) - { - currDispData = new newDisplayData(); - } - try - { - StringBuilder sb = new StringBuilder(); - sb.Append($"B_input --> {(short)B_input}{Environment.NewLine}"); - sb.Append($"{baseUtils.binaryForm(B_input)}{Environment.NewLine}"); - sb.Append($"{Environment.NewLine}"); - sb.Append($"----------- RAW Data Memory -----------{Environment.NewLine}"); - // Do x scontato siano VALIDI i valori di RawDataInputStart / size --> filtro... - var filtRawData = new byte[RawDataInputSize]; - Array.Copy(RawInput, RawDataInputStart, filtRawData, 0, RawDataInputSize); - int i = RawDataInputStart; - foreach (var item in filtRawData) - { - sb.Append($"B{i:00} --> {baseUtils.binaryForm(item)} = {(short)item}{Environment.NewLine}"); - i++; - } - sb.Append("-------------------------------"); - currDispData.currBitmap = sb.ToString(); - } - catch - { } - } - - /// - /// Metodo generico di reset contapezzi... - /// - /// - public virtual bool resetcontapezziPLC() - { - return false; - } - - /// - /// metodo dummy x salvataggio aree memoria conf x CN - /// - /// tipo di DUMP - public virtual void saveMemDump(dumpType tipo) - { - } - - /// - /// Salva valori indicati in prod data - /// - /// Item KVP di cui salvare i dati in currProdData come chiave/valore - /// - public void saveProdData(KeyValuePair item) - { - // imposto i valori... - if (currProdData.ContainsKey(item.Key)) - { - currProdData[item.Key] = item.Value; - } - else - { - currProdData.Add(item.Key, item.Value); - } - } - - /// - /// Effettua salvataggio in LUT del valore ricevuto - /// - /// - /// - /// - /// - public virtual void saveValue(ref Dictionary outVal, double valore, string chiave) - { - //check obj preliminare - if (outVal == null) - { - outVal = new Dictionary(); - } - bool scaduto = stackVal_TSVC(chiave, valore); - // recupero VC - valore = getVal_TSVC(chiave, scaduto); - if (scaduto) - { - // limite a 3 digit x valore float - outVal.Add(chiave, $"{valore:N3}"); - } - LastTSVC[chiave] = valore; - } - - /// - /// Invio la variazione dello stato allarmi (se avvenuta) - /// - /// COD memoria allarmi - /// Indice memoria allarmi - /// ultimo stato rilevato - /// stato corrente - /// Lista allarmi validi per l'area - /// - public bool sendAlarmVariations(string memAddr, int index, uint lastStatus, uint currStatus, List AlarmList) - { - bool fatto = false; - if (lastStatus != currStatus) - { - List ActiveAlarmList = new List(); - // invio GET del MemoryAddress, del banco e del valore currStatus - lastUrl = $"{urlSendAlarm}?memAddr={memAddr}&index={index}&currStatus={currStatus}"; - if (currStatus == 0) - { - ActiveAlarmList.Add("ALL OK"); - } - else - { - // calcolo quali allarmi mostrare dato currStatus ed elenco allarmi - string bitMap = Convert.ToString(currStatus, 2); - int bitLen = bitMap.Length; - // ciclo x associare tutti gli allarmi - for (int i = 0; i < bitLen; i++) - { - // se è 1 --> aggiungo! - if (bitMap[bitLen - i - 1] == '1') - { - // se sono entro limiti - if (AlarmList.Count >= i) - { - ActiveAlarmList.Add($"{i:000}-{AlarmList.ElementAt(i)}"); - } - //else - //{ - // ActiveAlarmList.Add($"Unknown Bit.{i}"); - //} - } - } - } - - string rawData = JsonConvert.SerializeObject(ActiveAlarmList); - - //string resp = utils.callUrlNow(lastUrl, rawData); - string resp = utils.callUrlAsync(lastUrl, rawData); - if (!string.IsNullOrEmpty(resp)) - { - if (resp.ToUpper() == "OK") - { - // segnalo fatto - fatto = true; - } - } - else - { - lgError($"Errore in invio richiesta registrazione allarme: URL: {lastUrl}{Environment.NewLine}Payload:{Environment.NewLine}{rawData}"); - } - } - return fatto; - } - - /// - /// Invia una LISTA di valori - /// - /// - /// - public void sendDataBlock(urlType tipoUrl, List listQueueVal) - { - // init obj display - newDisplayData currDispData = new newDisplayData(); - if (listQueueVal != null) - { - try - { - // recupero e formatto URL dati da coda... - lastUrl = urlDataBlock(tipoUrl); - // in base al tipo di dato compongo il payload Json da inviare - string payload = jsonPayload(tipoUrl, listQueueVal); - // async a true SE FLog - bool doAsync = tipoUrl == urlType.FLog ? true : false; - // se NON sono in demo effettuo invio! - if (!DemoOut) - { - // SE server alive... - if (checkServerAlive) - { - // chiamo URL! - string answ = callUrlWithPayload(lastUrl, payload, doAsync); - // attesa opzionale se configurata - - // loggo! - lgInfo($"[SEND payload] TipoURL: {tipoUrl} | {listQueueVal.Count} records --> {answ}"); - // se "OK" verde, altrimenti errore --> ROSSO - if (answ.Contains("OK")) - { - currDispData.semOut = Semaforo.SV; - // se oltre 1 min NON era online --> check pezzi! - if (DateTime.Now.Subtract(lastIobOnline).TotalMinutes > 1 && !isMulti) - { - lgInfo($"sendDataBlock --> offline timeout ({lastIobOnline}) --> pzCntReload(true)"); - pzCntReload(true); - } lastIobOnline = DateTime.Now; } + dtVetoCheckIOB = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 5); + } + catch + { } + } + // verifico SE è variato stato online/offline... + if (IobOnline != answ) + { + // se ORA sono online riporto... + if (answ) + { + lgInfo("IOB ONLINE for server MP/IO"); + } + else + { + lgInfo("IOB OFFLINE for server MP/IO"); + } + } + // fix colore + if (answ) + { + parentForm.commSrvActive = 2; + } + else + { + parentForm.commSrvActive = 1; + } + } + else + { + // altrimenti passo ultimo valore noto + answ = IobOnline; + } + return answ; + } + } + + /// + /// test ping all'indirizzo impostato nei parametri + /// + /// + private IPStatus testPingServer + { + get + { + IPStatus answ = IPStatus.Unknown; + // se disabilitato salto... + if (pingDisabled) + { + answ = IPStatus.Success; + } + else + { + IPAddress address; + PingReply reply; + var rand = new Random(); + int pingTOut = 500; + using (Ping pingSender = new Ping()) + { + address = IPAddress.Loopback; + int maxRetry = maxPingRetry + 1; + int numRetry = 1; + string ipAddr = cIobConf.serverData.MPIP.Replace($"{cIobConf.serverData.TRANSP}://", ""); + // fix se fosse ip + porta... + if (ipAddr.IndexOf(":") >= 0) + { + ipAddr = ipAddr.Substring(0, ipAddr.IndexOf(":")); + } + IPAddress.TryParse(ipAddr, out address); + // se null --> provo DNS... + if (address == null) + { + var rawAddresses = Dns.GetHostAddresses(ipAddr); + if (rawAddresses.Length > 0) + { + address = rawAddresses[0]; + } + } + try + { + // se != null --> uso address... + if (address != null) + { + pingTOut = rand.Next(200, 400); + reply = pingSender.Send(address, pingTOut); + } else { - currDispData.semOut = Semaforo.SR; + pingTOut = rand.Next(300, 600); + reply = pingSender.Send(cIobConf.cncIpAddr, pingTOut); } } - else + catch (Exception exc) { - lgInfo($"[SERVER KO] {listQueueVal.Count}"); + pingTOut = rand.Next(100, 200); + reply = pingSender.Send(IPAddress.Loopback, pingTOut); + lgError($"ping to loopback addres per eccezione:{Environment.NewLine}{exc}"); + } + // se ho timeout riprovo... + while (reply.Status != IPStatus.Success && numRetry < maxRetry) + { + Thread.Sleep(rand.Next(50, 200)); + pingTOut = pingServerMsTimeout * numRetry / 2; + reply = pingSender.Send(address, pingTOut); + numRetry++; + if (reply.Status == IPStatus.Success) + { + lgInfo("Server PING OK!"); + break; + } + else + { + lgInfo($"Server Ping KO | reply: {reply.Status} --> retry | TimeOut: {pingTOut}"); + } } } - else - { - currDispData.semOut = Semaforo.SV; - // loggo! - lgInfo($"{listQueueVal.Count} records --> [SIM]"); - } - nSendOut += listQueueVal.Count; - // riporto cosa inviato - currDispData.newUrlCallData = lastUrl; - // aggiorno data ultimo watchdog... - lastWatchDog = DateTime.Now; - } - catch - { - currDispData.semOut = Semaforo.SR; + answ = reply.Status; } + return answ; } - raiseRefresh(currDispData); + } + + #endregion Private Properties + + #region Private Methods + + /// + /// Verifica e se necessario comprime directory log... + /// + private void checkShrinkDir() + { + // comprimo x prima cosa la folder dell'IOB corrente + string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs", cIobConf.codIOB); + //string path = string.Format("{0}logs\\{1}", AppDomain.CurrentDomain.BaseDirectory, cIobConf.codIOB); + baseUtils.shrinkDir(path); + // provo a comprimere anche la folder MAIN.... + path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs", "MAIN"); + baseUtils.shrinkDir(path); } /// - /// Effettua invio a MoonPro del valore richiesto + /// Mostra i dati grezzi letti in esadecimale Parametri da + /// aggiornare x display in form /// - /// - /// Valore da trasmettere: es - /// INPUT: lo status rilevato in HEX - /// FLog: il valore da trasmettere per il flusso indicato - public void sendToMoonPro(urlType tipoUrl, string queueVal) + private void displayRawData(ref newDisplayData currDispData) { - // init obj display - newDisplayData currDispData = new newDisplayData(); + // mostro update... + string newString = string.Format("{0:X}", B_input); + currDispData.newInData = newString; + } + + /// + /// Esegue filtraggio dati x bit blinking!!! + /// + private void filterData() + { + // effettuo filtraggio dei valori letti... inizializzo OUT! + B_output = 0; + // in primis verifico SE ci siano bit blinkng... se non ci sono OUT=IN... + if (cIobConf.BLINK_FILT == 0) + { + B_output = B_input; + } + else + { + // incomincio con i valori NON blinking: questi "passano invariati", inizio a + // sommare nel valore OUT... + B_output = B_input & ~cIobConf.BLINK_FILT; + // calcolo il valore dei BIT che "passano la maschera" + int iBlink = B_input & cIobConf.BLINK_FILT; + // ...aggiungo i "bit che passano" + B_output += iBlink; + + // calcolo QUALI valori (tra quelli blink) siano PASSATI da 0 a 1 --> init counters... + BitArray bBlinkStart = new BitArray(new byte[] { Convert.ToByte(iBlink) }); + int[] bitsUp = bBlinkStart.Cast().Select(bit => bit ? 1 : 0).ToArray(); + for (int i = 0; i < bitsUp.Length; i++) + { + // SE 1... impostiamo contatori al MAX + if (bitsUp[i] == 1) + { + // se era zero indico START blink... + if (i_counters[i] == 0) + { + lgTrace("START BLINK: B{0}", i); + } + // imposto comunque contatore al cambio fronte... + i_counters[i] = cIobConf.MAX_COUNTER_BLINK; + } + } + + // quelli che sono zero... LI RECUPERO E LI PROCESSO... + int iZero = ~B_input & cIobConf.BLINK_FILT; + BitArray bBlinkEnd = new BitArray(new byte[] { Convert.ToByte(iZero) }); + int[] bitsDown = bBlinkEnd.Cast().Select(bit => bit ? 1 : 0).ToArray(); + for (int i = 0; i < bitsDown.Length; i++) + { + // se era a zero (invertito...) + if (bitsDown[i] == 1) + { + // SE è in corso il conteggio... + if (i_counters[i] > 0) + { + // decremento! + i_counters[i] -= 1; + // se è zero NON faccio nulla, altrimenti SOMMO... + if (i_counters[i] > 0) + { + B_output += 1 << i; + } + else + { + lgTrace("END BLINK: B{0}", i); + } + } + } + } + } + } + + /// + /// Imposta eventuali altri valori default + /// + private void fixDefaultPar() + { + // parametro max tentativi PING... + string s_maxPingRetry = getOptPar("MAX_PING_RETRY"); + if (!string.IsNullOrEmpty(s_maxPingRetry)) + { + int numRetry = 5; + int.TryParse(s_maxPingRetry, out numRetry); + maxPingRetry = numRetry; + } + + string s_maxErrCheck = getOptPar("MAX_ERR_CHECK"); + if (!string.IsNullOrEmpty(s_maxErrCheck)) + { + int numErr = 50; + int.TryParse(s_maxErrCheck, out numErr); + maxErroriCheck = numErr; + } + + string s_watchDogPer = getOptPar("WATCHDOG_PERIOD"); + if (!string.IsNullOrEmpty(s_watchDogPer)) + { + int numPer = 3; + int.TryParse(s_watchDogPer, out numPer); + watchDogPeriod = numPer; + } + } + + /// + /// Legge da conf il valore di demoltiplica lettura dynData (se presente) o ignora e pone a 1... + /// + private void fixDemFactDynData() + { + var rawDemFact = getOptPar("DEM_FACT_DYN_DATA"); + if (string.IsNullOrEmpty(rawDemFact)) + { + demFactDynData = 1; + } + else + { + int.TryParse(rawDemFact, out demFactDynData); + } + } + + /// + /// recupera valore salvato in persistence layer (se non c'è crea...) + /// + /// + /// + private string getStoredVal(string keyVal) + { + string value = ""; try { - // recupero e formatto URL dati da coda... - switch (tipoUrl) + if (persistenceLayer != null) { - case urlType.FLog: - lastUrl = urlFLog(queueVal); - break; - - case urlType.SignIN: - lastUrl = urlInput(queueVal); - break; - - default: - lastUrl = ""; - break; - } - // se NON sono in demo effettuo invio! - if (!DemoOut) - { - // SE server alive... - if (checkServerAlive) + if (!persistenceLayer.TryGetValue(keyVal, out value)) { - // chiamo URL! - string answ = callUrl(lastUrl, false); - // loggo! - lgDebug(string.Format("[SEND] {0} -> {1}", queueVal, answ)); - // se oltre 1 min NON era online --> check pezzi! - if (DateTime.Now.Subtract(lastIobOnline).TotalMinutes > 1 && !isMulti) - { - lgInfo($"sendToMoonPro --> offline timeout ({lastIobOnline}) --> pzCntReload(true)"); - pzCntReload(true); - } - // se richiesto effettuo refresh contapezzi - if (needRefreshPzCount && !isMulti) - { - pzCntReload(true); - needRefreshPzCount = false; - } - lastIobOnline = DateTime.Now; - // se "OK" verde, altrimenti errore --> ROSSO - if (answ == "OK") - { - currDispData.semOut = Semaforo.SV; - } - else - { - currDispData.semOut = Semaforo.SR; - } - } - else - { - lgError(string.Format("[SERVER KO] {0}", queueVal)); + persistenceLayer.Add(keyVal, "0"); } } - else - { - currDispData.semOut = Semaforo.SV; - // loggo! - lgDebug(string.Format("{0} -> [SIM]", queueVal)); - } - nSendOut++; - currDispData.newUrlCallData = lastUrl; - // aggiorno data ultimo watchdog... - lastWatchDog = DateTime.Now; } - catch + catch (Exception exc) { - currDispData.semOut = Semaforo.SR; + lgError(string.Format("Eccezione in getStoredVal: {0}{1}", Environment.NewLine, exc)); } - raiseRefresh(currDispData); + return value; } /// - /// Metodo generico di IMPOSTAZIONE FORZATA del contapezzi... + /// recupera valore salvato in persistence layer (se non c'è crea...) come double /// - /// Pezzi richiesti + /// /// - public virtual bool setcontapezziPLC(int newPzCount) + private double getStoredValDouble(string keyVal) { - return false; - } - - /// - /// Processing di Variabili Campionarie x TimeSeries, accoda valori x la VC (se esiste) e restituisce bool val se SCADUTO periodo controllo - /// - /// Nome della VC - /// Valore (nuovo) delal VC - /// - public bool stackVal_TSVC(string VCName, double VCVal) - { - bool answ = false; - // cerco VC... - if (TSVC_Data.ContainsKey(VCName)) + double answ = 0; + try { - TSVC_Data[VCName].dataArray.Add(VCVal); - // ora verifico scadenza... - if (TSVC_Data[VCName].DTStart.AddSeconds(TSVC_Data[VCName].Period) < DateTime.Now) - { - answ = true; - } + answ = Convert.ToDouble(getStoredVal(keyVal)); } + catch (Exception exc) + { + lgError(string.Format("Eccezione in getStoredValDouble: {0}{1}", Environment.NewLine, exc)); + } + answ = (answ < (double.MaxValue / 10 * 9)) ? answ : 0; return answ; } /// - /// Avvia l'adapter sulla porta richiesta + /// recupera valore salvato in persistence layer (se non c'è crea...) come INT /// - /// indica se sia richeisto di SVUOTARE le code delel info - public virtual void startAdapter(bool resetQueue) + /// + /// + private long getStoredValLong(string keyVal) { - lgInfo("Starting adapter..."); - maxJsonData = utils.CRI("maxJsonData"); - maxJsonDataEv = utils.CRI("maxJsonDataEv"); - parentForm.commPlcActive = false; - adpRunning = true; - dtAvvioAdp = DateTime.Now; - lastWatchDog = dtAvvioAdp; - lastPING = dtAvvioAdp; - lastReadPLC = dtAvvioAdp.AddMinutes(-1); - lastDisconnCheck = dtAvvioAdp; - TimingData.resetData(); - // aggiungo altri defaults - setDefaults(resetQueue); - adpTryRestart = true; - lgDebug("startAdapter completed"); + long answ = 0; + try + { + answ = Convert.ToInt64(getStoredVal(keyVal)); + } + catch + { } + // verifico che il valore sia minore di 9/10 del valore massimo... + answ = (answ < (long.MaxValue / 10 * 9)) ? answ : 0; + return answ; } /// - /// ferma l'adapter... + /// recupera valore salvato in persistence layer (se non c'è crea...) come UINT /// - /// indica se si debba tentare di riavviare l'adapter (con caduta connessione viene fermato in automatico) - /// indica se sia richeisto di SVUOTARE le code delel info - public virtual void stopAdapter(bool tryRestart, bool forceDequeue) + /// + /// + private uint getStoredValUInt(string keyVal) { - if (forceDequeue) + uint answ = 0; + try { - // svuoto le code dei valori letti e non ancora trasmessi... - parentForm.displayTaskAndLog("[CLOSING] Svuotamento FORZATO coda segnali..."); - while (QueueIN.Count > 0) + answ = Convert.ToUInt32(getStoredVal(keyVal)); + } + catch (Exception exc) + { + lgError(string.Format("Eccezione in getStoredValUInt: {0}{1}", Environment.NewLine, exc)); + } + // verifico che il valore sia minore di 9/10 del valore massimo... + answ = (answ < (uint.MaxValue / 10 * 9)) ? answ : 0; + return answ; + } + + /// + /// Classe fittizia in caso di processing GLOBALE di tutto in 1 solo colpo... + /// + private void processAllMemory() + { + // init obj display + newDisplayData currDispData = new newDisplayData(); + // in primis SALVO valori previous/precedenti + B_previous = B_output; + // poi faccio lettura NUOVI valori + readAllData(ref currDispData); + // eseguo il filtering dei valori (per i bit "blinking") + filterData(); + // effettuo confronto valori vecchi/nuovi... SE trovo variazione OPPURE se è passato + + // di un timeout di controllo... + if (B_output != B_previous) + { + accodaSigIN(ref currDispData); + } + raiseRefresh(currDispData); + } + + private void processMem2Write() + { + List updatedPar = new List(); + // ciclo tutti gli oggetti write x vedere se modificati... + foreach (var item in currProdData) + { + bool needWrite = false; + // li cerco su last... se non ci sono o modificati --> salvo da scrivere e copio + if (lastProdData.ContainsKey(item.Key)) { - // INVIO COMUNQUE...!!! - string valore = ""; - QueueIN.TryDequeue(out valore); - sendToMoonPro(urlType.SignIN, valore); - } - parentForm.displayTaskAndLog("[CLOSING] Svuotamento FORZATO coda FluxLOG..."); - // se ho + di 2 elementi in coda --> uso invio JSON in blocco... - if (QueueFLog.Count > minJsonData) - { - while (QueueFLog.Count > 0) + // verifico se variato... + if (!item.Value.Equals(lastProdData[item.Key])) { - List listaValori = new List(); - // se ho + di maxJsonData elementi --> invio un set di dati alla volta - if (QueueFLog.Count > maxJsonData) - { - string currVal = ""; - // prendoi primi maxJsonDataValori - for (int i = 0; i < maxJsonData; i++) - { - QueueFLog.TryDequeue(out currVal); - listaValori.Add(currVal); - } - sendDataBlock(urlType.FLog, listaValori); - } - else - { - // invio in blocco - listaValori = QueueFLog.ToList(); - // invio - sendDataBlock(urlType.FLog, listaValori); - // svuoto! - QueueFLog = new ConcurrentQueue(); - } + needWrite = true; + lastProdData[item.Key] = item.Value; } - // HO FINITO invio di FLog... } + // aggiungo else { - string currVal = ""; - while (QueueFLog.Count > 0) - { - // INVIO COMUNQUE...!!! - QueueFLog.TryDequeue(out currVal); - sendToMoonPro(urlType.FLog, currVal); - } + needWrite = true; + lastProdData.Add(item.Key, item.Value); } - - // svuoto coda ULog - while (QueueULog.Count > 0) + // se devo scrivere --> riporto + if (needWrite) { - List listaValori = new List(); - // se ho + di maxJsonData elementi --> invio un set di dati alla volta - if (QueueULog.Count > maxJsonData) + if (memMap.mMapWrite.ContainsKey(item.Key)) { - string currVal = ""; - // prendoi primi maxJsonDataValori - for (int i = 0; i < maxJsonData; i++) + // preparo obj da scrivere + objItem newWrite = new objItem() { - QueueULog.TryDequeue(out currVal); - listaValori.Add(currVal); - } - sendDataBlock(urlType.ULog, listaValori); - } - else - { - // invio in blocco - listaValori = QueueULog.ToList(); - // invio - sendDataBlock(urlType.ULog, listaValori); - // svuoto! - QueueULog = new ConcurrentQueue(); + uid = item.Key, + name = item.Key, + reqValue = memMap.mMapWrite[item.Key].value, + lastRequest = DateTime.Now, + writable = true + }; + updatedPar.Add(newWrite); } } } - parentForm.displayTaskAndLog("[STOP] Stopping adapter..."); - adpTryRestart = false; - - parentForm.displayTaskAndLog("[STOP] Stopping adapter - last periodic data read..."); - - // chiudo la connessione all'adapter... - tryDisconnect(); - dtStopAdp = DateTime.Now; - adpTryRestart = tryRestart; - adpRunning = false; - // chiudo! - parentForm.displayTaskAndLog("Adapter Stopped."); - parentForm.commPlcActive = false; + // se ho da scrivere... scrivo TUTTI! + if (updatedPar.Count > 0) + { + // scrivo valore! + lgInfo("Chiamata di plcWriteParams da processMem2Write"); + plcWriteParams(ref updatedPar); + // invio su cloud parametri! + string rawData = JsonConvert.SerializeObject(updatedPar); + utils.callUrl($"{urlUpdateWriteParams}", rawData); + lgInfo($"Notificato a server scrittura {updatedPar.Count} parametri"); + } } /// - /// Processo la coda SignalIN... + /// Effettua gestioen programma: legge e mostra su display... /// - public void svuotaCodaSignIN() + private void processProgram() { + string currPrgName = ""; + // se abilitata lettura prgName + if (enablePrgName) + { + if (connectionOk) + { + currPrgName = getPrgName(); + } + else + { + lgError("Errore connessione mancante x getPrgName"); + } + } + else + { + currPrgName = lastPrgName; + } + // verifico SE sia cambiato il programma... + if (lastPrgName != currPrgName) + { + // salvo! + lastPrgName = currPrgName; + string sVal = string.Format("[PROG]{0}", currPrgName); + + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog("PROG", currPrgName)); + } + } + + /// + /// Processo lettura dati sysinfo + /// + private void processSysInfo() + { + if (utils.CRB("enableSysInfo")) + { + Dictionary currSysInfo = new Dictionary(); + + if (connectionOk) + { + currSysInfo = getSysInfo(); + } + else + { + lgError("Errore connessione mancante x getSysInfo"); + } + // verifico SE sia cambiato il programma... + if (lastSysInfo != currSysInfo["SYSINFO"]) + { + // salvo! + lastSysInfo = currSysInfo["SYSINFO"]; + // per ogni valore del dizionario mostro ed accodo! + string sVal = ""; + foreach (var item in currSysInfo) + { + sVal = string.Format("[SYSINFO]{0}|{1}", item.Key, item.Value); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + } + } + } + } + + private void reportDataProc() + { + // update valori visualizzazione... + parentForm.dataProcLabel = string.Format("RAW: {0} --> IN: {1} --> OUT: {2}", nReadIN, nReadFilt, nSendOut); + } + + /// + /// Imposto alcuni valori di default + /// + /// indica se sia richeisto di SVUOTARE le code delel info + private void setDefaults(bool resetQueue) + { + numSim = utils.CRI("numSim"); + lastPrgName = ""; + nReadIN = 0; + nReadFilt = 0; + nSendOut = 0; + currMode = 0; + lastAlarm = ""; + doStartMemDump = utils.CRB("doStartMemDump"); + doSampleMemory = utils.CRB("doSampleMemory"); + // fix url wait random... + urlRandWait = utils.CRI("urlRandWait"); + // fix fattore demoltiplica dynData + fixDemFactDynData(); + + // svuoto code se richiesto + if (resetQueue) + { + QueueAlarm = new ConcurrentQueue(); + QueueIN = new ConcurrentQueue(); + QueueFLog = new ConcurrentQueue(); + QueueMessages = new ConcurrentQueue(); + QueueRawTransf = new ConcurrentQueue(); + QueueULog = new ConcurrentQueue(); + } + // imposto contatori blink a zero... + i_counters = new int[32]; + lastPeriodicLog = DateTime.Now; + // fix parametri generali... + enablePrgName = true; + } + + private void svuotaCodaContapezzi() + { + // permetto al max 2 tentativi infruttuosi... + int maxTry = 2; + int oldContapezzi = contapezziIOB; + // se ho contapezzi OLTRE limite... + while ((MPOnline) && (contapezziPLC > contapezziIOB + minSendPzCountBlock)) + { + lgInfo($"Ciclo svuotaCodaContapezzi --> contapezziPLC: {contapezziPLC} | contapezziIOB: {contapezziIOB}"); + if (!isMulti) + { + pzCntReload(true); + } + // provo invio + trySendPzCountBlock(); + // verifica per evitare loop infinito invio fallito + if (oldContapezzi == contapezziIOB) + { + maxTry--; + } + else + { + maxTry = 2; + oldContapezzi = contapezziIOB; + } + // verifico maxTry: se li ho esauriti esco! + if (maxTry <= 0) + { + return; + } + // aspetto x dare tempo calcolo + Thread.Sleep(400); + } + } + + /// + /// Processo la coda FLog... + /// + private void svuotaCodaFLog() + { + // controllo se è passato oltre watchdog e non ho inviato nulla --> RE-INVIO (ultimo inviato)!!!! + if (DateTime.Now.Subtract(lastWatchDog).TotalSeconds > utils.CRI("watchdogMaxSec")) + { + string wdStatus = "elapsed"; + string sVal = string.Format("[WDST]{0}", wdStatus); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog("WDST", wdStatus)); + lastWatchDog = DateTime.Now; + } // verifico SE la coda abbia dei valori... - if (QueueIN.Count > 0) + if (QueueFLog.Count > 0) { // invio pacchetto di dati (max da conf) for (int i = 0; i < nMaxSend; i++) { - if (QueueIN.Count > 0) + // SE ho qualcosa in coda... + if (QueueFLog.Count > 0) { string currVal = ""; - // se online provo if (MPOnline) { if (IobOnline) { // se ho + di 2 elementi in coda --> uso invio JSON in blocco... - if (QueueIN.Count > 1) + if (QueueFLog.Count > 1) { List listaValori = new List(); // se ho + di maxJsonData elementi --> invio un set di dati alla volta - if (QueueIN.Count > maxJsonDataEv) + if (QueueFLog.Count > maxJsonData) { // prendoi primi maxJsonDataValori - for (int j = 0; j < maxJsonDataEv; j++) + for (int j = 0; j < maxJsonData; j++) { - QueueIN.TryDequeue(out currVal); + QueueFLog.TryDequeue(out currVal); listaValori.Add(currVal); } - sendDataBlock(urlType.SignIN, listaValori); + sendDataBlock(urlType.FLog, listaValori); + lastWatchDog = DateTime.Now; } else { // invio in blocco - listaValori = QueueIN.ToList(); + listaValori = QueueFLog.ToList(); // invio - sendDataBlock(urlType.SignIN, listaValori); + sendDataBlock(urlType.FLog, listaValori); // svuoto! - QueueIN = new ConcurrentQueue(); + QueueFLog = new ConcurrentQueue(); + lastWatchDog = DateTime.Now; } } else { // INVIO SINGOLO...!!! - QueueIN.TryDequeue(out currVal); - sendToMoonPro(urlType.SignIN, currVal); - } - // salvo come last signal in il currVal ultimo... SE !="" - if (!string.IsNullOrEmpty(currVal)) - { - lastSignInVal = currVal; + QueueFLog.TryDequeue(out currVal); + sendToMoonPro(urlType.FLog, currVal); + lastWatchDog = DateTime.Now; } } else @@ -5480,193 +5700,302 @@ namespace IOB_WIN_NEXT } /// - /// Metodo base connessione... + /// Processo la coda RawTransf... /// - public virtual void tryConnect() + private void svuotaCodaRawTransf() { - dtAvvioAdp = DateTime.Now; - } - - /// - /// Metodo base disconnessione... - /// - public virtual void tryDisconnect() - { - } - - /// - /// Effettua verifica se abilitato invio pezzi in blocco e nel caso - /// - invio in blocco pezzi - /// - aggiornamento del contapezzi (passato come ref) x nuovo valore post invio - /// - public void trySendPzCountBlock() - { - // in primis HA SENSO procedere SOLO SE server MP è Online... - if (MPOnline) + // verifico SE la coda abbia dei valori... + if (QueueRawTransf.Count > 0) { - // SOLO SE online la macchina... - if (IobOnline) + // invio pacchetto di dati (max da conf) + for (int i = 0; i < nMaxSend; i++) { - int numIncr = 0; - int qtyAdded = 0; - // verifico se la funzione SIA abilitata - if (enableSendPzCountBlock) + // SE ho qualcosa in coda... + if (QueueRawTransf.Count > 0) { - int delta = contapezziPLC - contapezziIOB; - // se è abilitata verifico differenza: se ho DELTA > minSendPzCountBlock --> invio un blocco <= maxSendPzCountBlock - if (delta > minSendPzCountBlock) + string currVal = ""; + if (MPOnline) { - // init obj display - newDisplayData currDispData = new newDisplayData(); - // resta indietro di ALMENO minSendPzCountBlock pezzi x recuperare 1:1... - numIncr = delta > maxSendPzCountBlock + minSendPzCountBlock ? maxSendPzCountBlock : delta - minSendPzCountBlock; - // invio il num max di pezzi ammesso in blocco! - lastUrl = $"{urlAddPzCount}{numIncr}"; - string resp = utils.callUrlNow(lastUrl); - if (!string.IsNullOrEmpty(resp)) + if (IobOnline) { - // dalla risposta (come numero) capisco SE ha aggiunto i pezzi (e quanti) - int.TryParse(resp, out qtyAdded); - if (qtyAdded > 0) + List listaValori = new List(); + // se ho + di maxJsonData elementi --> invio un set di dati alla volta + if (QueueRawTransf.Count > maxJsonData) { - // aggiorno IL MIO contapezzi... - contapezziIOB += qtyAdded; - lgInfo($"Inviato incremento contapezzi: send: {numIncr} | resp: {qtyAdded} | contapezziIOB: {contapezziIOB}"); - // invio conferma contapezzi.. - string retVal = utils.callUrl($"{urlSetPzCount}{contapezziIOB}"); - // verifica se tutto OK - if (retVal != contapezziIOB.ToString()) + // prendoi primi maxJsonDataValori + for (int j = 0; j < maxJsonData; j++) { - // errore salvataggio contapezzi - lgError($"trySendPzCountBlock: errore salvataggio contapezzi: contapezziIOB {contapezziIOB} | risposta: {retVal}"); + QueueRawTransf.TryDequeue(out currVal); + listaValori.Add(currVal); } + sendDataBlock(urlType.RawTransf, listaValori); } else { - lgError($"Richiesto incremento {numIncr} ma NON registrato su server MP-IO"); + // invio in blocco + listaValori = QueueRawTransf.ToList(); + // invio + sendDataBlock(urlType.RawTransf, listaValori); + // svuoto! + QueueRawTransf = new ConcurrentQueue(); } } - currDispData.newUrlCallData = lastUrl; + else + { + break; + } + } + else + { + break; + } + } + else + { + break; + } + } + } + } + + /// + /// Processo la coda UserLog... + /// + private void svuotaCodaULog() + { + // verifico SE la coda abbia dei valori... + if (QueueULog.Count > 0) + { + // invio pacchetto di dati (max da conf) + for (int i = 0; i < nMaxSend; i++) + { + // SE ho qualcosa in coda... + if (QueueULog.Count > 0) + { + string currVal = ""; + if (MPOnline) + { + if (IobOnline) + { + List listaValori = new List(); + // se ho + di maxJsonData elementi --> invio un set di dati alla volta + if (QueueULog.Count > maxJsonData) + { + // prendoi primi maxJsonDataValori + for (int j = 0; j < maxJsonData; j++) + { + QueueULog.TryDequeue(out currVal); + listaValori.Add(currVal); + } + sendDataBlock(urlType.ULog, listaValori); + } + else + { + // invio in blocco + listaValori = QueueULog.ToList(); + // invio + sendDataBlock(urlType.ULog, listaValori); + // svuoto! + QueueULog = new ConcurrentQueue(); + } + } + else + { + break; + } + } + else + { + break; + } + } + else + { + break; + } + } + } + } + + /// + /// Cerca di inviare su un altro thread i vari dati accumulati... + /// + private void trySendValues() + { + // init obj display + newDisplayData currDispData = new newDisplayData(); + try + { + // verifico se risponde il server... + if (checkServerAlive) + { + bool iobOk = false; + if (utils.CRB("sendDataByThread")) + { + Task taskCheck = Task.Run(() => iobOk = checkIobEnabled); + } + else + { + iobOk = checkIobEnabled; + } + // verifico SE posso inviare dati + if (iobOk) + { + currDispData.semOut = Semaforo.SV; + // verificare come gestire il task secondario senza interferenza (chiamate + // update su FORM da thread secondari danno errori) + if (utils.CRB("sendDataByThread")) + { + // invio con thread separato... + Task taskSigIN = Task.Run(() => svuotaCodaSignIN()); + Task taskFLog = Task.Run(() => svuotaCodaFLog()); + Task taskRawTransf = Task.Run(() => svuotaCodaRawTransf()); + Task taskULog = Task.Run(() => svuotaCodaULog()); + } + else + { + // gestione queue SignalIN (invio, display) + svuotaCodaSignIN(); currDispData.counter = contapezziIOB; - currDispData.semOut = Semaforo.SV; raiseRefresh(currDispData); + // provo a svuotare coda contapezzi + svuotaCodaContapezzi(); + currDispData.counter = contapezziIOB; + raiseRefresh(currDispData); + // gestione queue FluxLog (invio, display) + svuotaCodaFLog(); + // coda RawTransf + svuotaCodaRawTransf(); + // coda UserLog + svuotaCodaULog(); + // refresh + raiseRefresh(currDispData); + } + // se arrivo è tutto ok... + currSendErrors = 0; + } + else + { + // mostro VETO-SEND x invio... GIALLO + currDispData.semOut = Semaforo.SG; + if (periodicLog) + { + lgInfo("IOB - VETO SEND"); } } } else { - lgError("Impossibile trySendPzCountBlock: IobOnline è false"); + // mostro SERVER KO x invio... ROSSO + currDispData.semOut = Semaforo.SR; + if (periodicLog) + { + lgError("IOB - SERVER NOT READY"); + } } } - else + catch (Exception exc) { - lgError("Impossibile trySendPzCountBlock: MPOnline è false"); + lgError($"Errore in fase trySendValues | currSendErrors: {currSendErrors}{Environment.NewLine}{exc}"); + currDispData.semOut = Semaforo.SR; } + raiseRefresh(currDispData); } /// - /// Inserimento/aggiornamento chiavi/valore in currProdData + /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce /// - /// - /// - public void upsertKey(string chiave, string valore) + /// + /// + /// + /// Nuovo valore incrementato + private double updateValDoubleByIncr(int i, double delta, string searchString) { - if (currProdData.ContainsKey(chiave)) - { - currProdData[chiave] = valore; - } - else - { - currProdData.Add(chiave, valore); - } + // stringa da cercare.. + string keyVal = string.Format(searchString, i + 1); + // recupero valore precedente... + double contAct = getStoredValDouble(keyVal); + // nuovo valore... + contAct += delta; + // salvo in ram! + persistenceLayer[keyVal] = contAct.ToString(); + // rendo il valore! + return contAct; } /// - /// Formatta URL x invio in DataBlock Json dei dati FLog / eventi + /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce /// - /// - /// - public string urlDataBlock(urlType tipoUrl) + /// + /// + /// + /// Nuovo valore incrementato + private long updateValLongByIncr(int i, long delta, string searchString) { - // verifico la parte di link "tipoComando" - string tipoComando = ""; - switch (tipoUrl) - { - case urlType.FLog: - tipoComando = cIobConf.serverData.CMDFLOG_JSON; - break; - - case urlType.SignIN: - tipoComando = cIobConf.serverData.CMDBASE_JSON; - break; - - case urlType.ULog: - tipoComando = cIobConf.serverData.CMDULOG_JSON; - break; - - default: - break; - } - // URL base x input - string answ = $@"{cIobConf.serverData.TRANSP}://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{tipoComando}{cIobConf.codIOB}"; - return answ; + // stringa da cercare.. + string keyVal = string.Format(searchString, i + 1); + // recupero valore precedente... + long contAct = getStoredValLong(keyVal); + // nuovo valore... + contAct += delta; + // salvo in ram! + persistenceLayer[keyVal] = contAct.ToString(); + // rendo il valore! + return contAct; } /// - /// Fornisce URL di tipo FluxLog + /// Aggiorna un valore del dizionario in SOSTITUZIONE /// - /// valore salvato in coda nel formato dtEve#flux#valore#counter - /// - public string urlFLog(string queueVal) + /// + /// + /// + /// Nuovo valore incrementato + private void updateValString(int i, string newVal, string searchString) { - // URL base x input - string answ = $@"{cIobConf.serverData.TRANSP}://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDFLOG}"; - // decodifica valore! - string[] valori = qDecodeIN(queueVal); - // aggiungo macchina e valore... - answ += string.Format(@"{0}?flux={1}&&valore={2}", cIobConf.codIOB, valori[1], valori[2]); - // aggiondo dataOra evento e corrente + contatore... - answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[3]); - return answ; + // stringa da cercare.. + string keyVal = string.Format(searchString, i + 1); + // salvo in ram! + persistenceLayer[keyVal] = newVal; } /// - /// Fornisce URL INPUT per i parametri richiesti + /// Aggiorna un valore del dizionario in SOSTITUZIONE e lo restituisce /// - /// valore salvato in coda formato dtEve#valore#counter - /// - public string urlInput(string queueVal) + /// + /// + /// + /// Nuovo valore incrementato + private void updateValUInt(int i, uint newVal, string searchString) { - // URL base x input - string answ = $@"{cIobConf.serverData.TRANSP}://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDBASE}"; - // decodifica valore! - string[] valori = qDecodeIN(queueVal); - // aggiungo macchina e valore... - answ += string.Format(@"{0}?valore={1}", cIobConf.codIOB, valori[1]); - // aggiondo dataOra evento e corrente + contatore... - answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[2]); - return answ; + // stringa da cercare.. + string keyVal = string.Format(searchString, i + 1); + // salvo in ram! + persistenceLayer[keyVal] = newVal.ToString(); } /// - /// Fornisce URL di tipo UserLog + /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce /// - /// valore salvato in coda nel formato dtEve#flux#valore#counter - /// - public string urlULog(string queueVal) + /// + /// + /// + /// Nuovo valore incrementato + private uint updateValUIntByIncr(int i, uint delta, string searchString) { - // URL base x input - string answ = $@"{cIobConf.serverData.TRANSP}://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDULOG}"; - // decodifica valore! - string[] valori = qDecodeIN(queueVal); - // aggiungo macchina e valore... - answ += string.Format(@"{0}?flux={1}&&valore={2}", cIobConf.codIOB, valori[1], valori[2]); - // aggiondo dataOra evento e corrente + contatore... - answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[3]); - return answ; + // stringa da cercare.. + string keyVal = string.Format(searchString, i + 1); + // recupero valore precedente... + uint contAct = getStoredValUInt(keyVal); + // nuovo valore... + contAct += delta; + // salvo in ram! + persistenceLayer[keyVal] = contAct.ToString(); + // rendo il valore! + return contAct; } - #endregion Public Methods + #endregion Private Methods } /// @@ -5674,15 +6003,6 @@ namespace IOB_WIN_NEXT /// public class iobRefreshedEventArgs : EventArgs { - #region Private Fields - - /// - /// classe obj privata - /// - private readonly newDisplayData _newDisplayData; - - #endregion Private Fields - #region Public Constructors /// @@ -5707,5 +6027,14 @@ namespace IOB_WIN_NEXT } #endregion Public Properties + + #region Private Fields + + /// + /// classe obj privata + /// + private readonly newDisplayData _newDisplayData; + + #endregion Private Fields } } \ No newline at end of file diff --git a/IOB-WIN-NEXT/IobIcoelDb.cs b/IOB-WIN-NEXT/IobIcoelDb.cs index f7c969b2..7508a23b 100644 --- a/IOB-WIN-NEXT/IobIcoelDb.cs +++ b/IOB-WIN-NEXT/IobIcoelDb.cs @@ -1,19 +1,24 @@ -using System; +using EgwProxy.Icoel; +using IOB_UT_NEXT; +using MapoSDK; +using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Diagnostics; +using System.Net.NetworkInformation; namespace IOB_WIN_NEXT -{ /// - /// Adapter specializzato per ICOEL e le chiamate tramite DB per i dati - /// - accettazione lotti prodotto (frontiera / entrata ciliegie) - /// - export (totale per prodotti) - /// - tracciabilità (confezioni - /// +{ + /// + /// Adapter specializzato per ICOEL e le chiamate tramite DB per i dati + /// - accettazione lotti prodotto (frontiera / entrata ciliegie) + /// - export (totale per prodotti) + /// - tracciabilità (confezioni + /// public class IobIcoelDb : IobGeneric { + #region Public Constructors + /// /// Costruttore dell'IOB Icoel DB /// @@ -21,11 +26,260 @@ namespace IOB_WIN_NEXT /// Configurazione IOB per avvio public IobIcoelDb(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) { + /* -------------------------------------- + * todo's + * -------------------------------------- + * - init obj comunicazione da conf e nuget + * - lanciare sync e verifica stato sync + */ + + string SyncStateDb = getOptPar("SyncStateDb"); + string SyncStateUser = getOptPar("SyncStateUser"); + string SyncStatePwd = getOptPar("SyncStatePwd"); + string SyncStateCTout = getOptPar("SyncStateCTout"); + + + string connSyncState = $"data source={SyncStateDb};initial catalog=MoonPro_ISF;persist security info=True;user id={SyncStateUser};password={SyncStatePwd};MultipleActiveResultSets=True;App=IOB-WIN-NEXT"; + + // gestione command timeout da https://erikej.github.io/sqlclient/2020/10/26/sqlclient-commandtimeout-preview.html + if (!string.IsNullOrEmpty(SyncStateCTout)) + { + connSyncState = $"{connSyncState};Command Timeout={SyncStateCTout}"; + } + + + // eccezione: NON TROVA EntityFramework 6.0.0 o successivo... why?!? + dbProxy = new DbProxy(connSyncState); + + lastPING = DateTime.Now.AddHours(-1); } + #endregion Public Constructors + + #region Public Methods + + /// + /// Implementazione custom esecuzione task specifici + /// + /// + /// public override Dictionary executeTasks(Dictionary task2exe) { - return base.executeTasks(task2exe); + // unico task ammissibile: fare un SYNC forzato... + Dictionary taskDone = new Dictionary(); + if (task2exe != null) + { + // controllo se memMap != null... + if (memMap != null) + { + bool taskOk = false; + string taskVal = ""; + // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4 + foreach (var item in task2exe) + { + taskOk = false; + taskVal = ""; + // converto richiesta in enum... + taskType tName = taskType.nihil; + Enum.TryParse(item.Key, out tName); + // controllo sulla KEY... + switch (tName) + { + case taskType.syncDbData: + lgInfo($"executeTasks --> syncDbData"); + // effettua sync + refreshElencoStati(); + + break; + + default: + taskVal = $"IobIcoelDb | taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; + lgInfo($"IobIcoelDb | chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + } + } + } + } + lastReadPLC = DateTime.Now; + return taskDone; } + + /// + /// Recupero dati dinamici... + /// + public override Dictionary getDynData() + { + // valore non presente in vers default... se gestito fare override + Dictionary outVal = new Dictionary(); + // recupero da DB locale stato sync attuale + var elencoSyncStateCurr = dbProxy.DataController.SyncStateGetAll(); + foreach (var item in elencoSyncStateCurr) + { + saveValue(ref outVal, item.NumRec, $"{item.TableName}_NumRec"); + saveValue(ref outVal, item.NumRecIn, $"{item.TableName}_NumRecIn"); + saveValue(ref outVal, item.LastIdx, $"{item.TableName}_LastIdx"); + saveValue(ref outVal, item.LastIdxIn, $"{item.TableName}_LastIdxIn"); + } + + // aggiungo anche i campi currData + var currData = dbProxy.DataController.CurrDataGetAll(); + foreach (var item in currData) + { + saveValue(ref outVal, (double)item.CurrVal, item.Topic); + } + + lastReadPLC = DateTime.Now; + return outVal; + } + + /// + /// Effettua processing CUSTOM x Icoel: + /// - recupera elenco batch delle 2 linee + /// - invia al sistema + /// + public override void processCustomTaskLF() + { + lgInfo($"Richiesto processCustomTaskLF"); + // effettua sync + refreshElencoStati(); + lastReadPLC = DateTime.Now; + } + + /// + /// Effettua lettura semafori principale Parametri da + /// aggiornare x display in form + /// + public override void readSemafori(ref newDisplayData currDispData) + { + if (connectionOk) + { + B_input = 1; + currDispData.semIn = Semaforo.SV; + + if (dbProxy != null && elencoSyncState != null && elencoSyncState.Count > 0) + { + B_input += (1 << 1); + } + + // accodo NON emergenza + B_input += (1 << 7); + } + else + { + B_input = 0; + currDispData.semIn = Semaforo.SR; + } + } + + /// + /// Override connessione + /// + 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("IcoelSoap: 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; + if (dbProxy != null) + { + elencoSyncState = dbProxy.DataController.SyncStateDoImportAll(); + + if (elencoSyncState != null && elencoSyncState.Count > 0) + { + parentForm.commPlcActive = false; + connectionOk = true; + } + } + // refresh stato connessione!!! + if (connectionOk) + { + if (adpRunning) + { + lgInfo("Connessione OK"); + } + } + else + { + lgError("Impossibile procedere, connessione mancante..."); + } + } + catch (Exception exc) + { + lgFatal($"Errore nella connessione all'adapter IcoelSoap: {szStatusConnection}{Environment.NewLine}{exc}"); + connectionOk = false; + lgInfo($"Eccezione in TryConnect, Adapter IcoelSoap 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: IcoelSoap controllo PING fallito per IP {cIobConf.cncIpAddr}"); + } + } + } + } + else + { + needRefresh = true; + } + } + + public override void tryDisconnect() + { + // registro solo che è disconnesso + connectionOk = false; + } + + #endregion Public Methods + + #region Protected Properties + + protected EgwProxy.Icoel.DbProxy dbProxy { get; set; } = null; + + /// + /// Stato di sync delle tab gestite + /// + protected List elencoSyncState { get; set; } = new List(); + + #endregion Protected Properties + + #region Private Methods + + private void refreshElencoStati() + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + elencoSyncState = dbProxy.DataController.SyncStateDoImportAll(); + sw.Stop(); + lgInfo($"DB: esecuzione task dbProxy.DataController.SyncStateGetAll() in {sw.ElapsedMilliseconds} ms"); + + if (elencoSyncState != null) + { + foreach (var item in elencoSyncState) + { + lgTrace($"TAB: {item.TableName} | IdxIN / IdxLocal {item.LastIdxIn} / {item.LastIdx} | NumIn / NumLocal {item.NumRecIn} / {item.NumRec}"); + } + } + } + + #endregion Private Methods } -} +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/IobIcoelSoap.cs b/IOB-WIN-NEXT/IobIcoelSoap.cs index d14ae42e..93309c38 100644 --- a/IOB-WIN-NEXT/IobIcoelSoap.cs +++ b/IOB-WIN-NEXT/IobIcoelSoap.cs @@ -2,7 +2,6 @@ using EgwProxy.Icoel.SizerService; using IOB_UT_NEXT; using MapoSDK; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net.NetworkInformation; @@ -40,32 +39,7 @@ namespace IOB_WIN_NEXT */ IcoelSizer = new Connector(IOBConf.cncIpAddr, IOBConf.cncPort); - } - - /// - /// Effettua lettura semafori principale - /// Parametri da aggiornare x display in form - /// - public override void readSemafori(ref newDisplayData currDispData) - { - if (connectionOk) - { - B_input = 1; - currDispData.semIn = Semaforo.SV; - if (currBatchList != null) - { - // se ho batch NON chiusi (data = minValue) allora lavora - if (currBatchList[1].EndTime == DateTime.MinValue || currBatchList[1].EndTime == DateTime.MinValue) - { - B_input = 3; - } - } - } - else - { - B_input = 0; - currDispData.semIn = Semaforo.SR; - } + lastPING = DateTime.Now.AddHours(-1); } #endregion Public Constructors @@ -90,7 +64,203 @@ namespace IOB_WIN_NEXT * *---------------------------------------*/ - return base.executeTasks(task2exe); + // Verificare il protocollo: dovrebbe togliere SOLO i task eseguiti... + Dictionary taskDone = new Dictionary(); + if (task2exe != null) + { + // controllo se memMap != null... + if (memMap != null) + { + bool taskOk = false; + string taskVal = ""; + // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4 + foreach (var item in task2exe) + { + taskOk = false; + taskVal = ""; + // converto richiesta in enum... + taskType tName = taskType.nihil; + Enum.TryParse(item.Key, out tName); + // controllo sulla KEY... + switch (tName) + { + case taskType.setSupplier: + + string cmdArgs = item.Value; + taskVal = executeSetSupplier(cmdArgs); + break; + + + case taskType.setParameter: + // richiedo da URL i parametri WRITE da popolare + lgInfo("Chiamata setParameter --> processMemWriteRequests"); + taskVal = processMemWriteRequests(); + // se restituiscce "" faccio altra prova... + if (string.IsNullOrEmpty(taskVal)) + { + // i parametri me li aspetto come stringa composta paramName|paramvalue + if (item.Value.Contains("|")) + { + string[] paramsJob = item.Value.Split('|'); + taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}"; + } + else + { + taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value"; + } + } + break; + + default: + taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; + lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + } + // aggiungo task! + taskDone.Add(item.Key, taskVal); + } + } + else + { + lgError($"Attenzione! memMap è nullo, non posso eseguire task2exe!"); + } + } + + return taskDone; + } + + private string executeSetSupplier(string cmdArgs) + { + string taskVal; + // loggo i parametri ricevuti da popolare + lgInfo($"Chiamata setSupplier --> params payload: {cmdArgs}"); + // recupero batch corrente x preselezionare i dati guid layout/varietà... + var currBatch = IcoelSizer.GetCurrentBatch(); + // recupero GUID x variety e layout di default + var varGuid = currBatch[1].VarietyId; + var layGuid = currBatch[1].LayoutId; + // predispongo grower di default + GrowerInfo GrowerData = new GrowerInfo(); + // le info sono una stringa separata da valore | di GrowerCode|GrowerName|varietyGuid|LayoutGuid; + string[] reqParams = cmdArgs.Split('|'); + // se ho dati sistemo grower... + if (reqParams.Length >= 2) + { + //GrowerData.GrowerCode = reqParams[0]; + //GrowerData.GrowerName = reqParams[1]; + // sistemo commenti + var comments = new List(); + comments.Add($"sent {DateTime.Now: yyyy.MM.dd HH:mm:ss}"); + comments.Add("Qty: no set"); + comments.Add("------------"); + //GrowerData.Comments = comments; + + GrowerData = new GrowerInfo() + { + GrowerCode = reqParams[0], + GrowerName = reqParams[1], + Comments = comments + }; + lgInfo($"Set grower data | GrowerCode: {GrowerData.GrowerCode} | GrowerName: {GrowerData.GrowerName}"); + } + if (reqParams.Length >= 3) + { + Guid.TryParse(reqParams[2], out varGuid); + lgInfo($"Set Variety data | VarGUID: {varGuid}"); + } + if (reqParams.Length >= 4) + { + Guid.TryParse(reqParams[3], out layGuid); + lgInfo($"Set Layout data | LayGUID: {layGuid}"); + } + + // invio richiesta!!! + IcoelSizer.EnqueueBatch(GrowerData, varGuid, layGuid); + lgInfo($"Request sent!"); + + + + taskVal = $"REQUEST SET SUPPLIER | EnqueueBatch | GrowCode: {GrowerData.GrowerCode} | GrowName: {GrowerData.GrowerName} | Var: {varGuid} | Lay: {layGuid} "; + // se restituiscce "" faccio altra prova... + if (string.IsNullOrEmpty(taskVal)) + { + // i parametri me li aspetto come stringa composta paramName|paramvalue + if (cmdArgs.Contains("|")) + { + string[] paramsJob = cmdArgs.Split('|'); + taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}"; + } + else + { + taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {cmdArgs} doesnt contain pipe for splitting key/value"; + } + } + + return taskVal; + } + + /// + /// Metodo da overridare x scrivere DAVVERO i parametri sul PLC + /// + /// + protected override void plcWriteParams(ref List updatedPar) + { + foreach (var item in updatedPar) + { + // cerco se sia setSupplier + if (item.uid == "setSupplier") + { + string reqVal = !string.IsNullOrEmpty(item.reqValue) ? item.reqValue : item.value; + // chiamo + var taskVal = executeSetSupplier(reqVal); + bool fatto = taskVal.StartsWith("REQUEST"); + // se fatto --> aggiorno! + if (fatto) + { + //item.value = item.reqValue; + item.reqValue = ""; + item.lastRead = DateTime.Now; + item.UM = ""; + } + } + + } + } + + /// + /// Dizionario parametri correnti + /// + protected Dictionary perfParamDict { get; set; } = new Dictionary(); + + /// + /// Dizionario dati Batch correnti + /// + protected Dictionary batchDataDict { get; set; } = new Dictionary(); + + /// + /// Recupero dati dinamici... + /// + public override Dictionary getDynData() + { + // valore non presente in vers default... se gestito fare override + Dictionary outVal = new Dictionary(); + // recupero da libreria il dizionario dei performance parameters... + perfParamDict = IcoelSizer.GetPerfMeters(); + lgTrace("SOAP: effettuata chiamata IcoelSizer.GetPerfMeters()"); + foreach (var item in perfParamDict) + { + saveValue(ref outVal, item.Value, item.Key); + } + // ora leggo i batch data + batchDataDict = IcoelSizer.GetCurrBatchData(); + lgTrace("SOAP: effettuata chiamata IcoelSizer.GetCurrBatchData()"); + foreach (var item in batchDataDict) + { + saveValueString(ref outVal, item.Value, item.Key); + } + + lastReadPLC = DateTime.Now; + return outVal; } /// @@ -102,6 +272,7 @@ namespace IOB_WIN_NEXT { lgInfo($"Richiesto processCustomTaskLF"); var currBatch = IcoelSizer.GetCurrentBatch(); + lgTrace("SOAP: effettuata chiamata IcoelSizer.GetCurrentBatch()"); if (currBatch != null) { // verifico se i batch siano variati... e quindi da inviare... @@ -111,23 +282,77 @@ namespace IOB_WIN_NEXT foreach (var item in currBatch) { // se variato ID è cambiato - doSend = (currBatchList[item.Key].Id != item.Value.Id); + doSend = doSend || (currBatchList[item.Key].Id != item.Value.Id); } } // se devo inviare impacchetto dati if (doSend) { - // serializzo ed invio al sistema il risultato - string rawData = JsonConvert.SerializeObject(currBatch); - // invio come tipo "IcoelBatch" - Dictionary sendObj = new Dictionary(); - sendObj.Add(IOB_UT_NEXT.rawTransfType.IcoelBatch, rawData); - - // accodo per invio... - accodaRawData(sendObj); + accodaRawData(rawTransfType.IcoelBatch, currBatch); currBatchList = currBatch; } } + + lastReadPLC = DateTime.Now; + } + + /// + /// Effettua lettura semafori principale Parametri da + /// aggiornare x display in form + /// + public override void readSemafori(ref newDisplayData currDispData) + { + if (connectionOk) + { + B_input = 1; + currDispData.semIn = Semaforo.SV; + if (currBatchList == null) + { + // se nullo --> provo a leggere! + var currBatch = IcoelSizer.GetCurrentBatch(); + lgTrace("SOAP: effettuata chiamata IcoelSizer.GetCurrentBatch()"); + if (currBatch != null) + { + currBatchList = currBatch; + accodaRawData(rawTransfType.IcoelBatch, currBatch); + } + } + else + { + //se i perf parameters mi danno valire > 0 x quantità frutta... + if (perfParamDict != null && perfParamDict.Count > 0) + { + if (perfParamDict.ContainsKey("VelFruttiMinuto")) + { + if (perfParamDict["VelFruttiMinuto"] > 0) + { + B_input += (1 << 1); + } + // metto manuale + else + { + B_input += (1 << 4); + } + } + } + + //usato altro criterio x stato verde da vel frutti minuto +#if false + // se ho batch NON chiusi (data = minValue) allora lavora + if (currBatchList[1].EndTime == DateTime.MinValue || currBatchList[1].EndTime == DateTime.MinValue) + { + B_input = 3; + } +#endif + } + // accodo NON emergenza + B_input += (1 << 7); + } + else + { + B_input = 0; + currDispData.semIn = Semaforo.SR; + } } /// @@ -156,6 +381,7 @@ namespace IOB_WIN_NEXT parentForm.commPlcActive = true; // recupero elenco batch... se != vuoto -_> connesso! var batchList = IcoelSizer.GetCurrentBatch(); + lgTrace("SOAP: effettuata chiamata IcoelSizer.GetCurrentBatch()"); if (batchList != null && batchList.Count > 0) { lgInfo($"szStatusConnection IcoelSoap, recuperato elenco di {batchList.Count} batch"); @@ -228,13 +454,14 @@ namespace IOB_WIN_NEXT ///determina se recuperare SOLO varietà attive o tutte bool soloAttive = false; var varList = IcoelSizer.GetVarietyList(soloAttive); + lgTrace("SOAP: effettuata chiamata IcoelSizer.GetVarietyList()"); if (varList != null && varList.Length > 0) { var varietyData = IcoelSizer.GetLayoutForVarietyList(varList); - // invio dai al server IO - + lgTrace("SOAP: effettuata chiamata IcoelSizer.GetLayoutForVarietyList()"); } + lastReadPLC = DateTime.Now; } #endregion Protected Methods diff --git a/IOB-WIN-NEXT/IobModbusTCP.cs b/IOB-WIN-NEXT/IobModbusTCP.cs index 4c1d8279..6f6de41f 100644 --- a/IOB-WIN-NEXT/IobModbusTCP.cs +++ b/IOB-WIN-NEXT/IobModbusTCP.cs @@ -169,6 +169,11 @@ namespace IOB_WIN_NEXT /// public override Dictionary getDynData() { + Random rnd = new Random(); + int minWait = 50; + int maxWait = 50; + int.TryParse(getOptPar("minWait"), out minWait); + int.TryParse(getOptPar("maxWait"), out maxWait); // valore non presente in vers default... se gestito fare override Dictionary outVal = new Dictionary(); if (utils.CRB("enableTSVC")) @@ -189,7 +194,8 @@ namespace IOB_WIN_NEXT foreach (var item in memSetR) { readBlockHoldingReg(item.Key, item.Value, parametri.holdRegBaseAddr); - Thread.Sleep(100); + int waitTime = rnd.Next(minWait, maxWait); + Thread.Sleep(waitTime); } } // procedo ... @@ -237,6 +243,23 @@ namespace IOB_WIN_NEXT outVal = new Dictionary(); tryConnect(); } + // ora aggiungo (se ci fossero) gli allarmi... + if (alarmMaps != null && alarmMaps.Count > 0) + { + if (hasAlarms) + { + string bankVal = ""; + foreach (var item in alarmMaps) + { + bankVal = ""; + var currState = currAlarmsState(item); + // calcolo vettore stringa degli allarmi... + bankVal = getAlarmState(item, currState); + bankVal = string.IsNullOrEmpty(bankVal) ? "OK" : bankVal; + saveAlarmString(ref outVal, bankVal, item.description); + } + } + } } } else @@ -525,7 +548,7 @@ namespace IOB_WIN_NEXT { try { - currPLC.WriteMultipleRegisters(startAddr, currRegVal); + currPLC.WriteMultipleRegisters(startAddr + deltaBase, currRegVal); answ = true; } catch @@ -626,7 +649,7 @@ namespace IOB_WIN_NEXT // bit status: // - allarmi che iniziano per # IGNORATI // - altri allarmi con un countdown da MAX_COUNTER_BLINK a 0 per il - // fronte di discesa + // fronte di discesa if (item.isChanged(i, (uint)currStatus)) { // registro gli allarmi attivi e trasmetto... @@ -654,6 +677,56 @@ namespace IOB_WIN_NEXT #region Protected Methods + /// + /// Restituisce stato allarmi in formato byte[] + /// + /// + /// + protected byte[] currAlarmsState(BaseAlarmConf item) + { + byte[] answ = new byte[item.size]; + int currStatus = 0; + int[] listInt = new int[2]; + // banchi in array Int16 --> scompongo + for (int i = 0; i < item.size / 2; i++) + { + // verifico se usare LUT + bool useLUT = memSetR != null && memSetR.Count > 0; + if (useLUT) + { + int lutAddress = 40000 + item.index; + if (HoldingRegisterLUT.ContainsKey(lutAddress)) + { + try + { + listInt = HoldingRegisterLUT[lutAddress]; + } + catch (Exception exc) + { + lgError($"Errore in lettura da HoldingRegisterLUT per indirizzo {lutAddress} | item {item.memAddr}{Environment.NewLine}{exc}"); + } + } + } + else + { + listInt = readInputReg(item.index, item.size); + } + currStatus = ModbusClient.ConvertRegistersToInt(listInt); + + // aggiornamento blink counters dato nuovo valore + item.checkBlinkCounter(i, (uint)currStatus); + + // calcolo indice errori + if ((uint)(item.alarmsMask[i] & currStatus) > 0) + { + var currByte = BitConverter.GetBytes(currStatus); + // salvo nell'array di byte + Buffer.BlockCopy(currByte, 0, answ, i * 2, 2); + } + } + return answ; + } + /// /// Decodifica il resto dell'area x i dati accessori (allarmi, ...) /// @@ -714,13 +787,21 @@ namespace IOB_WIN_NEXT break; case plcDataType.Int: - valInt = getScaledInt(currMem); - CurrVal = ModbusClient.ConvertIntToRegisters(valInt); + valInt = getScaledInt(currMem, true); + if (byteSize == 1) + { + CurrVal[0] = valInt; + } + else + { + CurrVal = ModbusClient.ConvertIntToRegisters(valInt); + } + fatto = writeInputReg(currMem.index, CurrVal); break; case plcDataType.DInt: - valUInt = getScaledUInt(currMem); + valUInt = getScaledUInt(currMem, true); CurrVal = ModbusClient.ConvertLongToRegisters(valInt); fatto = writeInputReg(currMem.index, CurrVal); break; @@ -811,12 +892,14 @@ namespace IOB_WIN_NEXT parametri.memSizeRead = fIni.ReadInteger("MEMORY", "SIZE_READ", 0); parametri.memSizeWrite = fIni.ReadInteger("MEMORY", "SIZE_WRITE", 0); parametri.holdRegBaseAddr = fIni.ReadInteger("MEMORY", "HR_BASE_ADDR", 40001); + // valore delta base + deltaBase = fIni.ReadInteger("MEMORY", "DELTA_BASE", 0); // salvo vettori memoria... lgInfoStartup("Set RawInput dimensions..."); RawInput = new byte[parametri.memSizeRead]; RawOutput = new byte[parametri.memSizeWrite]; // salvo parametri conn! - lgInfoStartup(string.Format("Parametri memoria: memAddrRead: {0} | memAddrWrite: {1} | memSizeRead: {2} | memSizeWrite: {3}", parametri.memAddrRead, parametri.memAddrWrite, parametri.memSizeRead, parametri.memSizeWrite)); + lgInfoStartup($"Parametri memoria: memAddrRead: {parametri.memAddrRead} | memAddrWrite: {parametri.memAddrWrite} | memSizeRead: {parametri.memSizeRead} | memSizeWrite: {parametri.memSizeWrite} | deltaBase: {deltaBase}"); } catch (Exception exc) { @@ -1027,13 +1110,17 @@ namespace IOB_WIN_NEXT /// private double deltaVal = 0; - /// - /// Indirizzo di base x fare il calcolo di dove leggere in ModBus - /// - private int HoldRegBaseAddr = 40001; - #endregion Private Fields + #region Private Properties + + /// + /// Valore da gestire come delta degli indirizzi configurati + /// + private int deltaBase { get; set; } = 0; + + #endregion Private Properties + #region Private Methods /// @@ -1050,6 +1137,7 @@ namespace IOB_WIN_NEXT switch (tipoMem) { case plcDataType.Real: + case plcDataType.FloatABCD: if (size == 4) { valore = ModbusClient.ConvertRegistersToDouble(listInt); @@ -1060,6 +1148,21 @@ namespace IOB_WIN_NEXT } break; + case plcDataType.FloatCDAB: + if (size == 4) + { + // invero array... + Array.Reverse(listInt); + valore = ModbusClient.ConvertRegistersToDouble(listInt); + } + else if (size == 2) + { + // non serve cambaire nulla... + Array.Reverse(listInt); + valore = ModbusClient.ConvertRegistersToFloat(listInt); + } + break; + // caso speciale x Cedax, che usa HighVal moltiplicato x 32768... case plcDataType.HLPInt: if (size == 4) @@ -1083,6 +1186,10 @@ namespace IOB_WIN_NEXT { valore = ModbusClient.ConvertRegistersToInt(listInt); } + else if (size == 1) + { + valore = listInt[0]; + } break; } return valore; @@ -1100,28 +1207,58 @@ namespace IOB_WIN_NEXT return valDouble; } - - private static int getScaledInt(dataConf currMem) + /// + /// Effettua scalatura valore secondo fattore + /// Read --> * (moltiplico) + /// Write --> / (divido) + /// + /// + /// + /// + private static int getScaledInt(dataConf currMem, bool isWrite = false) { - int valInt; + int valInt = 0; + double temp; // prima faccio eventuale fattore di scala... - int.TryParse(currMem.value, out valInt); + double.TryParse(currMem.value.Replace(".", ","), out temp); + //int.TryParse(currMem.value, out valInt); if (currMem.factor != 1) { - valInt = (int)(valInt * currMem.factor); + if (isWrite) + { + valInt = (int)(temp * 10 / currMem.factor) / 10; + } + else + { + valInt = (int)(temp * 10 * currMem.factor) / 10; + } } return valInt; } - private static uint getScaledUInt(dataConf currMem) + /// + /// Effettua scalatura valore secondo fattore + /// Read --> * (moltiplico) + /// Write --> / (divido) + /// + /// + /// + private static uint getScaledUInt(dataConf currMem, bool isWrite = false) { uint valUInt; // prima faccio eventuale fattore di scala... uint.TryParse(currMem.value, out valUInt); if (currMem.factor != 1) { - valUInt = valUInt * (uint)currMem.factor; + if (isWrite) + { + valUInt = valUInt / (uint)currMem.factor; + } + else + { + valUInt = valUInt * (uint)currMem.factor; + } } return valUInt; @@ -1188,16 +1325,33 @@ namespace IOB_WIN_NEXT case modBusAddrType.HoldingRegister: if (useLUT) { - int lutAddress = 40000 + item.Value.index; - if (HoldingRegisterLUT.ContainsKey(lutAddress)) + int lutAddress = 40000 + item.Value.index + deltaBase; + // se size = 1 --> devo cambiare modo recupero + if (item.Value.size == 1) { - try + if (item.Value.index % 2 == 0) { - listInt = HoldingRegisterLUT[lutAddress]; + //Array.Copy(HoldingRegisterLUT[lutAddress], listInt, 1); + Array.Copy(HoldingRegisterLUT[lutAddress], 0, listInt, 0, 1); } - catch (Exception exc) + else { - lgError($"Errore in lettura da HoldingRegisterLUT per indirizzo {lutAddress} | item {item.Key}{Environment.NewLine}{exc}"); + lutAddress--; + Array.Copy(HoldingRegisterLUT[lutAddress], 1, listInt, 0, 1); + } + } + else + { + if (HoldingRegisterLUT.ContainsKey(lutAddress)) + { + try + { + listInt = HoldingRegisterLUT[lutAddress]; + } + catch (Exception exc) + { + lgError($"Errore in lettura da HoldingRegisterLUT per indirizzo {lutAddress} | item {item.Key}{Environment.NewLine}{exc}"); + } } } } @@ -1213,16 +1367,16 @@ namespace IOB_WIN_NEXT } // verifica limite... con delta da impianto dataOk = (valore > (item.Value.minVal + deltaVal) && valore < (item.Value.maxVal - deltaVal)); - if (dataOk) + if (dataOk || disDynDataRangeCheck) { // moltiplico x fattore conversione... valoreScal = valore * item.Value.factor; saveValue(ref outVal, valoreScal, item.Key); - lgDebug($"getDynData: valore ricevuto | {item.Key} | val: {valore} | valoreScal: {valoreScal}"); + lgDebug($"getDataDictionary: valore ricevuto | {item.Key} | val: {valore} | valoreScal: {valoreScal}"); } else { - lgError($"getDynData: valore scartato x limiti min/max | {item.Key} | val: {valore} | valoreScal: {valoreScal} | min-max: {item.Value.minVal}-{item.Value.maxVal} | deltaVal: {deltaVal}"); + lgError($"getDataDictionary: valore scartato x limiti min/max | {item.Key} | val: {valore} | valoreScal: {valoreScal} | min-max: {item.Value.minVal}-{item.Value.maxVal} | deltaVal: {deltaVal}"); readErrorList.Add(item.Key, item.Value); lgDebug($"--> rimesso in coda lettura | parametro: {item.Key} | index: {item.Value.index} | size: {item.Value.size}"); } @@ -1264,7 +1418,7 @@ namespace IOB_WIN_NEXT /// /// Effettua lettura blocco memoria indicato e lo salva in copia locale HoldingRegisterLUT /// - /// Indirizzo di aprtenza + /// Indirizzo di partenza /// NUm registri da leggere (max 120) private void readBlockHoldingReg(int startAddr, int numReg, int baseAddr) { diff --git a/IOB-WIN-NEXT/IobModbusTCPCedax.cs b/IOB-WIN-NEXT/IobModbusTCPCedax.cs index 1b64e300..a67ef056 100644 --- a/IOB-WIN-NEXT/IobModbusTCPCedax.cs +++ b/IOB-WIN-NEXT/IobModbusTCPCedax.cs @@ -101,11 +101,15 @@ namespace IOB_WIN_NEXT B_input = 0; /* ----------------------------------------------------- - * bitmap MAPO STANDARD + * bitmap MAPO STANDARD 60 * B0: POWER_ON * B1: RUN * B2: pzCount * B3: allarme + * B4: manuale + * B5: slowTC + * B6: WarmUpCoolDown + * B7: EmergArmata * ----------------------------------------------------- */ @@ -128,6 +132,9 @@ namespace IOB_WIN_NEXT byteSignals += (1 << 1); } + // segnalo NON emergenza + byteSignals += (1 << 7); + // salvo! B_input = byteSignals; } diff --git a/IOB-WIN-NEXT/IobModbusTCPCenterfrigo.cs b/IOB-WIN-NEXT/IobModbusTCPCenterfrigo.cs new file mode 100644 index 00000000..47302ac3 --- /dev/null +++ b/IOB-WIN-NEXT/IobModbusTCPCenterfrigo.cs @@ -0,0 +1,147 @@ +using EasyModbus; +using IOB_UT_NEXT; +using MapoSDK; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.NetworkInformation; +using System.Text; +using System.Threading.Tasks; + +namespace IOB_WIN_NEXT +{ + /* -------------------------------------------------------------------------------- + * Controlli ModBusTCP Centerfrigo + * - protocollo ModBus TCP + * - specifico comportamento impianti Centerfrigo + * - gestione allarmi + * - gestione stati salvati come dynData + * - gestione valori analogici + * + * STRUTTURA MEMORIA a banchi di UInt16, convertiti successivamente in int EVENTUALMENTE divisi per 10/100/1000 + * lettura: xxx byte, + * scrittura yyy byte + * G:\Drive condivisi\30_Clienti\Giacovelli - WIL\CenterFrigo + * + * ATTENZIONE! leggere al max 44 byte alla volta + * + * -------------------------------------------------------------------------------- */ + + public class IobModbusTCPCenterfrigo : IobModbusTCP + { + #region Public Constructors + + /// + /// Classe base con i metodi x ModBusTCP + /// + /// + /// + public IobModbusTCPCenterfrigo(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) + { + lgInfo("NEW IOB ModBus TCP Centerfrigo"); + + // provo lettura una prima volta i dati DYN + if (currPLC != null && currPLC.Connected) + { + try + { + processDynData(); + } + catch (Exception exc) + { + lgError($"Eccezione in processDynData iniziale x ModBus TCP Cedax:{Environment.NewLine}{exc}"); + } + } + } + + #endregion Public Constructors + + #region Private Methods + + private void testBlockRead(int baseAddr, int numByte) + { + int baseHold = 40001; + int[] readTestFull = new int[2]; + lgTrace($"-------------------- Inizio test lettura {baseAddr} --------------------"); + try + { + stopwatch.Restart(); + readTestFull = currPLC.ReadHoldingRegisters(baseAddr - baseHold, numByte); + stopwatch.Stop(); + lgTrace($"Stats lettura | {readTestFull.Length} val | {stopwatch.ElapsedMilliseconds}ms"); + } + catch + { } + + for (int i = 0; i < readTestFull.Length / 2; i++) + { + int[] thisSet = new int[2]; + Array.Copy(readTestFull, i * 2, thisSet, 0, 2); + lgTrace($"{baseAddr + i * 2:000} | HoldingRegisters: {thisSet[0]} / {thisSet[1]} | Val Real: {ModbusClient.ConvertRegistersToFloat(thisSet):N6}"); + } + lgTrace("-------------------- Completato test lettura {baseAddr} --------------------"); + } + + private void testRead() + { + foreach (var item in memSetR) + { + testBlockRead(item.Key, item.Value); + } + } + + #endregion Private Methods + + #region Protected Methods + + /// + /// Effettua decodifica aree memoria alla bitmap usata x MAPO + /// + protected override void decodeToBaseBitmap() + { + // init a zero... + B_input = 0; + + /* ----------------------------------------------------- + * bitmap MAPO STANDARD 60 + * B0: POWER_ON + * B1: RUN + * B2: pzCount + * B3: allarme + * B4: manuale + * B5: slowTC + * B6: WarmUpCoolDown + * B7: EmergArmata + * + ----------------------------------------------------- */ + + var MemInt = new byte[2]; + + int byteSignals = 0; + // bit 0 (poweron) imposto a 1 SE connected... + if (currPLC.Connected) + { + byteSignals += (1 << 0); + } + + // processo dagli stati + gravi... + if (hasAlarms) + { + byteSignals += (1 << 3); + } + else + { + byteSignals += (1 << 1); + } + + // segnalo NON emergenza + byteSignals += (1 << 7); + + // salvo! + B_input = byteSignals; + } + + #endregion Protected Methods + } +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/IobOpcUa.cs b/IOB-WIN-NEXT/IobOpcUa.cs index e3049e89..dfa8e7e5 100644 --- a/IOB-WIN-NEXT/IobOpcUa.cs +++ b/IOB-WIN-NEXT/IobOpcUa.cs @@ -549,7 +549,7 @@ namespace IOB_WIN_NEXT protected DateTime lastCurrent = DateTime.Now; /// - /// Oggetto MAIN x connessione MTC + /// Oggetto MAIN x connessione OPC-UA /// protected UAClient UA_ref; diff --git a/IOB-WIN-NEXT/IobOpcUaOmronIcoel.cs b/IOB-WIN-NEXT/IobOpcUaOmronIcoel.cs index 91803e95..bc31f488 100644 --- a/IOB-WIN-NEXT/IobOpcUaOmronIcoel.cs +++ b/IOB-WIN-NEXT/IobOpcUaOmronIcoel.cs @@ -415,7 +415,7 @@ namespace IOB_WIN_NEXT B_input = powerOnOk ? 1 : 0; // decodifico da currData - if (currData.Varie.InEmergenza) + if (!currData.Varie.InEmergenza) { B_input += (1 << 7); } @@ -427,6 +427,7 @@ namespace IOB_WIN_NEXT { B_input += (1 << 3); } + } // controllo se sono poweroff e se non ho dati buoni da > 2 minuti --> disconnetto diff --git a/IOB-WIN-NEXT/IobSiemens.cs b/IOB-WIN-NEXT/IobSiemens.cs index fe0abcac..c97c504f 100644 --- a/IOB-WIN-NEXT/IobSiemens.cs +++ b/IOB-WIN-NEXT/IobSiemens.cs @@ -844,6 +844,16 @@ namespace IOB_WIN_NEXT case plcDataType.String: valString = S7.Net.Types.String.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray()); + saveValueString(ref outVal, valString, item.Key); + break; + + case plcDataType.BitMap: + byte[] byteState = RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray(); + // calcolo valore string come unione delle bitmap attive... + valString = getBitmapState(item.Value, byteState); + // se vuoto segno "OK" + valString = string.IsNullOrEmpty(valString) ? "OK" : valString; + saveValueString(ref outVal, valString, item.Key); break; default: @@ -924,7 +934,8 @@ namespace IOB_WIN_NEXT /// public override void processContapezzi() { - if (utils.CRB("enableContapezzi")) + bool disableByIob = (getOptPar("DISABLE_PZCOUNT") == "TRUE"); + if (utils.CRB("enableContapezzi") && !disableByIob) { try { @@ -1727,5 +1738,51 @@ namespace IOB_WIN_NEXT } #endregion Public Methods + + /// + /// Verifica presenza allarmi (tra quelli configurati) + /// + protected bool hasAlarms + { + get + { + bool answ = false; + int numErrors = 0; + uint currStatus = 0; + if (alarmMaps != null) + { + // leggo a ciclo le aree degli allarmi CONFIGURATI, se ne trovo --> segnalo allarme... + foreach (var item in alarmMaps) + { + // banchi in WORD (2 byte) --> scompongo + for (int i = 0; i < item.size / 2; i++) + { + currStatus = S7.Net.Types.Counter.FromByteArray(RawInput.Skip(item.index + 2 * i).Take(2).ToArray()); + // verifica e decremento blink... + item.checkBlinkCounter(i, (uint)currStatus); + + // verifico SE sia variato... confronto allarmi filtrato stile blink per bit status: + // - allarmi che iniziano per # IGNORATI + // - altri allarmi con un countdown da MAX_COUNTER_BLINK a 0 per il fronte di discesa + if (item.isChanged(i, currStatus)) + { + if (currStatus > 0) + { + numErrors++; + } + // registro gli allarmi attivi e trasmetto... + if (sendAlarmVariations(item.memAddr, i, item.alarmsState[i], (uint)(item.alarmsMask[i] & currStatus), item.messages)) + { + // se inviato --> salvo stato da current... + item.updStatusVal(i, (uint)(item.alarmsMask[i] & currStatus)); + } + } + } + } + } + answ = numErrors > 0; + return answ; + } + } } } \ No newline at end of file diff --git a/IOB-WIN-NEXT/IobSiemensComeca.cs b/IOB-WIN-NEXT/IobSiemensComeca.cs index 948d5656..e4416c40 100644 --- a/IOB-WIN-NEXT/IobSiemensComeca.cs +++ b/IOB-WIN-NEXT/IobSiemensComeca.cs @@ -57,6 +57,7 @@ namespace IOB_WIN_NEXT #region Protected Properties +#if false protected bool hasAlarms { get @@ -98,7 +99,8 @@ namespace IOB_WIN_NEXT answ = numErrors > 0; return answ; } - } + } +#endif #endregion Protected Properties diff --git a/IOB-WIN-NEXT/IobSiemensNWSE.cs b/IOB-WIN-NEXT/IobSiemensNWSE.cs new file mode 100644 index 00000000..a96f3a0a --- /dev/null +++ b/IOB-WIN-NEXT/IobSiemensNWSE.cs @@ -0,0 +1,222 @@ +using MapoSDK; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +namespace IOB_WIN_NEXT +{ + /// + /// Controllo Siemens specifico x impianti RobotSerice (es Smerigliature DONATI) + /// + public class IobSiemensNWSE : IobSiemens + { + /* -------------------------------------------------------------------------------- + * Controlli SIEMENS NWS + * - basasto su SIEMENS + * - S7 vers 1200 + * + * STRUTTURA MEMORIA DB100: (lettura) 50byte, + * G:\Drive condivisi\30_Clienti\Giacovelli - WIL\NWS + * + * + * DB100 + * B00..B15 --> 16 byte di allarmi (osmosi, depurazione, 6 x filtri) + * B20..B35 --> 16 byte di stati (osmosi, depurazione, 6 x filtri) + * B40..B49 --> 5 valori uint lettura parametri + * + * + * + * STRUTTURA MEMORIA DB101: (scrittura) 14byte, solo 2 impiegati x ora + * NB: segnali da tenere attivi ALMENO 3 secondi x farli recepire + * + * B0.0 Bit Azzeramento volume acqua OSMOSI + * B0.1 Bit Azzeramento volume acqua DEPURAZIONE + * + * B1.7 Bit Attivazione modo DEMO (0 = disattivato) + * + * -------------------------------------------------------------------------------- */ + + #region Protected Fields + + protected bool EmergencyBypass = false; + + #endregion Protected Fields + + #region Public Constructors + + /// + /// Classe base con i metodi x Siemens + /// + /// + /// + public IobSiemensNWSE(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) + { + lgInfo("NEW IOB SIEMENS versione NWS"); + + if (IOBConf.optPar.ContainsKey("EMERGENCY_BYPASS")) + { + bool.TryParse(IOBConf.optPar["EMERGENCY_BYPASS"], out EmergencyBypass); + lgInfo($"Override EmergencyBypass da conf: {IOBConf.optPar["EMERGENCY_BYPASS"]} --> {EmergencyBypass}"); + } + } + + #endregion Public Constructors + + #region Protected Methods + + /// + /// Effettua decodifica aree memoria alla bitmap usata x MAPO + /// + protected override void decodeToBaseBitmap() + { + // init a zero... + B_input = 0; + + /* ----------------------------------------------------- + * bitmap MAPO STANDARD 60 + * B0: POWER_ON + * B1: RUN + * B2: pzCount - NON usato + * B3: allarme (almeno 1 presente) + * B4: manuale - non usato + * B5: slowTC - non usato + * B6: WarmUpCoolDown - no usato + * B7: Emergenza armata (1) + * + ----------------------------------------------------- */ + + int byteSignals = 0; + // bit 0 (poweron) imposto a 1 SE connected... + if (currPLC.IsConnected) + { + byteSignals += (1 << 0); + } + + // processo dagli stati + gravi... + if (hasAlarms) + { + byteSignals += (1 << 3); + } + else + { + byteSignals += (1 << 1); + } + + // se bypass emergenza attivo --> forzo a ARMED... + if (EmergencyBypass) + { + // segnalo NON emergenza + byteSignals += (1 << 7); + } + + // salvo! + B_input = byteSignals; + } + + #endregion Protected Methods + + #region Public Methods + + /// + /// Processo i task richiesti e li elimino dalla coda 1:1 + /// + /// + public override Dictionary executeTasks(Dictionary task2exe) + { + lgInfo($"Chiamata executeTasks specifica IobSiemensNWS: {task2exe.Count} task ricevuti"); + // Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti... + Dictionary taskDone = new Dictionary(); + bool taskOk = false; + string taskVal = ""; + // inizio con 1 byte di default + byte[] MemBlock = new byte[1]; + string memAddrWrite = ""; + if (task2exe != null) + { + // cerco task specifici + foreach (var item in task2exe) + { + taskOk = false; + taskVal = ""; + // converto richiesta in enum... + taskType tName = taskType.nihil; + Enum.TryParse(item.Key, out tName); + // controllo sulla KEY + switch (tName) + { + case taskType.forceResetPzCount: + // usato x resettare i contatori osmosi inversa e depurazione + // processo scrittura BIT su DB101.DBB0 per + MemBlock = new byte[1]; + // scrivo 3 x resettare entrambi i contatori + MemBlock = S7.Net.Types.Byte.ToByteArray(3); + memAddrWrite = "DB101.DB0"; + // scrivo! + taskOk = S7WriteBB(ref MemBlock, memAddrWrite); + // attesa 3.5 sec sec + Thread.Sleep(3500); + // predispongo x reset valore 0... + MemBlock = S7.Net.Types.Byte.ToByteArray(0); + + break; + + // lasciato commentato, da rivalutare... +#if false + case taskType.setParameter: + // richiedo da URL i parametri WRITE da popolare + lgInfo("setParameter --> processMemWriteRequests"); + taskVal = processMemWriteRequests(); + // se restituiscce "" faccio altra prova... + if (string.IsNullOrEmpty(taskVal)) + { + // i parametri me li aspetto come stringa composta paramName|paramvalue + if (item.Value.Contains("|")) + { + string[] paramsJob = item.Value.Split('|'); + taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}"; + } + else + { + taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value"; + } + } + break; +#endif + + default: + taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; + break; + } + + lgInfo($"executeTask | task name: {tName} | task value: {taskVal}"); + // aggiungo task! + taskDone.Add(item.Key, taskVal); + if (!string.IsNullOrEmpty(memAddrWrite)) + { + // scrivo! + taskOk = S7WriteBB(ref MemBlock, memAddrWrite); + } + if (taskOk) + { + // aggiorno valore memoria... SE presente + if (memMap.mMapWrite.ContainsKey(item.Key)) + { + memMap.mMapWrite[item.Key].value = item.Value; + lgInfo($"Aggiornato valore in mMapWrite per {item.Key}"); + } + lgInfo($"Eseguita con successo S7WriteBB per executeTasks: {item.Key} | {item.Value}"); + } + else + { + lgError($"Errore in S7WriteBB durante executeTasks: {item.Key} | {item.Value}"); + } + } + } + return taskDone; + } + + #endregion Public Methods + } +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/IobSimula.cs b/IOB-WIN-NEXT/IobSimula.cs index 92787889..e4c29f4d 100644 --- a/IOB-WIN-NEXT/IobSimula.cs +++ b/IOB-WIN-NEXT/IobSimula.cs @@ -57,6 +57,11 @@ namespace IOB_WIN_NEXT /// protected DateTime lastSimData; + /// + /// Ultimo istante in cui sono stati ridotti dati simulazione duration + /// + protected DateTime lastRedDuration; + /// /// Matricola OPR simulato /// @@ -139,13 +144,19 @@ namespace IOB_WIN_NEXT lastWarnODL = adesso; lastEvCheck = adesso; lastSimData = adesso; + lastRedDuration = adesso; + // setup allarmi simulati + for (int i = 1; i <= 8; i++) + { + alarmMessages.Add($"Allarme {i:000}"); + } // sistemo parametri x simulazione... if (cIobConf.optPar.Count > 0) { if (!string.IsNullOrEmpty(getOptPar("PER_BASE"))) { int.TryParse(getOptPar("PER_BASE"), out periodoMSec); - // aggiungo NOISE... +/- 20% + // aggiungo NOISE... +/- 10% Random rnd = new Random(); int noise = rnd.Next(1, periodoMSec / 5); periodoMSec += noise - (periodoMSec / 10); @@ -198,6 +209,45 @@ namespace IOB_WIN_NEXT { } + private Random rnd = new Random(); + private int currSimAlarmCode = 0; + private List alarmMessages = new List(); + + /// + /// Decremento duration del bit indicato secondo stesse regole di ritardo dei bit di wait + /// + /// + protected void tryRedDuration(int bit2proc) + { + if (lastRedDuration.AddMilliseconds(periodoMSec) < DateTime.Now) + { + switch (bit2proc) + { + case 2: + bit2.duration--; + break; + case 3: + bit3.duration--; + break; + case 4: + bit4.duration--; + break; + case 5: + bit5.duration--; + break; + case 6: + bit6.duration--; + break; + case 7: + bit7.duration--; + break; + default: + break; + } + lastRedDuration = DateTime.Now; + } + } + /// /// Effettua decodifica aree memoria alla bitmap usata x MAPO /// @@ -329,12 +379,24 @@ namespace IOB_WIN_NEXT { // segnalo BIT B_input += (1 << 3); + // se non ancora fatto, simulo insorgenza allarme + if (currSimAlarmCode == 0) + { + // simulo una bitmap di max 8 allarmi, 1..255 + currSimAlarmCode = rnd.Next(1, 255); + // invio allarme, 0 --> sim + sendAlarmVariations("SIM_BANK", 0, 0, (uint)currSimAlarmCode, alarmMessages); + } // decremento duration - bit3.duration--; + tryRedDuration(3); // controllo se sia scaduta la duration... in quel caso reset... if (bit3.duration <= 0) { bit3 = setupSimPar("SIM_ALARM"); + // invio fine allarme: sim --> 0 + sendAlarmVariations("SIM_BANK", 0, (uint)currSimAlarmCode, 0, alarmMessages); + // simulo terminazione allarme + currSimAlarmCode = 0; } } else if (bit6.wait <= 0) @@ -342,7 +404,7 @@ namespace IOB_WIN_NEXT // segnalo BIT B_input += (1 << 6); // decremento duration - bit6.duration--; + tryRedDuration(6); // controllo se sia scaduta la duration... in quel caso reset... if (bit6.duration <= 0) { @@ -356,7 +418,7 @@ namespace IOB_WIN_NEXT // segnalo BIT NEGATO (emergenza) B_input -= (1 << 7); // decremento duration - bit7.duration--; + tryRedDuration(7); // controllo se sia scaduta la duration... in quel caso reset... if (bit7.duration <= 0) { @@ -370,7 +432,7 @@ namespace IOB_WIN_NEXT // segnalo BIT B_input += (1 << 4); // decremento duration - bit4.duration--; + tryRedDuration(4); // controllo se sia scaduta la duration... in quel caso reset... if (bit4.duration <= 0) { @@ -413,7 +475,7 @@ namespace IOB_WIN_NEXT } } // decremento duration - bit2.duration--; + tryRedDuration(2); // controllo se sia scaduta la duration... in quel caso reset... if (bit2.duration <= 0) { @@ -457,7 +519,7 @@ namespace IOB_WIN_NEXT else { // decremento duration - bit2.duration--; + tryRedDuration(2); if (bit2.duration <= 0) { bit2 = setupSimPar("SIM_PZCNT"); @@ -469,7 +531,7 @@ namespace IOB_WIN_NEXT // segnalo BIT B_input += (1 << 5); // decremento duration - bit5.duration--; + tryRedDuration(5); // controllo se sia scaduta la duration... in quel caso reset... if (bit5.duration <= 0) { @@ -579,10 +641,13 @@ namespace IOB_WIN_NEXT string[] param = fullVal.Split('|'); int.TryParse(param[0], out answ.wait); int.TryParse(param[1], out answ.duration); - // aggiongo noise, +/- 40%... - Random rnd = new Random(); - int noise = rnd.Next(1, answ.wait * 40 / 100); - answ.wait += noise - (answ.wait * 20 / 100); + // simulo valore wait: in media target, range +/- 80% + answ.wait = rnd.Next(answ.wait / 5, answ.wait * 9 / 5); + // simulo valore duration: in media target, range +/- 50% + answ.duration = rnd.Next(answ.duration / 2, answ.duration * 3 / 2); + // verifico siano > 0... + answ.wait = answ.wait > 1 ? answ.wait : 2; + answ.duration = answ.duration > 1 ? answ.duration : 2; } } } @@ -878,13 +943,31 @@ namespace IOB_WIN_NEXT if (lastEvCheck.AddMilliseconds(periodoMSec) < DateTime.Now) { // decremento contatore ultimo evento - bit2.wait--; - bit3.wait--; - bit4.wait--; - bit5.wait--; - simDich.wait--; - simRC.wait--; - simRS.wait--; + try + { + if (bit2 != null) + bit2.wait--; + + if (bit3 != null) + bit3.wait--; + + if (bit4 != null) + bit4.wait--; + + if (bit5 != null) + bit5.wait--; + + if (simDich != null) + simDich.wait--; + + if (simRC != null) + simRC.wait--; + + if (simRS != null) + simRS.wait--; + } + catch + { } lastEvCheck = DateTime.Now; } } diff --git a/IOB-WIN-NEXT/NLog.config b/IOB-WIN-NEXT/NLog.config index 124f6170..351a1daa 100644 --- a/IOB-WIN-NEXT/NLog.config +++ b/IOB-WIN-NEXT/NLog.config @@ -21,9 +21,9 @@ /> - - - - + + + + +