Files
mapo-mono/MP.MONO.DECODER/Program.cs
T
Samuele E. Locatelli 87b159b167 update decodifica status
- errore in decodifica prog name (stringa)
2022-06-23 14:42:08 +02:00

694 lines
28 KiB
C#

using Microsoft.Extensions.Configuration;
using MP.MONO.Core;
using MP.MONO.Core.CONF;
using MP.MONO.Core.DTO;
using MP.MONO.Data;
using MP.MONO.Data.Controllers;
using MP.MONO.Data.DbModels;
using MP.MONO.DECODER;
using Newtonsoft.Json;
using NLog;
using NLua;
using StackExchange.Redis;
using System.Reflection;
using static MP.MONO.Core.Enums;
// See https://aka.ms/new-console-template for more information
// init parte config, vedere https://blog.hildenco.com/2020/05/configuration-in-net-core-console.html
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
var builder = new ConfigurationBuilder()
.AddJsonFile($"appsettings.json", true, true)
.AddJsonFile($"appsettings.{env}.json", true, true)
.AddEnvironmentVariables();
var config = builder.Build();
// init LOG
Logger Log = LogManager.GetCurrentClassLogger();
// initi va di base
string lineSep = "---------------------------------------------";
Console.WriteLine(lineSep);
Console.WriteLine("Start DECODER with LUA integration!");
Console.WriteLine($"vers.{Assembly.GetExecutingAssembly().GetName().Version}");
Console.WriteLine(lineSep);
Console.WriteLine("");
Console.WriteLine("Running - press CTRL-C to stop");
Console.WriteLine(lineSep);
Console.WriteLine("");
// init DB
// init info x DB
string dbServerAddr = config["DbConfig:Server"];
string nKey = config["DbConfig:nKey"];
string sKey = config["DbConfig:sKey"];
DbConfig.InitDb(dbServerAddr, nKey, sKey);
// inizializzo il DB e creo (se necessario) l'utente
DbConfig.CheckUser(nKey, sKey);
// verifico se serve applicazione migrazioni
DbConfig.ExecMigrationMain();
//DbConfig.ExecMigrationIdentity();
// altri parametri per check vari
string connStringDB = DbConfig.CONNECTION_STRING;
MpDbController dbController = null!;
if (string.IsNullOrEmpty(connStringDB))
{
Log.Error("ConnString empty!");
}
else
{
dbController = new MpDbController();
Log.Info("DbController OK");
Console.WriteLine("DbController OK");
}
// init info di base
int MachineId = 1;
int.TryParse(config.GetValue<string>("MachineId"), out MachineId);
// init oggetti REDIS + messagePipe...
ConnectionMultiplexer.SetFeatureFlag("preventthreadtheft", true);
ConnectionMultiplexer redisConn = ConnectionMultiplexer.Connect(config.GetConnectionString("Redis"));
IDatabase? redisDb = redisConn.GetDatabase();
// preparo oggetti da configurare
AlarmReportingMode alarmMode = AlarmReportingMode.ND;
List<BaseAlarmBankConf>? alarmsBankBitConf = new List<BaseAlarmBankConf>();
List<BaseAlarmRawConf>? alarmsRListConf = new List<BaseAlarmRawConf>();
List<string>? activeAlarmList = new List<string>();
List<AlarmListModel>? alarmsRecorded = new List<AlarmListModel>();
List<MachineMode>? machineModeConf = new List<MachineMode>();
List<MachineStatus>? machineStatusConf = new List<MachineStatus>();
MachineDTO machinePlate = new MachineDTO();
// gestione configurazioni da redis
setupConf();
/* --------------------------------
* Setup Gestione ALLARMI
* --------------------------------*/
// init classe gestione allarmi con LUA
AlarmsManager alarmsMan = new AlarmsManager();
// inizializzo gestione messagePipe da Redis x allarmi
MessagePipe alarmsSendPipe = new MessagePipe(redisConn, Constants.ALARM_M_QUEUE);
MessagePipe alarmsRecvPipe = new MessagePipe(redisConn, Constants.ALARM_RAW_QUEUE);
// datetime dell'inizio esecuzione task... x usare un semaforo di veto doppia esecuzione entro 30 sec
DateTime lastExecAlarms = DateTime.Now.AddHours(-1);
// registro gestione eventi
alarmsRecvPipe.EA_NewMessage += AlarmsValPipe_EA_NewMessage;
/* --------------------------------
* Setup Gestione Parametri
* --------------------------------*/
ParamsManager paramMan = new ParamsManager();
// inizializzo gestione messagePipe da Redis x allarmi
MessagePipe paramsSendPipe = new MessagePipe(redisConn, Constants.PARAMS_M_QUEUE);
MessagePipe paramsRecvPipe = new MessagePipe(redisConn, Constants.PARAMS_RAW_QUEUE);
// datetime dell'inizio esecuzione task... x usare un semaforo di veto doppia esecuzione entro 30 sec
DateTime lastExecParams = DateTime.Now.AddHours(-1);
// registro gestione eventi
paramsRecvPipe.EA_NewMessage += ParamsValPipe_EA_NewMessage;
/* --------------------------------
* Setup Gestione MachineStatus
* --------------------------------*/
MPStatusManager mpStatusMan = new MPStatusManager();
// inizializzo gestione messagePipe da Redis x allarmi
MessagePipe mpStatusSendPipe = new MessagePipe(redisConn, Constants.STATUS_M_QUEUE);
MessagePipe mpStatusRecvPipe = new MessagePipe(redisConn, Constants.STATUS_RAW_QUEUE);
// datetime dell'inizio esecuzione task... x usare un semaforo di veto doppia esecuzione entro 30 sec
DateTime lastExecStatus = DateTime.Now.AddHours(-1);
// registro gestione eventi
mpStatusRecvPipe.EA_NewMessage += MpStatusRecvPipe_EA_NewMessage;
/* --------------------------------
* Setup Gestione Counters
* --------------------------------*/
CounterManager counterMan = new CounterManager();
// inizializzo gestione messagePipe da Redis x allarmi
MessagePipe counterSendPipe = new MessagePipe(redisConn, Constants.COUNT_M_QUEUE);
MessagePipe counterRecvPipe = new MessagePipe(redisConn, Constants.COUNT_RAW_QUEUE);
// datetime dell'inizio esecuzione task... x usare un semaforo di veto doppia esecuzione entro 30 sec
DateTime lastExecCounters = DateTime.Now.AddHours(-1);
// registro gestione eventi
counterRecvPipe.EA_NewMessage += CounterRecvPipe_EA_NewMessage;
/* --------------------------------
* Funzioni / metodi accessori
* --------------------------------*/
/// <summary>
/// Recupero da redis le conf (es modi,stati,allarmi)
/// </summary>
void setupConf()
{
// recupero valori e deserializzo
string rawData = "";
// machine status (display) conf
rawData = redisDb.StringGet(Constants.MACHINE_CONF_PLATE);
if (!string.IsNullOrEmpty(rawData))
{
var currData = JsonConvert.DeserializeObject<MachineDTO>(rawData);
machinePlate = currData != null ? currData : new MachineDTO();
}
// machine status (display) conf
rawData = redisDb.StringGet(Constants.DISPLSTATUS_CONF_KEY);
if (!string.IsNullOrEmpty(rawData))
{
machineStatusConf = JsonConvert.DeserializeObject<List<MachineStatus>>(rawData);
}
// machine mode
rawData = redisDb.StringGet(Constants.MODE_CONF_KEY);
if (!string.IsNullOrEmpty(rawData))
{
machineModeConf = JsonConvert.DeserializeObject<List<MachineMode>>(rawData);
}
// allarmi..
rawData = redisDb.StringGet(Constants.ALARMS_MODE_KEY);
alarmMode = JsonConvert.DeserializeObject<AlarmReportingMode>(rawData);
// elenco allarmi già registrati (cache DB)
rawData = redisDb.StringGet(Constants.ALARMS_SETT_RLIST_KEY);
if (!string.IsNullOrEmpty(rawData))
{
alarmsRecorded = JsonConvert.DeserializeObject<List<AlarmListModel>>(rawData);
}
// ora la conf specifica
rawData = redisDb.StringGet(Constants.ALARMS_CONF_KEY);
if (!string.IsNullOrEmpty(rawData))
{
if (alarmMode == AlarmReportingMode.RawList)
{
alarmsRListConf = JsonConvert.DeserializeObject<List<BaseAlarmRawConf>>(rawData);
}
else
{
alarmsBankBitConf = JsonConvert.DeserializeObject<List<BaseAlarmBankConf>>(rawData);
}
}
}
/// <summary>
/// Gestione evento ricezione messaggi allarmi secondo tipologia attiva...
/// </summary>
void AlarmsValPipe_EA_NewMessage(object? sender, EventArgs e)
{
PubSubEventArgs currArgs = (PubSubEventArgs)e;
// conversione on-the-fly List<string> --> allarmi
if (!string.IsNullOrEmpty(currArgs.newMessage))
{
DateTime adesso = DateTime.Now;
if (alarmMode == AlarmReportingMode.RawList)
{
try
{
// decodifico allarmi ricevuti
var alarmList = JsonConvert.DeserializeObject<List<string>>(currArgs.newMessage);
List<AlarmRecModel> alarmRecList = new List<AlarmRecModel>();
List<AlarmLogModel> alarmLogList = new List<AlarmLogModel>();
List<AlarmListModel>? mutedAlarmsList = new List<AlarmListModel>();
string rawData = redisDb.StringGet(Constants.ALARMS_SETT_RLIST_KEY);
if (!string.IsNullOrEmpty(rawData))
{
mutedAlarmsList = JsonConvert.DeserializeObject<List<AlarmListModel>>(rawData);
}
if (mutedAlarmsList == null)
{
mutedAlarmsList = dbController.AlarmListGetAll();
}
// rileggo da REDIS la conf attuale allarmi già attivi da area ALARM_CURR_KEY
List<string>? lastAlarms = new List<string>();
rawData = redisDb.StringGet(Constants.ALARM_CURR_KEY);
// se trovati uso questi...
if (!string.IsNullOrEmpty(rawData))
{
lastAlarms = JsonConvert.DeserializeObject<List<string>>(rawData);
}
// altrimenti parto da vuoto
else
{
lastAlarms = new List<string>();
}
// ciclo x ogni allarme ricevuto x vedere se sia INIZIATO
if (alarmList != null)
{
// ciclo x ogni allarme attivo x verificare se si sia CHIUSO
foreach (var newAlarm in alarmList)
{
// in primis... se è muted --> lo escludo...
bool isMuted = false;
var maybeMuted = mutedAlarmsList.Where(x => x.FullValue == newAlarm).FirstOrDefault();
if (maybeMuted != null)
{
isMuted = maybeMuted.Muted;
}
// cerco l'allarme nell'elenco degli allarmi dal DB
var foundAlarm = alarmsRecorded
.Where(x => x.FullValue == newAlarm)
.FirstOrDefault();
// se non lo trovo --> chiamo procedura che verifica su DB, eventualmente inserisce, restituisce nuovo elenco
if (foundAlarm == null)
{
// salvo sul DB
foundAlarm = dbController.AlarmListInsert(newAlarm);
// ora rileggo ed aggiorno redis e cerco di nuovo record...
alarmsRecorded = dbController.AlarmListGetAll();
redisDb.StringSet(Constants.ALARMS_SETT_RLIST_KEY, JsonConvert.SerializeObject(alarmsRecorded));
}
if (!isMuted && lastAlarms != null)
{
if (!lastAlarms.Contains(newAlarm))
{
if (foundAlarm != null)
{
// segno come iniziato...
AlarmRecModel newAlarmRec = new AlarmRecModel()
{
MachineId = MachineId,
DtStart = adesso,
DtEnd = adesso,
AlarmId = foundAlarm.AlarmId
};
alarmRecList.Add(newAlarmRec);
}
}
}
else
{
// rimuovo da alarmList
alarmList.Remove(newAlarm);
}
}
}
// processo elenco allarmi già presenti
if (lastAlarms != null)
{
// ciclo x ogni allarme attivo x verificare se si sia CHIUSO
foreach (var oldData in lastAlarms)
{
var trovato = alarmList.Contains(oldData);
if (!trovato)
{
// se non lo trovo
var foundAlarm = alarmsRecorded
.Where(x => x.FullValue == oldData)
.FirstOrDefault();
if (foundAlarm != null)
{
// salvo sul DB
_ = dbController.AlarmRecCloseActive(foundAlarm.AlarmId);
}
}
}
}
// verifico se devo scrivere
bool wALog = lastAlarms.Count != alarmList.Count;
if (!wALog)
{
// verifico se ci siano differenze...
wALog = alarmList.Union(lastAlarms).Count() != lastAlarms.Count;
}
// salvo se c'è stata variazione...
if (wALog)
{
// preparo dati x alarmLog
AlarmLogModel newAlarmLog = new AlarmLogModel()
{
MachineId = MachineId,
DtRif = adesso,
MemAddress = "ND",
Index = 0,
Status = (uint)alarmList.Count,
ValDecoded = alarmList.Count > 0 ? string.Join(", ", alarmList) : "All OK"
};
alarmLogList.Add(newAlarmLog);
}
// serializzo l'elenco allarmi...
string serAlarms = "[]";
serAlarms = JsonConvert.SerializeObject(alarmList);
// invio sulla message pipeline corretta TUTTI gli allarmi serializzati
alarmsSendPipe.saveAndSendMessage(Constants.ALARM_CURR_KEY, serAlarms);
// salvo sul DB
_ = dbController.AlarmRecInsertMany(alarmRecList).Result;
_ = dbController.AlarmLogInsertMany(alarmLogList).Result;
// salvo nuovo elenco allarmi
lastAlarms = alarmList;
}
catch
{ }
}
else
{
try
{
// verifico codici allarmi ricevuti
var alarmList = JsonConvert.DeserializeObject<Dictionary<string, uint>>(currArgs.newMessage);
if (alarmList != null)
{
// variabili accessorie
List<string> activeAlarmList = new List<string>();
List<AlarmLogModel> alarmLogList = new List<AlarmLogModel>();
// rileggo da REDIS la conf attuale allarmi da area ALARMS_SETT_KEY, altrimenti uso quella letta inizialmente da conf base
List<BaseAlarmBankConf>? currAlarmsBankConf = new List<BaseAlarmBankConf>();
string rawData = redisDb.StringGet(Constants.ALARMS_SETT_BBIT_KEY);
// se trovati uso questi...
if (!string.IsNullOrEmpty(rawData))
{
currAlarmsBankConf = JsonConvert.DeserializeObject<List<BaseAlarmBankConf>>(rawData);
}
// altrimenti uso quelli di default inizialmente letti
else
{
currAlarmsBankConf = alarmsBankBitConf;
}
if (currAlarmsBankConf != null)
{
// ciclo x ogni bank di allarmi configurato
foreach (var alarmData in currAlarmsBankConf)
{
// recupero valore allarme
var bankVal = alarmList.FirstOrDefault(x => x.Key == alarmData.memAddr);
uint actVal = !string.IsNullOrEmpty(bankVal.Key) ? bankVal.Value : 0;
// valutare se dividere in 2 da 16... FIXME TODO
var bankAlarmList = AlarmsManager.processData(alarmData.memAddr, alarmData.messages, alarmData.silenceMask[0], alarmData.disableMask[0], alarmData.alarmsState[0], ref actVal);
// salvo nuovo valore in oggetto...
if (alarmData.alarmsState[0] != actVal)
{
alarmData.alarmsState[0] = actVal;
// aggiungo...
activeAlarmList.AddRange(bankAlarmList);
AlarmLogModel newAlarmLog = new AlarmLogModel()
{
MachineId = MachineId,
DtRif = adesso,
MemAddress = bankVal.Key,
Index = alarmData != null ? alarmData.index : 0,
Status = alarmData != null ? (uint)bankVal.Value & alarmData.silenceMask[0] & alarmData.disableMask[0] : (uint)bankVal.Value,
ValDecoded = bankAlarmList.Count > 0 ? string.Join(", ", bankAlarmList) : "All OK"
};
alarmLogList.Add(newAlarmLog);
}
}
}
// salvo status aggiornato allarme...
redisDb.StringSet(Constants.ALARMS_SETT_BBIT_KEY, JsonConvert.SerializeObject(currAlarmsBankConf));
// serializzo l'elenco allarmi...
string serAlarms = "[]";
serAlarms = JsonConvert.SerializeObject(activeAlarmList);
// invio sulla message pipeline corretta TUTTI gli allarmi serializzati
alarmsSendPipe.saveAndSendMessage(Constants.ALARM_CURR_KEY, serAlarms);
// verifico NON ci sia veto di scrittura... 60 sec...
if (adesso.Subtract(lastExecAlarms).TotalSeconds > 60)
{
lastExecAlarms = adesso;
if (dbController != null)
{
// salvo sul DB
_ = dbController.AlarmLogInsertMany(alarmLogList).Result;
}
}
}
}
catch (Exception exc)
{
Log.Error($"Eccezione in AlarmsValPipe_EA_NewMessage, mode {alarmMode}:{Environment.NewLine}{exc}");
}
}
}
}
/// <summary>
/// Gestione evento ricezione messaggi parametri
/// </summary>
void ParamsValPipe_EA_NewMessage(object? sender, EventArgs e)
{
PubSubEventArgs currArgs = (PubSubEventArgs)e;
// conversione on-the-fly Dictionary<string,int> --> parametri valorizzati (tra quelli configurati)
if (!string.IsNullOrEmpty(currArgs.newMessage))
{
DateTime adesso = DateTime.Now;
try
{
// verifico codici ricevuti
var paramsList = JsonConvert.DeserializeObject<Dictionary<string, double>>(currArgs.newMessage);
if (paramsList != null)
{
// recupero elenco parametri salvati in redis...
List<DisplayDataDTO>? redisParamConf = new List<DisplayDataDTO>();
List<DisplayDataDTO> updatedParams = new List<DisplayDataDTO>();
string rawData = redisDb.StringGet(Constants.PARAMS_CONF_KEY);
if (!string.IsNullOrEmpty(rawData))
{
redisParamConf = JsonConvert.DeserializeObject<List<DisplayDataDTO>>(rawData);
// se ho i parametri...
if (redisParamConf != null)
{
// ciclo x ogni valore ricevuto da message service...
foreach (var item in paramsList)
{
// cerco il parametro corrispondente...
var currParam = redisParamConf.FirstOrDefault(x => x.Title == item.Key);
if (currParam != null)
{
currParam.ValueNum = item.Value;
currParam.Value = $"{item.Value.ToString(currParam.DisplFormat)}";
// aggiungo a lista...
updatedParams.Add(currParam);
}
}
// verifico NON ci sia veto di scrittura... 60 sec...
if (adesso.Subtract(lastExecParams).TotalSeconds > 60)
{
lastExecParams = adesso;
if (dbController != null)
{
// verifico x ogni parametro se sia completato il periodo di campionamento...
var params2save = paramMan.processData(paramsList, redisParamConf);
if (params2save.Count > 0)
{
// salvo sul DB
_ = dbController.DataLogInsertMany(params2save).Result;
}
}
}
}
}
// invio sulla message pipeline corretta TUTTI i parametri aggiornati serializzati
string updRawVal = JsonConvert.SerializeObject(redisParamConf);
paramsSendPipe.saveAndSendMessage(Constants.PARAMS_CURR_KEY, updRawVal);
}
}
catch (Exception exc)
{
Log.Error($"Eccezione in ParamsValPipe_EA_NewMessage:{Environment.NewLine}{exc}");
}
}
}
/// <summary>
/// Gestione evento ricezione messaggi status
/// </summary>
void MpStatusRecvPipe_EA_NewMessage(object? sender, EventArgs e)
{
PubSubEventArgs currArgs = (PubSubEventArgs)e;
// conversione on-the-fly Dictionary<string,int> --> parametri valorizzati (tra quelli configurati)
if (!string.IsNullOrEmpty(currArgs.newMessage))
{
DateTime adesso = DateTime.Now;
try
{
// verifico codici ricevuti
var dataList = JsonConvert.DeserializeObject<Dictionary<string, string>>(currArgs.newMessage);
if (dataList != null)
{
/************************************************************************
*
* <BROADCAST_EVENT DESCRIPTION = "MACHINE STATUS" IDENTIFIER = "1" >
* <!--
* DESCRIPTION:
* 0: MACHINE OFF
* 1: MACHINE ON
* -->
*
* <BROADCAST_EVENT DESCRIPTION = "PROC 1 STATUS" IDENTIFIER = "500" >
* <!--
* DESCRIPTION:
* 1: IDLE
* 2: CYCLE (RUN)
* 3: HOLD (HOLD, RUNH, HRUN)
* 6: ERROR
* 8: RESET
* 11: PAUSE (WAIT, INPUT)
* -->
*
* <BROADCAST_EVENT DESCRIPTION = "PROC 1 MODE" IDENTIFIER = "501" >
* <!--
* DESCRIPTION:
* 1: MDI
* 2: AUTO
* 3: STEP (BLK-BLK)
* 4: MANU (MANJOG)
* 5: MANJ (INCJOG)
* 6: RETPROF (PROFILE)
* 7: HOME
* 8: HPG (HANDWHEEL)
* -->
*
*
*************************************************************************/
// recupero elenco parametri salvati in redis...
MachineDTO? machinePlate = new MachineDTO();
string rawData = redisDb.StringGet(Constants.MACHINE_CONF_PLATE);
if (!string.IsNullOrEmpty(rawData))
{
machinePlate = JsonConvert.DeserializeObject<MachineDTO>(rawData);
}
int machStatus = 0;
int procStatus = 0;
int procMode = 0;
string currKey = "";
// ora processo il messaggio ricevuto x stati e modi vari
currKey = "MACHINE STATUS";
if (dataList.ContainsKey(currKey))
{
int.TryParse(dataList[currKey], out machStatus);
}
currKey = "PROCESS STATUS";
if (dataList.ContainsKey(currKey))
{
int.TryParse(dataList[currKey], out procStatus);
}
currKey = "PROCESS MODE";
if (dataList.ContainsKey(currKey))
{
int.TryParse(dataList[currKey], out procMode);
}
// fix me todo inserire gestione program name!!!
if (machStatus == 0)
{
machinePlate.StatusId = 7;
}
else
{
switch (procMode)
{
case 1:
machinePlate.StatusId = 8;
break;
case 2:
machinePlate.StatusId = 2;
break;
case 3:
machinePlate.StatusId = 9;
break;
case 4:
machinePlate.StatusId = 5;
break;
case 5:
machinePlate.StatusId = 10;
break;
case 6:
machinePlate.StatusId = 11;
break;
case 7:
machinePlate.StatusId = 12;
break;
case 8:
machinePlate.StatusId = 13;
break;
default:
break;
}
}
// eseguo cablata la gestione x ora... rispetto a MachineStatus + MachineMode invierò un machineDTO
switch (procStatus)
{
case 1:
machinePlate.ModeId = 2;
break;
case 2:
machinePlate.ModeId = 1;
break;
case 3:
machinePlate.ModeId = 3;
break;
case 6:
machinePlate.ModeId = 8;
break;
case 8:
machinePlate.ModeId = 9;
break;
case 11:
machinePlate.ModeId = 10;
break;
default:
break;
}
// invio sulla message pipeline corretta TUTTI i parametri aggiornati serializzati
string updRawVal = JsonConvert.SerializeObject(machinePlate);
paramsSendPipe.saveAndSendMessage(Constants.STATUS_CURR_KEY, updRawVal);
}
}
catch (Exception exc)
{
Log.Error($"Eccezione in MpStatusRecvPipe_EA_NewMessage:{Environment.NewLine}{exc}");
}
}
};
/// <summary>
/// Gestione evento ricezione messaggi status
/// </summary>
void CounterRecvPipe_EA_NewMessage(object? sender, EventArgs e)
{
// fare...
}
/* --------------------------------
* MAIN
* --------------------------------*/
// Ciclo infinito x attesa chiusura con CTRL-C
do
{
Thread.Sleep(100);
} while (true);