diff --git a/CMS_CORE_Library/CMS_CORE_Library.csproj b/CMS_CORE_Library/CMS_CORE_Library.csproj index b736dbc..d92774a 100644 --- a/CMS_CORE_Library/CMS_CORE_Library.csproj +++ b/CMS_CORE_Library/CMS_CORE_Library.csproj @@ -153,6 +153,7 @@ + diff --git a/CMS_CORE_Library/Models/CmsError.cs b/CMS_CORE_Library/Models/CmsError.cs index 0bd46d7..290bea2 100644 --- a/CMS_CORE_Library/Models/CmsError.cs +++ b/CMS_CORE_Library/Models/CmsError.cs @@ -72,6 +72,7 @@ namespace CMS_CORE_Library.Models OSAI_TT_FOLDER_NOT_FOUND = 27, OPTION_NOT_CONSISTENT = 28, WRONG_CMS_PP = 29, - SIEMENS_TOOL_TABLE_ERROR = 30 + SIEMENS_TOOL_TABLE_ERROR = 30, + PLC_IP_NOT_FOUND = 31 } } \ No newline at end of file diff --git a/CMS_CORE_Library/Models/DataStructures.cs b/CMS_CORE_Library/Models/DataStructures.cs index b873ba3..4e6aa2b 100644 --- a/CMS_CORE_Library/Models/DataStructures.cs +++ b/CMS_CORE_Library/Models/DataStructures.cs @@ -178,6 +178,7 @@ namespace CMS_CORE_Library.Models public static CmsError INCORRECT_PARAMETERS_ERROR = new CmsError(CMS_ERROR_CODES.INCORRECT_PARAMETERS, "error_incorrect_parameters"); public static CmsError INCORRECT_LANGUAGE_ERROR = new CmsError(CMS_ERROR_CODES.NC_LANGUAGE_ERROR, "error_invalid_language"); public static CmsError SIEMENS_ENVIRONMENT_NOT_FOUND_ERROR = new CmsError(CMS_ERROR_CODES.SIEMENS_ENVIRONMENT_NOT_FOUND, "error_siemens_enviroment_not_found_error"); + public static CmsError PLC_IP_NOT_FOUND_ERROR = new CmsError(CMS_ERROR_CODES.PLC_IP_NOT_FOUND, "error_plc_ip_not_found_error"); public static CmsError SIEMENS_HMI_NOT_RUNNING_ERROR = new CmsError(CMS_ERROR_CODES.SIEMENS_HMI_NOT_RUNNING, "error_siemens_hmi_not_running"); public static CmsError MAX_TOOL_REACHED_ERROR = new CmsError(CMS_ERROR_CODES.MAX_TOOL_REACHED, "error_max_tool_reached"); public static CmsError MAX_EDGES_PER_TOOL_REACHED_ERROR = new CmsError(CMS_ERROR_CODES.MAX_EDGES_PER_TOOL_REACHED, "error_max_edges_per_tool_reached"); diff --git a/CMS_CORE_Library/S7Net/Nc_S7Net.cs b/CMS_CORE_Library/S7Net/Nc_S7Net.cs new file mode 100644 index 0000000..fd87d24 --- /dev/null +++ b/CMS_CORE_Library/S7Net/Nc_S7Net.cs @@ -0,0 +1,7071 @@ +using CMS_CORE_Library.Models; +using Siemens.Sinumerik.Operate.Services; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Windows.Forms; +using System.Xml.Linq; +using static CMS_CORE_Library.Models.DataStructures; +using static CMS_CORE_Library.Nc; +using static CMS_CORE_Library.Siemens.MEMORY_ADDRESS; +using static CMS_CORE_Library.ToolConfigurations; +using static CMS_CORE_Library.Utils.Nc_Utils; +using static Siemens.Sinumerik.Operate.Services.ToolMngmntSvc; + +namespace CMS_CORE_Library.S7Net +{ + public class Nc_S7Net : Nc + { + // Global Constants +#if false + private const string OptionHMINotRunning = "P66"; + + private const string HMIDllName = "Wrapper.dll"; +#endif + + private const string NcNotFound = "Missing response"; + private const string NcNotFound2 = "networking error"; +#if false + private const string NcNotFound3 = "Nc not Connected"; + private const string SinumerikEnvVar = "HMI_INSTALL_DIR"; +#endif + private const int IDMinPLCMessage = 700000; + private const int IDMaxPLCMessage = 799999; + private const int IDMinChannel = 10000; + private const int IDMaxChannel = 19999; + +#if false + // Siemens Path Constants + private const string MAX_CHANNEL_NO_PATH = "/Nck/Configuration/maxnumChannels"; + + private const string CONF_CHANNEL_NO_PATH = "/Nck/Configuration/numChannels"; + private const string NC_TYPE_PATH = "/Nck/Configuration/nckType"; + private const string NC_VERSION_PATH = "/Nck/Configuration/nckVersion"; + private const string LANGUAGE_PATH = "/Nck/Configuration/anLanguageOnHmi"; + private const string SERIAL_NO_PATH = "/Nck/State/hwProductSerialNrL"; + private const string NC_TIME_PATH = "/Nck/State/sysTimeBCD"; + private const string NC_GENERIC_MODE_PATH = "/Bag/State/opMode"; + private const string NC_GENERIC_STATE_PATH = "/Channel/State/chanStatus"; + private const string JOG_INCR_PATH = "/Channel/GeometricAxis/actIncrVal"; + private const string ADVANCED_JOG_PATH = "/Channel/State/machFunc"; + private const string RELATIVE_POS_PATH = "/Channel/GeometricAxis/actToolBasPosEN"; + private const string UNIT_OF_MEASURE = "/Nck/Configuration/basicLengthUnit"; + + private const string ACT_PROG_LINES_PATH = "/Channel/ProgramInfo/actPartProgram"; + private const string ACT_PROG_NAME_PATH = "/Channel/ProgramPointer/progName"; + private const string MAGAZINE_ACTION_PATH = "DB258.DBB4000"; + + // TOOLS + private const string NC_TOOL_FILE_PATH = "//NC/ACT.DIR/TO.DIR/TO_INI.INI"; + private const string LOCALE_TOOL_FILE_PATH = "C:\\CMS\\Active\\TMP\\TO_INI.INI"; +#endif + + // Global Variables + private static DateTime Last_Static_Read; + + private ushort TimeoutConn; + private static string Cnc_name; + private static string Cnc_SftVersion; + private static string Cnc_SeriesNum; + private static string Cms_MachNumber; + private static uint ConfChannelNo; + private static uint MaxChannelNo; + private static uint SiemensLanguage; + private static string UnitOfMeasure; + + // Alarms data + private AlarmSvc SiemensAlmSvc = null; + private Alarm[] SiemensAlarms; + +#if false + // Tool table listeners + private static ToolMngmntSvc SiemensToolSvc = null; + + private static DataSvc MagazinePositionSvc = null; + private static DataSvc MagazineActionsSvc = null; + + private Guid ToolMngmtListGuid = Guid.Empty; + + // Magazine config parameters + private static int MAX_TOOL_NUMER; + + private static int MAX_EDGES_PER_TOOL; + private static int MAX_TOOLS_PER_FAMILY; + private static int MAX_MULTITOOLS_NUMBER; + private static int MAX_TOOLS_PER_MULTITOOL; + private static int MAX_MULTITOOLS_LOCATIONS; + + private static bool LIFE_OPTION_ACTIVE; + private static bool MULTITOOL_OPTION_ACTIVE; + + private const string PLC_MESSAGES_FILE_PATH = "C:\\Program Files (x86)\\Siemens\\MotionControl\\oem\\sinumerik\\hmi\\lng\\"; + private static readonly string AXES_FILE_PATH = AppDomain.CurrentDomain.BaseDirectory + "\\Config\\axesConfig.xml"; + + // axis data + private static List AxesData = new List(); + public static uint multitoolsNumber = 0; + + public static uint MAX_AXES_FOR_PROCESS = 20; + + // File paths + public const string BASE_FILE_PATH = "//NC/"; + public const string NC_FILE_PATH = "MPF.DIR"; + + private static DataSvc AxesSvc; + private static DataSvc SelectedProcessSvc; + private static ushort SelectedProcess = 0; + + private static Dictionary MachineAxesPosition = new Dictionary(); + private static Dictionary ToGoAxesPosition = new Dictionary(); + private static Dictionary InterpAxesPosition = new Dictionary(); + private static Dictionary ProgrammedAxisPosition = new Dictionary(); +#endif + + private bool EnableAlarms; + private bool EnableHeaters; + private bool EnableModules; + private bool EnableParameters; + private bool EnableProd; + + private bool EnableAxes; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #region Contructor & global methods + + /// + ///Instantiate The NC-S7Net Class + /// + ///Send/Recieve timeout connection [mS] + public Nc_S7Net(ushort ConnectionTimeOut) + { + //Setup options + this.EnableAlarms = true; + this.EnableHeaters = true; + this.EnableModules = true; + this.EnableParameters = true; + this.EnableProd = true; + + this.EnableAxes = false; + + //Setup timeout + TimeoutConn = ConnectionTimeOut; + // FIXME: modificare in allarme generico bitmap? + SiemensAlarms = new Alarm[] { }; + } + + /// + /// Instantiate The NC-Siemens Class + /// + /// Send/Recieve timeout connection [mS] + /// Enable Axes Svc + /// Enable Alarms Svc + /// Enable Heaters Svc + /// Enable Modules Svc + /// Enable Parameters Svc + /// Enable Prod Svc + public Nc_S7Net(ushort ConnectionTimeOut, bool EnableAxes, bool EnableAlarms, bool EnableHeaters, bool EnableModules, bool EnableParameters, bool EnableProd) + { + //Setup options + this.EnableAlarms = EnableAlarms; + this.EnableAxes = EnableAxes; + this.EnableHeaters = EnableHeaters; + this.EnableModules = EnableModules; + this.EnableParameters = EnableParameters; + this.EnableProd = EnableProd; + + //Setup timeout + TimeoutConn = ConnectionTimeOut; + SiemensAlarms = new Alarm[] { }; + } + + public override CmsError NC_Connect() + { + // Try to get information + try + { + // Check if Siemens Environment is started + CmsError cmsError = CheckS7Ping(); + if (cmsError.IsError()) + return cmsError; + + // Check connection + Item item = new Item("DB258.DBX0.0"); + DataSvc svc = new DataSvc(); + + svc.Read(item); + Connected = true; + + // InitializeSiemens objects + if (this.EnableAxes) + { + if (AxesSvc == null) + AxesSvc = new DataSvc(); + } + + if (SelectedProcessSvc == null) + { + SelectedProcessSvc = new DataSvc(); + + SelectedProcessSvc.Subscribe(ManageSelectedProcess, new Item[] + { + new Item() { Path = "DB258.DBX2582.2" }, + new Item() { Path = "DB258.DBX2586.2" }, + new Item() { Path = "DB258.DBX2590.2" }, + new Item() { Path = "DB258.DBX2594.2" }, + new Item() { Path = "DB258.DBX2598.2" }, + new Item() { Path = "DB258.DBX2602.2" }, + }); + } + + //Setup the alarms (Only managed in this way (Siemens Thread) + + if (this.EnableAlarms) + { + SiemensAlarms = new Alarm[] { }; + SiemensAlmSvc = new AlarmSvc(ConvertToSTEPLanguage(SiemensLanguage).ThreeLetterISOLanguageName); + SiemensAlmSvc.Subscribe(AlarmsChanged); + Infrastructure.SubscribeLanguageChanged(NcLanguageChanged); + } + + if (this.EnableTools) + { + // Setup tooltable listeners + if (SiemensToolSvc == null) + { + SiemensToolSvc = new ToolMngmntSvc(1); + ToolMngmtListGuid = SiemensToolSvc.Subscribe(ToolMngmtSvcHandler); + SetupToolTableData(); + } + + // Setup magazine position listener + if (MagazinePositionSvc == null) + { + MagazinePositionSvc = new DataSvc(); + SetupMagazinePositionListener(); + } + + // Setup magazine action + if (MagazineActionsSvc == null) + { + MagazineActionsSvc = new DataSvc(); + SetupMagazineActionListener(); + } + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + private void ManageSelectedProcess(Guid guid, Item[] item, DataSvcStatus[] status) + { + SelectedProcess = 0; + // Set selectedProcess + for (int i = 0; i < item.Count(); i++) + { + if (status[i].Ok) + { + if (Convert.ToBoolean(item[i].Value)) + SelectedProcess = (ushort)(i + 1); + } + } + + if (this.EnableAxes) + { + // Clean listener + AxesSvc.UnSubscribe(ManageAxes); + + if (SelectedProcess > 0) + { + List axesConf = new List(); + + AXES_RAxesNames(SelectedProcess, ref AxesData); + + List axesData = new List(); + foreach (var conf in AxesData) + { + // Setup the items to be subscribed + // Machine + axesData.Add(new Item() { Path = string.Format("/Nck/{0}[u{1},{2}]", "MachineAxis/actToolBasePos", SelectedProcess, conf.Id), SymbolicName = conf.Id.ToString() }); + // Programmed + axesData.Add(new Item() { Path = string.Format("/Channel/{0}[u{1},{2}]", "GeometricAxis/cmdProgPos", SelectedProcess, conf.Id), SymbolicName = conf.Id.ToString() }); + // Interp + axesData.Add(new Item() { Path = string.Format("/Channel/{0}[u{1},{2}]", "GeometricAxis/actToolEdgeCenterPos", SelectedProcess, conf.Id), SymbolicName = conf.Id.ToString() }); + // Dist to go + axesData.Add(new Item() { Path = string.Format("/Channel/{0}[u{1},{2}]", "MachineAxis/toolBaseDistToGo", SelectedProcess, conf.Id), SymbolicName = conf.Id.ToString() }); + } + + if (axesData.Count() > 0) + // Subscribe to axis changes + AxesSvc.Subscribe(ManageAxes, axesData.ToArray()); + } + } + } + + private void ManageAxes(Guid guid, Item[] item, DataSvcStatus[] status) + { + lock (MachineAxesPosition) + { + lock (ProgrammedAxisPosition) + { + lock (InterpAxesPosition) + { + lock (ToGoAxesPosition) + { + MachineAxesPosition.Clear(); + ProgrammedAxisPosition.Clear(); + InterpAxesPosition.Clear(); + ToGoAxesPosition.Clear(); + + for (int i = 0; i < AxesData.Count(); i++) + { + if (status[i * 4].Ok) + MachineAxesPosition.Add(item[i * 4].SymbolicName, Convert.ToDouble(item[i * 4].Value)); + if (status[i * 4 + 1].Ok) + ProgrammedAxisPosition.Add(item[i * 4 + 1].SymbolicName, Convert.ToDouble(item[i * 4 + 1].Value)); + if (status[i * 4 + 2].Ok) + InterpAxesPosition.Add(item[i * 4 + 2].SymbolicName, Convert.ToDouble(item[i * 4 + 2].Value)); + if (status[i * 4 + 3].Ok) + ToGoAxesPosition.Add(item[i * 4 + 3].SymbolicName, Convert.ToDouble(item[i * 4 + 3].Value)); + } + } + } + } + } + } + + // Disconnect Method + public override CmsError NC_Disconnect() + { + // Set Connected to FALSE and close the sessions + Connected = false; + if (SiemensToolSvc != null) + { + SiemensToolSvc.UnSubscribe(ToolMngmtSvcHandler); + // SiemensToolSvc.Dispose(); + } + if (MagazinePositionSvc != null) + { + MagazinePositionSvc.UnSubscribe(MagazinePositionEnabled_OnChange); + //MagazinePositionSvc = null; + // MagazinePositionSvc.Dispose(); + } + if (MagazineActionsSvc != null) + { + MagazineActionsSvc.UnSubscribe(MagazineAction_OnChange); + //MagazineActionsSvc = null; + // MagazineActionsSvc.Dispose(); + } + + if (this.EnableAxes) + { + if (AxesSvc != null) + AxesSvc.UnSubscribe(ManageAxes); + } + + return NO_ERROR; + } + + private void SetupToolTableData() + { + DataSvc dataSvc = new DataSvc(); + // Read max tool number + Item itemToRead = new Item("/NC/_N_NC_TEA_ACX/$MN_MM_NUM_TOOL"); + dataSvc.Read(itemToRead); + MAX_TOOL_NUMER = (int)itemToRead.Value; + + // Read max edge per tool number + itemToRead = new Item("/NC/_N_NC_TEA_ACX/$MN_MM_MAX_CUTTING_EDGE_PERTOOL"); + dataSvc.Read(itemToRead); + MAX_EDGES_PER_TOOL = (int)itemToRead.Value; + + // Read max tools per family + itemToRead = new Item("/NC/_N_NC_TEA_ACX/$MN_MAXNUM_REPLACEMENT_TOOLS"); + dataSvc.Read(itemToRead); + MAX_TOOLS_PER_FAMILY = (int)itemToRead.Value; + + // Read max multitools number + itemToRead = new Item("/NC/_N_NC_TEA_ACX/$MN_MM_NUM_MULTITOOL"); + dataSvc.Read(itemToRead); + MAX_MULTITOOLS_NUMBER = (int)itemToRead.Value; + + // Read max tools per multitools + itemToRead = new Item("/NC/_N_NC_TEA_ACX/$MN_MAX_TOOLS_PER_MULTITOOL"); + dataSvc.Read(itemToRead); + MAX_TOOLS_PER_MULTITOOL = (int)itemToRead.Value; + // Read file + string[] toolsStrings = ReadToolTableFile(); + + // Read max multitools locations + itemToRead = new Item("/NC/_N_NC_TEA_ACX/$MN_MM_NUM_MULTITOOL_LOCATIONS"); + dataSvc.Read(itemToRead); + MAX_MULTITOOLS_LOCATIONS = (int)itemToRead.Value; + + // Read Life option + //itemToRead = new Item("/NC/_N_NC_TEA_ACX/$MN_MM_TOOL_MANAGEMENT_MASK"); + //LIFE_OPTION_ACTIVE = GetBitValue(Convert.ToInt32(itemToRead.Value), 6); + // MULTITOOL_OPTION_ACTIVE = GetBitValue(Convert.ToInt32(itemToRead.Value), 10); + MULTITOOL_OPTION_ACTIVE = false; + + // Read Life option + itemToRead = new Item("/NC/_N_NC_TEA_ACX/$MNS_ACCESS_WRITE_TM_SUPVIS"); + dataSvc.Read(itemToRead); + LIFE_OPTION_ACTIVE = Convert.ToInt32(itemToRead.Value) == 7; + // If not active remove fields from config + if (!LIFE_OPTION_ACTIVE) + RemoveLifeParamsFromConfig(); + + // Read file + PopulateToolsTableFromFileStrings(toolsStrings); + + Array.Clear(toolsStrings, 0, toolsStrings.Count()); + + //// Subscribe to multitools number + //DataSvc d = new DataSvc(); + //Item i = new Item() { Path = "/Tool/MTCatalogue/numMultiTools[u1]" }; + //d.Subscribe(MultitoolsNumber_OnChange, i); + } + + private void SetupMagazinePositionListener() + { + // Setup magazine positions listener + List magPosItems = new List(); + foreach (var position in MagazinePositionsData) + { + int paramId = ((position.PositionId - 1) * 11) + 5; + magPosItems.Add(new Item() + { + Path = string.Format("/Tool/Magazine/placeData[c{0} , {1}]", position.MagazineId, paramId), + SymbolicName = position.MagazineId + "_" + position.PositionId + }); + } + + if (magPosItems.Count > 0) + // Subscribe + MagazinePositionSvc.Subscribe(MagazinePositionEnabled_OnChange, magPosItems.ToArray()); + } + + private void SetupMagazineActionListener() + { + Item magActionsItem = new Item() { Path = MAGAZINE_ACTION_PATH }; + + // Setup magazine actions listener + MagazineActionsSvc.Subscribe(MagazineAction_OnChange, magActionsItem); + } + + private void RemoveLifeParamsFromConfig() + { + SiemensToolFieldsConfig.RemoveAll(x => x.Category == "life"); + SiemensEdgesFieldsConfiguration.EdgeConfiguration.RemoveAll(x => x.Category == "life"); + } + + public override CmsError NC_GetTranslatedPlcMessages(string language, ref Dictionary messages) + { + string filePath; + try + { + messages = new Dictionary(); + + CultureInfo cultureInfo = CultureInfo.CreateSpecificCulture(language); + + // Setup the path of NC alarms translations file + filePath = PLC_MESSAGES_FILE_PATH + "cmsalarm_" + cultureInfo.ThreeLetterISOLanguageName.ToUpper() + ".ts"; + if (!File.Exists(filePath)) + return INCORRECT_LANGUAGE_ERROR; + + // Open file reader + XDocument xmlTranslationsFile; + + using (StreamReader oReader = new StreamReader(filePath, Encoding.ASCII)) + { + xmlTranslationsFile = XDocument.Load(oReader); + } + + // Read file with LINQ + var messagesList = xmlTranslationsFile + .Root + .Descendants("context") + .Elements() + .Where(x => x.Name == "message") + .Select(x => new + { + Key = Convert.ToInt32(x.Element("source").Value.Split('/').FirstOrDefault()), + Value = x.Element("translation").Value + }); + + foreach (var message in messagesList) + { + // If not contain key + if (!messages.Keys.Contains(message.Key)) + messages.Add(message.Key, message.Value); + } + + return NO_ERROR; + } + catch (Exception ex) + { + return ManageException(ex); + } + } + + public override CmsError NC_GetAvailableLanguages(ref ICollection languages) + { + try + { + foreach (string file in Directory.GetFiles(PLC_MESSAGES_FILE_PATH)) + { + if (Path.GetExtension(file) == ".ts") + { + string fileName = Path.GetFileNameWithoutExtension(file); + + var splittedFileName = fileName.Split('_'); + if (splittedFileName.Count() == 2) + { + if (splittedFileName[0].ToLower() == "cmsalarm") + { + // Get lang from threeletter + var lang = GetCultureFromThreeLetter(splittedFileName[1]); + + if (lang != null) + languages.Add(lang); + } + } + } + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + #endregion Contructor & global methods + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #region High level methods + + // Get the processes-count configurated + public override CmsError NC_RProcessesNum(ref ushort ProcNumber) + { + CmsError cmsError = ReadStaticNCData(); + if (cmsError.IsError()) + return cmsError; + + ProcNumber = (ushort)ConfChannelNo; + + return NO_ERROR; + } + + // Get the NC model Name + public override CmsError NC_RModelName(ref string ModelName) + { + CmsError cmsError = ReadStaticNCData(); + if (cmsError.IsError()) + return cmsError; + + ModelName = Cnc_name; + + return NO_ERROR; + } + + // Get the NC Software Version + public override CmsError NC_RSoftwareVersion(ref string SWV) + { + CmsError cmsError = ReadStaticNCData(); + if (cmsError.IsError()) + return cmsError; + + SWV = Cnc_SftVersion; + + return NO_ERROR; + } + + // Get the NC Language + public override CmsError NC_RLanguage(ref CultureInfo Language) + { + CmsError cmsError = ReadStaticNCData(); + if (cmsError.IsError()) + return cmsError; + + Language = ConvertToSTEPLanguage(SiemensLanguage); + + return NO_ERROR; + } + + // Set the NC Language + public override CmsError NC_WLanguage(CultureInfo Language) + { + //CmsError cmsError = CheckConnection(); + //if (cmsError.IsError()) + // return cmsError; + + //// Write write the language + //Infrastructure.CurrentLanguage = ConvertToNCLanguage(Language); + + return NO_ERROR; + } + + // Get the NC Serial number + public override CmsError NC_RSerialNumber(ref string serialNumber) + { + CmsError cmsError = ReadStaticNCData(); + if (cmsError.IsError()) + return cmsError; + + serialNumber = Cnc_SeriesNum; + + return NO_ERROR; + } + + // Get CMS Machine number + public override CmsError NC_RMachineNumber(bool hasLetters, ref string MachNumber) + { + if (!hasLetters) + { + CmsError cmsError = ReadStaticNCData(); + if (cmsError.IsError()) + return cmsError; + + MachNumber = Cms_MachNumber; + } + else + { + // New method to read machine number + List lists = new List(); + CmsError cmsError = MEM_RWByteList(R, 0, NEW_MATR_MACC.MemType, NEW_MATR_MACC.Address, NEW_MATR_MACC.SubAddress, 0, 4, ref lists); + if (cmsError.IsError()) + return cmsError; + + lists.Reverse(); + + MachNumber = Encoding.ASCII.GetString(lists.ToArray()); + } + + return NO_ERROR; + } + + // Get the Date-Time of the NC + public override CmsError NC_RDateTime(ref DateTime ActualTime) + { + // Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + // Try to get information + try + { + // Setup variables + DataSvc Data = LowPriorityDataSvc(); + Item itemRead = new Item(NC_TIME_PATH); + + // Read Data + Data.Read(itemRead); + + // Save Data + ActualTime = (DateTime)itemRead.Value; + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + // Check if the NC is in running state + public override CmsError NC_RIsRunning(ref bool running) + { + ushort nProcess = 0; + // Get the number of processes + CmsError cmsError = NC_RProcessesNum(ref nProcess); + if (cmsError.IsError()) + return cmsError; + + ushort i = 1; + running = false; + do + { + PROC_STATUS procStatus = PROC_STATUS.IDLE; + + // Read process status + cmsError = PROC_RStatus(i, ref procStatus); + if (cmsError.IsError()) + return cmsError; + + if (procStatus == PROC_STATUS.RUN) + running = true; + i++; + } while (!running || i <= nProcess); + + return NO_ERROR; + } + + // Get NC unit of measure + public override CmsError NC_RUnitOfMeasure(ref string unitOfMeasure) + { + CmsError cmsError = ReadStaticNCData(); + if (cmsError.IsError()) + return cmsError; + + unitOfMeasure = UnitOfMeasure; + + return NO_ERROR; + } + + // Get the Nc Active Alarms + public override CmsError NC_RActiveAlarms(ref List alarms) + { + alarms = SiemensAlarms. + Where(x => (x.Id < IDMinPLCMessage || x.Id > IDMaxPLCMessage) && (x.Id < IDMinChannel || x.Id > IDMaxChannel)) + .Select(x => + { + uint id = x.Instance == 1 ? (uint)x.Id : Convert.ToUInt32((x.Id & 0xffff) | (x.Instance << 24)); + return new AlarmModel() + { + Id = id, + Message = x.Message, + IsWarning = false, + Process = 0, + DateTime = x.TimeStamp + }; + }) + .GroupBy(x => x.Id).Select(x => x.First()) + .ToList(); + + return NO_ERROR; + } + + // Set the Nc Active Page of the NC + public override CmsError NC_SetScreenVisible(SCREEN_PAGE screen) + { + //Waiting time + int SleepMs = 50; + int TotalTimes = 2000 / 50; + int ActualTimes = 0; + + string area = ConvertStepToSiemensScreen(screen); + if (string.IsNullOrEmpty(area)) + return INCORRECT_PARAMETERS_ERROR; + + if (Infrastructure.CurrentActiveArea != area) + { + Infrastructure.SwitchToArea(area); + while (Infrastructure.CurrentActiveArea != area) + { + if (ActualTimes == TotalTimes) + return HMI_NOT_RESPONDING_ERROR; + Thread.Sleep(SleepMs); + ActualTimes++; + } + } + + return NO_ERROR; + } + + public override CmsError NC_WMDICommand(int processId, string mdiString) + { + // Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + try + { + FileSvc fileSvc = new FileSvc(); + var a = fileSvc.ReadMdaBuffer(1); + fileSvc.WriteMdaBuffer(processId, mdiString); + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + #endregion High level methods + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #region PLC High-level data + public override CmsError PLC_RWManageWatchdog() + { + bool plcWatchdog = false; + CmsError cmsError = MEM_RWBoolean(R, 0, NC_WATCHDOG.MemType, NC_WATCHDOG.Address, NC_WATCHDOG.SubAddress, 0, ref plcWatchdog); + if (cmsError.IsError()) + return cmsError; + + if (plcWatchdog) + return PLC_NOT_RUNNING_ERROR; + + plcWatchdog = true; + return MEM_RWBoolean(W, 0, NC_WATCHDOG.MemType, NC_WATCHDOG.Address, NC_WATCHDOG.SubAddress, 0, ref plcWatchdog); + } + + public override CmsError PLC_RActiveMessages(ref List alarms) + { + bool[] statusBits; + int i = 0; + List readValues = new List(); + CmsError cmsError; + try + { + alarms.Clear(); + + // Read on data from memory + cmsError = MEM_RWIntegerList(R, 0, + ALARMS_STATUS.MemType, + ALARMS_STATUS.Address, + ALARMS_STATUS.SubAddress, + (ALARMS_STATUS.Size / 4) + (ALARMS_DATA.Size / 2), // statys_bytes / 4 + data_word / 2 + ref readValues); + + if (cmsError.IsError()) + return cmsError; + + alarms.Clear(); + + //List readValues = new List(); + + //// Read on data from memory + //CmsError cmsError = MEM_RWIntegerList(R, 0, + // ALARMS_STATUS.MemType, + // ALARMS_STATUS.Address, + // ALARMS_STATUS.SubAddress, + // (ALARMS_STATUS.Size + ALARMS_DATA.Size) / 4, // byte / 4 + // ref readValues); + + //if (cmsError.IsError()) + // return cmsError; + + // Convert integer array into bit array + statusBits = IntToBits(readValues.ToArray()); + + for (i = 0; i < ALARMS_STATUS.Size * 8; i++) + { + // If alarm is active + if (statusBits[i]) + { + // Calculate matching alarm byte info address + int dataByteAddress = (i * 16) + ALARMS_NUMBER; + + var processList = new List(); + + // Get processes on which alarm is active + for (int j = dataByteAddress; j < dataByteAddress + 6; j++) + { + if (statusBits[j]) + processList.Add(j + 1 - dataByteAddress); + } + // Add alarm info into active alarms list + alarms.Add(new PlcAlarmModel() + { + Id = (uint)i + 1, + IsWarning = statusBits[dataByteAddress + 7], + RestorationIsActive = statusBits[dataByteAddress + 6], + Process = processList + }); + } + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError PLC_WRestoreMessage(uint id) + { + // Check id range + if (id > ALARMS_NUMBER) + return INCORRECT_PARAMETERS_ERROR; + + // Call restore message + CmsError cmsError = PLC_WStrobe(ALARM_ACK, ALARM_RESTORATION_STROBE, id); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + public override CmsError PLC_WRefreshMessage(uint id) + { + // Check id range + if (id > ALARMS_NUMBER) + return INCORRECT_PARAMETERS_ERROR; + + // Call restore message + CmsError cmsError = PLC_WStrobe(ALARM_ACK, ALARM_REFRESH_STROBE, id); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + public override CmsError PLC_WRefreshAllMessages() + { + return PLC_WNcSoftKey(REFRESH_ALL_ALARMS_SFKEY_INDEX); + } + + public override CmsError PLC_RPowerOnData(ref PreAndPostPowerOnModel powerOnModel) + { + int readValue = 0; + // Read pre power on and post power on data from memory + CmsError cmsError = MEM_RWInteger(R, 0, PRE_POST_POWER_ON.MemType, PRE_POST_POWER_ON.Address, PRE_POST_POWER_ON.SubAddress, ref readValue); + if (cmsError.IsError()) + return cmsError; + + bool[] bits = new bool[32]; + + // Convert int into to true/false array + bits = IntToBits(readValue); + // Create adn set pre power on object + PrePowerOnModel prePowerOn = new PrePowerOnModel() + { + PowerOn = new PowerOnDataModel() { Id = 1, Active = bits[0], Clickable = bits[16] }, // id = N, bits = N, Clickable = N + 8 (Second bit) + AirPressure = new PowerOnDataModel() { Id = 2, Active = bits[1], Clickable = bits[17] }, + ProtectionStatus = new PowerOnDataModel() { Id = 3, Active = bits[2], Clickable = bits[18] }, + EmergencyButtons = new PowerOnDataModel() { Id = 4, Active = bits[3], Clickable = bits[19] }, + SettingMode = new PowerOnDataModel() { Id = 5, Active = bits[4], Clickable = bits[20] }, + StartingKey = new PowerOnDataModel() { Id = 6, Active = bits[5], Clickable = bits[21] } + }; + + // Create and set post power on object + PostPowerOnModel postPowerOn = new PostPowerOnModel() + { + AxisReset = new PowerOnDataModel() { Id = 9, Active = bits[8], Clickable = bits[24] }, // id = N - 8, bits = N, Clickable = N + 8 (Second bit) + WaterjetPump = new PowerOnDataModel() { Id = 10, Active = bits[9], Clickable = bits[25] } + }; + + powerOnModel = new PreAndPostPowerOnModel() + { + PostPowerOn = postPowerOn, + PrePowerOn = prePowerOn + }; + + return NO_ERROR; + } + + public override CmsError PLC_WPowerOnData(uint id, bool value) + { + // Check bit range + if (id > 16) + return INCORRECT_PARAMETERS_ERROR; + + // Call restore message + CmsError cmsError = PLC_WStrobe(PRE_POST_POWER_ON_ACK, PRE_POST_POWER_ON_CLICKED, id); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + public override CmsError PLC_RFunctionAccess(ref List functions) + { + List readValues = new List(); + int numberOfIntegers = FUNCTION_ACCESS.Size / 4; + // Read functions access data from memory + CmsError cmsError = MEM_RWIntegerList(R, 0, FUNCTION_ACCESS.MemType, FUNCTION_ACCESS.Address, FUNCTION_ACCESS.SubAddress, numberOfIntegers, ref readValues); + if (cmsError.IsError()) + return cmsError; + + functions = new List(); + // Convert int into to true/false array + bool[] bits = IntToBits(readValues.ToArray()); + // Convert array into structured data + for (int i = 0; i < bits.Count(); i++) + { + functions.Add(new FunctionalityModel() + { + Id = (uint)i + 1, + IsActive = bits[i] + }); + } + + return NO_ERROR; + } + + public override CmsError PLC_RAxesResetData(ref AxisResetDataModel axisResetData) + { + byte value = 0; + // Read byte from memory + CmsError cmsError = MEM_RWByte(R, 0, AXIS_RESET_PROCEDURE.MemType, AXIS_RESET_PROCEDURE.Address, AXIS_RESET_PROCEDURE.SubAddress, 0, ref value); + if (cmsError.IsError()) + return cmsError; + + // Check last bit if is active + if ((value & 128) == 128) + { + // Set to 0 last bit( isActive bit x - 128 ) + // From 0 to 6 bit represents percentage + // If higher than 100 then value = 100 + byte percentage = value - 128 > 100 ? (byte)100 : (byte)(value - 128); + axisResetData = new AxisResetDataModel() + { + IsActive = true, + Percentage = percentage + }; + } + + return NO_ERROR; + } + + public override CmsError PLC_RNcSoftKeys(ref List ncSoftKeys) + { + CmsError cmsError = PLC_RSoftKeys(NC_SOFTKEYS_VALUE, NC_SOFTKEYS_CLICKABLE, ref ncSoftKeys); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + public override CmsError PLC_RUserSoftKeys(ref List softKeys) + { + CmsError cmsError = PLC_RSoftKeys(USER_SOFTKEYS_VALUE, USER_SOFTKEYS_CLICKABLE, ref softKeys); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + private CmsError PLC_RSoftKeys(MEMORY_CELL softKeyStatusMemory, MEMORY_CELL softKeysClickableMemory, ref List softKeys) + { + softKeys = new List(); + List readValues = new List(); + + int memorySizeToRead = (softKeyStatusMemory.Size + softKeysClickableMemory.Size); + // Offset between status and clickable data + int offset = softKeyStatusMemory.Size * 8; + + // Read on data from memory + CmsError cmsError = MEM_RWIntegerList(R, 0, + softKeyStatusMemory.MemType, + softKeyStatusMemory.Address, + softKeyStatusMemory.SubAddress, + memorySizeToRead / 4, + ref readValues); + + if (cmsError.IsError()) + return cmsError; + // Convert ints into an array of bools + bool[] bits = IntToBits(readValues.ToArray()); + + // Convert array into structured data + for (ushort i = 0; i < bits.Count() / 2; i++) + { + softKeys.Add(new SoftKeysModel() + { + Id = (uint)i + 1, + Value = bits[i], + Active = bits[i + offset] + }); + } + + return NO_ERROR; + } + + public override CmsError PLC_WNcSoftKey(uint id) + { + // Check id range + if (id > NC_SOFTKEYS_NUMBER) + return INCORRECT_PARAMETERS_ERROR; + + // Write strobe into memory + CmsError cmsError = PLC_WStrobe(NC_SOFT_KEYS_ACK, NC_SOFT_KEYS_CLICKED, id); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + public override CmsError PLC_WUserSoftKey(uint id) + { + // Check id range + if (id > USER_SOFTKEYS_NUMBER) + return INCORRECT_PARAMETERS_ERROR; + + // Write strobe into memory + CmsError cmsError = PLC_WStrobe(USER_SOFT_KEYS_ACK, USER_SOFT_KEYS_CLICKED, id); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + public override CmsError PLC_RHeadsData(List heads, int number) + { + // Check parameters + if (number > MAX_HEADS_NUMBER) + return INCORRECT_PARAMETERS_ERROR; + heads.Clear(); + + List readInts = new List(); + List readValues = new List(); + List readHours = new List(); + // Find the size of a single head + int headsByte = (HEADS_DATA.Size / MAX_HEADS_NUMBER); + double headsInts = Math.Ceiling((double)(headsByte / 4) + 1); + + // Read data for N heads + CmsError cmsError = MEM_RWIntegerList(R, 0, + HEADS_DATA.MemType, + HEADS_DATA.Address, + HEADS_DATA.SubAddress, + (int)headsInts * number, + ref readInts); + + if (cmsError.IsError()) + return cmsError; + // Convert into list of byte + readValues = readInts.SelectMany(BitConverter.GetBytes).ToList(); + + // Read Worked time heads + cmsError = MEM_RWDWordList(R, 0, HEADS_WORKED_TIMES.MemType, HEADS_WORKED_TIMES.Address, HEADS_WORKED_TIMES.SubAddress, number, ref readHours); + if (cmsError.IsError()) + return cmsError; + + // Parse and format read data + for (int i = 0; i < number; i++) + { + // Head address = posizion * size of single head in memory + var headOffset = i * headsByte; + short toolId = SwapShortEndianFormat(BitConverter.ToInt16(readValues.ToArray(), headOffset + 4)); + + double residualLife = 0; + + // Find tool + var tool = ToolTableData.Where(x => x.Id == toolId).FirstOrDefault(); + + // Check if process is selected + if (readValues[headOffset] != 0) + { + try + { + // Read selected edge + Item activeEdgeId = new Item { Path = "/Channel/State/actDNumber[u" + readValues[headOffset] + ",1]" }; // OffsetId + DataSvc dataSvc = new DataSvc(); + dataSvc.Read(activeEdgeId); + + if (Convert.ToInt32(activeEdgeId.Value) != 0) + { + // Find edge + var edge = tool.EdgesData + .Where(x => x.Id == Convert.ToInt32(activeEdgeId.Value)) + .FirstOrDefault(); + // Set residual life + if (edge != null) + residualLife = edge.ResidualLife; + } + } + catch (Exception ex) + { + return ManageException(ex); + } + } + + heads.Add(new HeadDataModel() + { + Id = (uint)i + 1, + Process = readValues[headOffset], + Override = readValues[headOffset + 1], + Load_Abrasive = SwapShortEndianFormat(BitConverter.ToInt16(readValues.ToArray(), headOffset + 2)), // Uint 16 = 2byte + MountedTool_Vacum = toolId, // Uint 16 = 2byte + ActualSpeed_Pressure = SwapIntEndianFormat(BitConverter.ToInt32(readValues.ToArray(), headOffset + 6)), // Int32 = 4byte + IsActive = (readValues[headOffset + 10] & 1) != 0, // bit 0 + IsSelected = (readValues[headOffset + 10] & 2) != 0, // bit 1 + OverrideEditable = (readValues[headOffset + 10] & 4) != 0, // bit 2 + Configured = (readValues[headOffset + 10] & 8) != 0, + Rotation = (readValues[headOffset + 10] & 16) == 0 ? ROTATION.CLOCKWHISE : ROTATION.COUNTERCLOCKWHISE, + WorkedTime = readHours[i], + Tool = new ToolInSpindleModel() + { + ChildId = tool == null ? 0 : tool.ChildId, + ToolName = tool == null ? "" : tool.FamilyName, + Disabled = tool == null ? false : !tool.IsActive, + Measured = tool == null ? false : tool.IsMeasured, + Broken = tool == null ? false : tool.IsInhibited, + MaxLoad = tool == null ? 0 : tool.Load, + MaxSpeed = tool == null ? 0 : tool.MaxSpeed, + ResidualLife = residualLife + } + }); + } + + return NO_ERROR; + } + + public override CmsError PLC_RWorkedTimeHead(int head, ref uint time) + { + int index = (head - 1) * 4; + + // Read Worked time + CmsError cmsError = MEM_RWDWord(R, 0, HEADS_WORKED_TIMES.MemType, HEADS_WORKED_TIMES.Address, HEADS_WORKED_TIMES.SubAddress + index, ref time); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + public override CmsError PLC_WResetWorkedTimeHead(int head) + { + byte usControlWord = 0; + + if (head <= 0 || head > MAX_HEADS_NUMBER) + return INCORRECT_PARAMETERS_ERROR; + + // Read status + CmsError cmsError = MEM_RWByte(R, 0, HEAD_RESET_WORKED_TIME.MemType, HEAD_RESET_WORKED_TIME.Address, HEAD_RESET_WORKED_TIME.SubAddress, 0, ref usControlWord); + if (cmsError.IsError()) + return cmsError; + + // Re-Write it status + usControlWord = Convert.ToByte((usControlWord & 0xE0) | (head & 0X1F)); + cmsError = MEM_RWByte(W, 0, HEAD_RESET_WORKED_TIME.MemType, HEAD_RESET_WORKED_TIME.Address, HEAD_RESET_WORKED_TIME.SubAddress, 0, ref usControlWord); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + public override CmsError PLC_RWorkedTimeMachine(ref uint time) + { + // Read Worked time + CmsError cmsError = MEM_RWDWord(R, 0, MACHINE_WORKED_TIME.MemType, MACHINE_WORKED_TIME.Address, MACHINE_WORKED_TIME.SubAddress, ref time); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + public override CmsError PLC_WResetWorkedTimeMachine(uint time) + { + uint actTime = 0; + + // Read actual Value + CmsError cmsError = MEM_RWDWord(R, 0, MACHINE_WORKED_TIME.MemType, MACHINE_WORKED_TIME.Address, MACHINE_WORKED_TIME.SubAddress, ref actTime); + if (cmsError.IsError()) + return cmsError; + + // Per richiedere l'azzeramento del timer invio 4 volte il segnale velocemente al PLC + // Il PLC resetta il bit e aspetta quello successivo entro 500ms, se no abortisce + // Sfrutto così la velocità dei sw, cosa che un "nemico" a mano se provasse a forzare il bit non avrebbe + bool bitValue = true; + int nTry = 0; + + for (int i = 0; i <= 4; i++) + { + //Scrivo il bit + bitValue = true; + nTry = 0; + cmsError = MEM_RWBoolean(W, 0, MACHINE_RESET_WORKED_TIME.MemType, MACHINE_RESET_WORKED_TIME.Address, MACHINE_RESET_WORKED_TIME.SubAddress, 0, ref bitValue); + if (cmsError.IsError()) + return cmsError; + + //Aspetto che venga abbassato + do + { + Thread.Sleep(50); + nTry += 1; + cmsError = MEM_RWBoolean(R, 0, MACHINE_RESET_WORKED_TIME.MemType, MACHINE_RESET_WORKED_TIME.Address, MACHINE_RESET_WORKED_TIME.SubAddress, 0, ref bitValue); + if (cmsError.IsError()) + return cmsError; + + } while (bitValue && nTry <= 10); + + //se il valore è rimasto a 1 il plc non l'ha preso in carico, e abortisco + if (bitValue) + { + bitValue = true; + cmsError = MEM_RWBoolean(W, 0, MACHINE_RESET_WORKED_TIME.MemType, MACHINE_RESET_WORKED_TIME.Address, MACHINE_RESET_WORKED_TIME.SubAddress, 0, ref bitValue); + if (cmsError.IsError()) + return cmsError; + + return PLC_NOT_RUNNING_ERROR; + } + else + { + //Se l'ha abbassato scrivo il nuovo dato + cmsError = MEM_RWDWord(W, 0, MACHINE_WORKED_TIME.MemType, MACHINE_WORKED_TIME.Address, MACHINE_WORKED_TIME.SubAddress, ref time); + } + + } + + return NO_ERROR; + } + + public override CmsError PLC_WHeadOverride(uint id, HEAD_OVERRIDE_SIGN sign) + { + if (id > MAX_HEADS_NUMBER) + return INCORRECT_PARAMETERS_ERROR; + + MEMORY_CELL currentStrobeCell = sign == HEAD_OVERRIDE_SIGN.PLUS ? HEADS_STROBE_INCREMENT : HEADS_STROBE_DECREMENT; + + // Write strobe into memory + CmsError cmsError = PLC_WStrobe(HEADS_ACK, currentStrobeCell, id); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + // MACHINE COUNTERS + public override CmsError PLC_RMachineCounters(ref List counters) + { + List val = new List(); + // Read ints + CmsError cmsError = MEM_RWDWordList(R, 0, COUNTERS_DATA.MemType, COUNTERS_DATA.Address, COUNTERS_DATA.SubAddress, COUNTERS_DATA.Size / 4, ref val); + if (cmsError.IsError()) + return cmsError; + + // Set return value + uint i = 0; + counters = val.Select(x => new CounterModel() + { + Id = i++, + Value = x + }) + .ToList(); + + return NO_ERROR; + } + + public override CmsError PLC_WResetMachineCounters(uint counter) + { + bool isResettable = false; + CmsError cmsError = MEM_RWBoolean(R, 0, COUNTER_IS_RESETTABLE.MemType, COUNTER_IS_RESETTABLE.Address, COUNTER_IS_RESETTABLE.SubAddress, (int)(counter - 1), ref isResettable); + if (cmsError.IsError()) + return cmsError; + + if (!isResettable) + return FUNCTION_NOT_ALLOWED_ERROR; + + cmsError = PLC_WStrobe(COUNTER_IS_RESETTABLE_ACK, COUNTER_IS_RESETTABLE_STROBE, counter); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + public override CmsError PLC_ROperatorInputIsNeeded(ref List value) + { + byte val = 0; + // Read memory + CmsError cmsError = MEM_RWByte(R, 0, M155_INPUT_NEEDED.MemType, M155_INPUT_NEEDED.Address, M155_INPUT_NEEDED.SubAddress, 0, ref val); + if (cmsError.IsError()) + return cmsError; + // Convert byte to an array of bits + bool[] bits = ByteToBits(val); + uint processId = 1; + + string[] parameters; + string actualLine = ""; + + foreach (bool bit in bits) + { + if (bit) + { + // Read active program line + cmsError = PROC_ReadActiveLine(processId, ref actualLine); + if (cmsError.IsError()) + return cmsError; + + // Parse line & get parameters + parameters = ExtractM155ParametersFromNcCodeLine(actualLine); + if (parameters.Count() == 0) + { + value.Add(new M155InputIsNeededModel() + { + Process = processId, + IsNeeded = bits[processId - 1], + Message = "", + Type = M155_TYPE.REAL, + Buttons = new Dictionary() + }); + + return NO_ERROR; + } + + byte i = 1; + if (parameters[0].ToUpper().Trim() == "SHOWVAL") + { + try + { + // Skip first parameter because it's the message string + // Set button with -> id = 1..5 -> value = parameter value + Dictionary buttons = parameters.Skip(2)?.ToDictionary(x => i++, x => x); + + // Read machine variable + DataSvc dataSvc = new DataSvc(); + Item item = new Item() + { + Path = string.Format("/channel/parameter/r[c{0} , 155]", processId), + }; + + dataSvc.Read(item); + + value.Add(new M155InputIsNeededModel() + { + Process = processId, + IsNeeded = bits[processId - 1], + Message = parameters[1] ?? "", + Type = M155_TYPE.SHOW_VAL, // if there aren't buttons is a simple request, + Value = Convert.ToDouble(item.Value), + Buttons = buttons + }); + } + catch (Exception ex) + { + return ManageException(ex); + } + } + else + { + // Skip first parameter because it's the message string + // Set button with -> id = 1..5 -> value = parameter value + Dictionary buttons = parameters.Skip(1)?.ToDictionary(x => i++, x => x); + + value.Add(new M155InputIsNeededModel() + { + Process = processId, + IsNeeded = bit, + Message = parameters[0] ?? "", + Type = parameters.Count() > 1 ? M155_TYPE.MULTIPLE_BUTTONS : M155_TYPE.REAL, // if there aren't buttons is a simple request + Buttons = buttons + }); + } + } + + // Next path + processId++; + } + + return NO_ERROR; + } + + public override CmsError PLC_WOperatorInputResponse(int process, double responseVal) + { + try + { + DataSvc dataSvc = new DataSvc(); + Item item = new Item() + { + Path = string.Format("/channel/parameter/r[c{0} , 155]", process), + Value = responseVal + }; + + dataSvc.Write(item); + + return PLC_WStrobe(M155_INPUT_ACK, M155_INPUT_STROBE, (uint)process); + } + catch (Exception ex) + { + return ManageException(ex); + } + } + + public override CmsError PLC_RM154Data(ref List data, ref bool MTCOnOff) + { + MTCOnOff = false; + CmsError cmsError = MEM_RWBoolean(R, 0, M154_SWITCH_ONOFF.MemType, M154_SWITCH_ONOFF.Address, M154_SWITCH_ONOFF.SubAddress, 1, ref MTCOnOff); + + if (cmsError.IsError()) + return cmsError; + + byte val = 0; + cmsError = MEM_RWByte(R, 0, M154_STROBE.MemType, M154_STROBE.Address, M154_STROBE.SubAddress, 0, ref val); + if (cmsError.IsError()) + return cmsError; + + // Convert a byte to an array of booleans + bool[] bits = ByteToBits(val); + string[] parameters; + string tmpStr = ""; + + for (uint processId = 1; processId <= MAX_PROCESS_NUMBER; processId++) + { + if (bits[processId - 1]) + { + // Read active program line + cmsError = PROC_ReadActiveLine(processId, ref tmpStr); + if (cmsError.IsError()) + return cmsError; + + // Parse parameters + parameters = ExtractM154ParametersFromNcCodeLine(tmpStr); + data.Add(new M154DataModel() + { + Process = processId, + IsNeeded = bits[processId - 1], + Parameters = parameters + }); + } + } + + return NO_ERROR; + } + + public override CmsError PLC_W154ManageAck(int processId) + { + return PLC_ManageActiveAck(M154_STROBE.Address, M154_STROBE.SubAddress, processId - 1, M154_ACK.Address, M154_ACK.SubAddress, processId - 1, M154_STROBE.MemType); + } + + + public override CmsError PLC_RM156Data(ref List value) + { + byte val = 0; + List vals = new List(); + CmsError cmsError = MEM_RWByte(R, 0, M156_INPUT_NEEDED.MemType, M156_INPUT_NEEDED.Address, M156_INPUT_NEEDED.SubAddress, 0, ref val); + if (cmsError.IsError()) + return cmsError; + + cmsError = MEM_RWByteList(R, 0, M156_INPUT_ID_LIST.MemType, M156_INPUT_ID_LIST.Address, 0, M156_INPUT_ID_LIST.Size, ref vals); + if (cmsError.IsError()) + return cmsError; + + bool[] bits = ByteToBits(val); + + for (int processId = 1; processId <= MAX_PROCESS_NUMBER; processId++) + { + if (bits[processId - 1]) + { + Item item = new Item() + { + Path = string.Format("/channel/parameter/r[c{0} , 154]", processId), + }; + try + { + DataSvc dataSvc = new DataSvc(); + dataSvc.Read(item); + } + catch (Exception ex) + { + return ManageException(ex); + } + + // Parse line & get parameters + value.Add(new M156InputIsNeededModel() + { + Process = (uint)processId, + Id = vals.ElementAt(processId - 1), + Value = Convert.ToDouble(item.Value) + }); + } + } + + return NO_ERROR; + } + + public override CmsError PLC_WM156Response(int process, double responseVal) + { + //CmsError cmsError = MEM_RWDouble(W, 0, MEMORY_TYPE.Osai_GD, 900 + (process - 1), ref responseVal); + //if (cmsError.IsError()) + // return cmsError; + + return PLC_WStrobe(M156_INPUT_ACK, M156_INPUT_STROBE, (uint)process); + } + + public override CmsError PLC_RScadaValue(string memIndex, SCADA_MEM_TYPE memType, ref object value) + { + if (memType == SCADA_MEM_TYPE.BOOL) + { + if (memIndex.ToUpper() == "FALSE") + { + value = false; + return NO_ERROR; + } + else if (memIndex.ToUpper() == "TRUE") + { + value = true; + return NO_ERROR; + } + } + + string[] index = memIndex.Split('.'); + CmsError cmsError = NO_ERROR; + try + { + if (index.Count() == 0 || index.Count() == 1) + return INCORRECT_PARAMETERS_ERROR; + else if (index.Count() == 2) + { + if (memType == SCADA_MEM_TYPE.INT) + { + // read INT + int val = 0; + cmsError = MEM_RWInteger(R, 0, MEMORY_TYPE.Siemens_DB, Convert.ToInt32(index[0]), Convert.ToInt32(index[1]), ref val); + + value = val; + } + else if (memType == SCADA_MEM_TYPE.WORD) + { // read WORD + short val = 0; + cmsError = MEM_RWShort(R, 0, MEMORY_TYPE.Siemens_DB, Convert.ToInt32(index[0]), Convert.ToInt32(index[1]), ref val); + + value = val; + } + else if (memType == SCADA_MEM_TYPE.REAL) + { // read DOUBLE + double val = 0; + cmsError = MEM_RWDouble(R, 0, MEMORY_TYPE.Siemens_DB, Convert.ToInt32(index[0]), Convert.ToInt32(index[1]), ref val); + + value = val; + } + else + { // read BYTE + byte val = 0; + cmsError = MEM_RWByte(R, 0, MEMORY_TYPE.Siemens_DB, Convert.ToInt32(index[0]), Convert.ToInt32(index[1]), 0, ref val); + + value = val; + } + } + else if (index.Count() == 3 && memType == SCADA_MEM_TYPE.BOOL) + { // read BOOL + bool val = false; + cmsError = MEM_RWBoolean(R, 0, MEMORY_TYPE.Siemens_DB, Convert.ToInt32(index[0]), Convert.ToInt32(index[1]), Convert.ToInt32(index[2]), ref val); + + value = val; + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return cmsError; + } + + public override CmsError PLC_RScadaSiemens(ref List objects) + { + try + { + List items = new List(); + + string bit, + address; + char charType = 'B'; + + // Cycle through object + for (int i = 0; i < objects.Count(); i++) + { + // Split memory string -> X.Y.Z + string[] splittedMem = objects[i].Address.Split('.'); + bit = "0"; + address = "0"; + + bool read = true; + + switch (objects[i].MemType) + { + case SCADA_MEM_TYPE.BOOL: + { + // Check if memory contains default value + if (splittedMem[0].ToUpper() == "FALSE") + { + objects[i].Value = false; + read = false; + break; + } + else if (splittedMem[0].ToUpper() == "TRUE") + { + objects[i].Value = true; + read = false; + break; + } + + bit = splittedMem[2]; + address = splittedMem[1]; + charType = 'X'; // Siemens memory type character + } + break; + case SCADA_MEM_TYPE.BYTE: + { + address = splittedMem[1]; + charType = 'B'; + } + break; + case SCADA_MEM_TYPE.INT: + { + address = splittedMem[1]; + charType = 'D'; + } + break; + case SCADA_MEM_TYPE.WORD: + { + address = splittedMem[1]; + charType = 'W'; + } + break; + case SCADA_MEM_TYPE.REAL: + { + address = splittedMem[1]; + charType = 'D'; + } + break; + } + + // If needs to read + if (read) + { + // Convert splitted address into Siemens address + ConvertMemToPath(MEMORY_TYPE.Siemens_DB, + Convert.ToInt32(splittedMem[0]), + Convert.ToInt32(address), + Convert.ToInt32(bit), + 1, + charType, + out string item); + + // Add to the list of items to be readed + items.Add(new Item() + { + Path = item + }); + } + } + + if (items.Count() > 0) + { + // Read data + DataSvc dataSvc = new DataSvc(); + dataSvc.Read(items.ToArray()); + + int alreadyReaded = 0; + for (int i = 0; i < objects.Count(); i++) + { + // Skip the objects already valorised + if (objects[i].Value == null) + { + switch (objects[i].MemType) + { + case SCADA_MEM_TYPE.BOOL: + { + // Valorize data + objects[i].Value = Convert.ToBoolean(items[i - alreadyReaded].Value); + } + break; + case SCADA_MEM_TYPE.BYTE: + { + objects[i].Value = Convert.ToByte(items[i - alreadyReaded].Value); + } + break; + case SCADA_MEM_TYPE.INT: + { + objects[i].Value = Convert.ToInt32(items[i - alreadyReaded].Value); + } + break; + case SCADA_MEM_TYPE.WORD: + { + objects[i].Value = Convert.ToInt16(items[i - alreadyReaded].Value); + } + break; + case SCADA_MEM_TYPE.REAL: + { + // Convert value to double + var byteVal = BitConverter.GetBytes((uint)items[i - alreadyReaded].Value); + var value = unchecked(Convert.ToDouble(BitConverter.ToSingle(byteVal, 0))); + + objects[i].Value = Math.Round(value, objects[i].Round); + } + break; + } + } + else + { + // Count items already readed + alreadyReaded++; + } + } + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError PLC_WScadaValue(string memIndex, SCADA_MEM_TYPE memType, object value) + { + string[] index = memIndex.Split('.'); + CmsError cmsError = NO_ERROR; + if (index.Count() == 0) + return INCORRECT_PARAMETERS_ERROR; + + else if (index.Count() == 2) + { + if (memType == SCADA_MEM_TYPE.INT) + { + // write INT + int val = Convert.ToInt32(value); + cmsError = MEM_RWInteger(W, 0, MEMORY_TYPE.Siemens_DB, Convert.ToInt32(index[0]), Convert.ToInt32(index[1]), ref val); + } + else if (memType == SCADA_MEM_TYPE.WORD) + { // write WORD + short val = Convert.ToInt16(value); + cmsError = MEM_RWShort(W, 0, MEMORY_TYPE.Siemens_DB, Convert.ToInt32(index[0]), Convert.ToInt32(index[1]), ref val); + } + else if (memType == SCADA_MEM_TYPE.REAL) + { // write DOUBLE + double val = Convert.ToDouble(value); + cmsError = MEM_RWDouble(W, 0, MEMORY_TYPE.Siemens_DB, Convert.ToInt32(index[0]), Convert.ToInt32(index[1]), ref val); + } + else + { // write byte + byte val = Convert.ToByte(value); + cmsError = MEM_RWByte(W, 0, MEMORY_TYPE.Siemens_DB, Convert.ToInt32(index[0]), Convert.ToInt32(index[1]), 0, ref val); + } + } + else if (index.Count() == 3 && memType == SCADA_MEM_TYPE.BOOL) + { // write BOOL + bool val = Convert.ToBoolean(value); + cmsError = MEM_RWBoolean(W, 0, MEMORY_TYPE.Siemens_DB, Convert.ToInt32(index[0]), Convert.ToInt32(index[1]), Convert.ToInt32(index[2]), ref val); + } + + return cmsError; + } + + public override CmsError PLC_WAssistedToolingCmd(ushort toolId, ushort familyId, ushort shankId, ushort magazineId, ushort positionId, ASSISTED_TOOLING_ACTION action) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError PLC_RAssistedToolingData(ref AssistedToolingModel data) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError PLC_WTerminateAssistedToolingProcedure() + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + private CmsError PLC_WStrobe(MEMORY_CELL ackCell, MEMORY_CELL strobeCell, uint id) + { + CmsError cmsError; + bool readValue = false; + bool writeValue = true; + + SetupAckStrobeAddresses(ackCell.SubAddress, strobeCell.SubAddress, id, out int ackByte, out int strobeByte, out int alarmBitId); + + // Check Strobe + cmsError = MEM_RWBoolean(R, 0, strobeCell.MemType, strobeCell.Address, strobeByte, alarmBitId, ref readValue); + if (cmsError.IsError()) + return cmsError; + + // If PLC it's performing another request then return + if (readValue) + return NO_ERROR; + + // Check ACK + cmsError = MEM_RWBoolean(R, 0, ackCell.MemType, ackCell.Address, ackByte, alarmBitId, ref readValue); + if (cmsError.IsError()) + return cmsError; + + // If PLC it's performing another request then return + if (readValue) + return NO_ERROR; + + // Write strobe into memory + cmsError = MEM_RWBoolean(W, 0, strobeCell.MemType, strobeCell.Address, strobeByte, alarmBitId, ref writeValue); + if (cmsError.IsError()) + return cmsError; + + // Reset wait ack = 1 and reset the strobe + cmsError = ResetStrobe(alarmBitId, strobeByte, ackByte, ackCell.MemType); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + private void SetupAckStrobeAddresses(int ackAddress, int strobeAddress, uint id, out int ackByte, out int strobeByte, out int bit) + { + ackByte = ackAddress + (((int)id - 1) / 8); + strobeByte = strobeAddress + (((int)id - 1) / 8); + bit = (((int)id - 1) % 8); + } + + private CmsError ResetStrobe(int bitId, int strobeByte, int ackByte, MEMORY_TYPE memType) + { + int n = 600; + bool readValue = false; + bool writeValue = false; + bool ok = false; + + CmsError cmsError; + do + { + // Check ACK + cmsError = MEM_RWBoolean(R, 0, memType, TABLE, ackByte, bitId, ref readValue); + if (cmsError.IsError()) + return cmsError; + + // If true reset strobe + if (readValue == true) + { + // Reset strobe + cmsError = MEM_RWBoolean(W, 0, memType, TABLE, strobeByte, bitId, ref writeValue); + if (cmsError.IsError()) + return cmsError; + // Exit from cycle + n = 0; + ok = true; + } + else + { + // Decrement + n--; + // Wait befor next cycle + Thread.Sleep(20); + } + } while (n > 0); + + if (!ok) + { + // Reset strobe + cmsError = MEM_RWBoolean(W, 0, memType, TABLE, strobeByte, bitId, ref writeValue); + if (cmsError.IsError()) + return cmsError; + } + + return cmsError; + } + + private CmsError PLC_ManageActiveAck(int strobeByte, int strobeSubByte, int strobeBit, int ackByte, int ackSubByte, int ackBit, MEMORY_TYPE memType) + { + int n = 1200; // 30 seconds + bool readValue = false; + bool writeValue = true; + bool ok = false; + // Set ack to 1 + CmsError cmsError = MEM_RWBoolean(W, 0, memType, ackByte, ackSubByte, ackBit, ref writeValue); + if (cmsError.IsError()) + return cmsError; + + do + { + // Check strobe + cmsError = MEM_RWBoolean(R, 0, memType, strobeByte, strobeSubByte, strobeBit, ref readValue); + if (cmsError.IsError()) + return cmsError; + + // If true reset acknowledge + if (!readValue) + { + writeValue = false; + // Reset acknowledge + cmsError = MEM_RWBoolean(W, 0, memType, ackByte, ackSubByte, ackBit, ref writeValue); + if (cmsError.IsError()) + return cmsError; + // Exit from cycle + n = 0; + ok = true; + } + else + { + // Decrement + n--; + // Wait befor next cycle + Thread.Sleep(25); + } + } while (n > 0); + + // If loop timeout goes in timeout + if (!ok) + { + // Reset acknowledge + writeValue = false; + cmsError = MEM_RWBoolean(W, 0, memType, ackByte, ackSubByte, ackBit, ref writeValue); + if (cmsError.IsError()) + return cmsError; + } + + return cmsError; + } + + public override CmsError PLC_WExpiredCandy(bool value) + { + bool newVal = false; + + //Scrivo il dato + CmsError cmsError = MEM_RWBoolean(W, 0, EXP_CANDY_MEM.MemType, EXP_CANDY_MEM.Address, EXP_CANDY_MEM.SubAddress, 5, ref value); + if (cmsError.IsError()) + return cmsError; + else + { + //Leggo il dato + cmsError = PLC_RExpiredCandy(ref newVal); + if (cmsError.IsError()) + return cmsError; + + //Se i 2 dati coincidono ritorno OK + if (value == newVal) + return NO_ERROR; + else + return PLC_NOT_RUNNING_ERROR; + + } + } + + public override CmsError PLC_RExpiredCandy(ref bool value) + { + CmsError cmsError = MEM_RWBoolean(R, 0, EXP_CANDY_MEM.MemType, EXP_CANDY_MEM.Address, EXP_CANDY_MEM.SubAddress, 5, ref value); + if (cmsError.IsError()) + return cmsError; + return NO_ERROR; + } + + public override CmsError PLC_WCandy(long value) + { + // Long is formed by a integer + word + // Write Word + ushort word = (ushort)((value & 0xFFFF)); + CmsError cmsError = MEM_RWWord(W, 0, CANDY_MEM.MemType, CANDY_MEM.Address, CANDY_MEM.SubAddress, ref word); + if (cmsError.IsError()) + return cmsError; + + int integer = (int)((value & 0xFFFFFFFF0000) >> 16); + // Write Integer (+1 is used because osai uses word) + cmsError = MEM_RWInteger(W, 0, CANDY_MEM.MemType, CANDY_MEM.Address, CANDY_MEM.SubAddress + 2, ref integer); + if (cmsError.IsError()) + return cmsError; + + // Rieggo il dato + long newVal = 0; + cmsError = PLC_RCandy(ref newVal); + if (cmsError.IsError()) + return cmsError; + + // Se i 2 dati coincidono ritorno OK + if (value == newVal) + return NO_ERROR; + else + return PLC_NOT_RUNNING_ERROR; + } + + public override CmsError PLC_RCandy(ref long value) + { + // Long is formed by a integer + word + // Read word + ushort word = 0; + CmsError cmsError = MEM_RWWord(R, 0, CANDY_MEM.MemType, CANDY_MEM.Address, CANDY_MEM.SubAddress, ref word); + if (cmsError.IsError()) + return cmsError; + + // Read first int + uint firtInt = 0; + cmsError = MEM_RWDWord(R, 0, CANDY_MEM.MemType, CANDY_MEM.Address, CANDY_MEM.SubAddress + 2, ref firtInt); + if (cmsError.IsError()) + return cmsError; + + + + // Build Long value + value = ((long)firtInt << 16) + word; + + return NO_ERROR; + } + + public override CmsError PLC_RActiveClient(ref int clientId) + { + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + byte readValues = 0; + cmsError = MEM_RWByte(R, 0, ACTIVE_CLIENT.MemType, ACTIVE_CLIENT.Address, ACTIVE_CLIENT.SubAddress, 0, ref readValues); + if (cmsError.IsError()) + return cmsError; + + // Convert integer array into bit array + bool[] statusBits = ByteToBits(readValues); + // check which bit is set + for (int i = 0; i < 8; i++) + { + if (statusBits[i]) + clientId = i + 1; + } + + return NO_ERROR; + } + + public override CmsError PLC_RToolMovement(ref MovementBetweenMagazinesModel toolMovement) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError PLC_WTerminateMovementProcedure(MOVEMENT_RESPONSE resp) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + #endregion PLC High-level data + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #region PROCESS (PATH) High-level data + + // Get the process Mode + public override CmsError PROC_RMode(ushort ProcNumber, ref PROC_MODE Mode) + { + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + // Try to get information + try + { + // Setup variables + DataSvc Data = HighPriorityDataSvc(); + Item itemRead = new Item(NC_GENERIC_MODE_PATH + "[u" + ProcNumber + "]"); + Item itemReadIncr = new Item(JOG_INCR_PATH + "[u" + ProcNumber + "]"); + Item itemReadAdv = new Item(ADVANCED_JOG_PATH + "[u" + ProcNumber + "]"); + + // Read Data + Data.Read(itemRead); + Data.Read(itemReadIncr); + Data.Read(itemReadAdv); + + // Save Data + Mode = ConvertToSTEPMode((uint)itemRead.Value, (uint)itemReadIncr.Value, (uint)itemReadAdv.Value); + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + // Get the process status + public override CmsError PROC_RStatus(ushort ProcNumber, ref PROC_STATUS Status) + { + // Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + // Try to get information + try + { + // Setup variables + DataSvc Data = HighPriorityDataSvc(); + Item itemRead = new Item(NC_GENERIC_STATE_PATH + "[u" + ProcNumber + "]"); + + // Read Data + Data.Read(itemRead); + + // Save Data + Status = ConvertToSTEPStatus((uint)itemRead.Value); + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + // Get PP Lines + public override CmsError PROC_RPPLines(ushort ProcNumber, ref List Lines) + { + // Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + string[] newLines; + // Try to get information + try + { + // Setup variables + DataSvc Data = HighPriorityDataSvc(); + Item itemRead = new Item(ACT_PROG_LINES_PATH + "[u" + ProcNumber + "]"); + + // Read Data + Data.Read(itemRead); + + // Save Data + newLines = ((string)itemRead.Value).Replace("\r", string.Empty).Split('\n'); + + // Setup the return values + Lines.Clear(); + foreach (string Line in newLines) + Lines.Add(Line); + + // Remove the first Line (the previous line) + if (Lines.Count > 0) + Lines.RemoveAt(0); + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + // Get PP Name + public override CmsError PROC_RSelectedPPName(ushort ProcNumber, ref string Name) + { + // Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + string RetString; + int LastUnderscore; + + // Try to get information + try + { + // Setup variables + DataSvc Data = HighPriorityDataSvc(); + Item itemRead = new Item(ACT_PROG_NAME_PATH + "[u" + ProcNumber + "]"); + + // Read Data + Data.Read(itemRead); + + // Elaborate String + RetString = ((string)itemRead.Value); + RetString = RetString.Replace("_N_", ""); + LastUnderscore = RetString.LastIndexOf("_"); + if (LastUnderscore >= 0) + RetString = RetString.Remove(LastUnderscore, 1).Insert(LastUnderscore, "."); + + // Save Data + Name = RetString; + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + // Get the process Active Alarms + public override CmsError PROC_RActiveAlarms(ushort procNumber, ref List alarms) + { + alarms = SiemensAlarms + .Where(x => x.Id >= IDMinChannel && x.Id <= IDMaxChannel && x.Parameters[0].Equals(procNumber.ToString())) + .Select(x => + { + uint id = x.Instance == 1 ? (uint)x.Id : Convert.ToUInt32((x.Id & 0xffff) | (x.Instance << 24)); + return new AlarmModel() + { + Id = id, + Message = x.Message, + IsWarning = false, + Process = procNumber, + DateTime = x.TimeStamp + }; + }) + .ToList(); + + return NO_ERROR; + } + + // Get process part program data + public override CmsError PROC_RStatusAndData(ushort procNumber, ref ProcessDataModel processData) + { + processData.Id = procNumber; + // Read part program name + CmsError cmsError = PROC_RSelectedPPName(procNumber, ref processData.PartProgramName); + if (cmsError.IsError()) + return cmsError; + + int readValue = 0; + // Read processes status from memory + cmsError = MEM_RWInteger(R, 0, PROCESS_STATUS.MemType, PROCESS_STATUS.Address, PROCESS_STATUS.SubAddress + ((procNumber - 1) * 2), ref readValue); + if (cmsError.IsError()) + return cmsError; + + byte[] bytes = BitConverter.GetBytes(readValue); + + // Convert Byte into true/false array + BitArray bits = new BitArray(new byte[] { bytes[0] }); // 1st byte -> 0 : Proccess type (AUX-WORK), 1: Process in alarm status, 2: Run, 3: Hold, 4: Read, 5: PartProgramVisible + + // Get part program info visibility + processData.Visible = bits[0]; + + // Populate response structure + processData.Type = bits[1] ? "WORK" : "AUX"; + processData.IsSelected = bits[2]; + processData.IsInAlarm = bits[3]; + processData.CanLoadProgram = bits[4]; + + // Choose process status + if (bytes[1] == 1) + processData.Status = "HOLD"; + else + { + if (bytes[1] == 2) + processData.Status = "RUN"; + else + processData.Status = "READY"; + } + + // Get Reps from 3nd-4th byte + processData.Reps = BitConverter.ToUInt16(bytes, 2); + + return NO_ERROR; + } + + public override CmsError PROC_RSelectedProcess(ref ushort procNumber) + { + if (SelectedProcess == 0) + return SELECTED_PROCESS_ERROR; + + procNumber = SelectedProcess; + //CmsError cmsError; + //bool readValue = false; + + //for (int i = 0; i < PROCESS_NUMBER; i++) + //{ + // // Calculate bit address = ProcessBase + processId * 2 + // int memoryAddress = SELECTED_PROCESS.SubAddress + i * (2); + // // Read memory from plc + // cmsError = MEM_RWBoolean(R, 0, SELECTED_PROCESS.MemType, SELECTED_PROCESS.Address, memoryAddress, 2, ref readValue); + // if (cmsError.IsError()) + // return cmsError; + + // if (readValue) + // { + // procNumber = (ushort)(i + 1); + // return NO_ERROR; + // } + //} + + return NO_ERROR; + } + + public override CmsError PROC_WSelectProcess(ushort procNumber) + { + CmsError cmsError; + byte processNum = (byte)procNumber; + + // Check parameter + if (processNum > MAX_PROCESS_NUMBER) + return INCORRECT_PARAMETERS_ERROR; + + // Write process number + cmsError = MEM_RWByte(W, 0, SELECT_PROCESS.MemType, SELECT_PROCESS.Address, SELECT_PROCESS.SubAddress, ref processNum); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + public override CmsError PROC_RSelectedProcessData(int processId, ref SelectedProcessData processData) + { + if (processId <= 0) + return PROC_NOT_FOUND_ERROR; + + try + { + Item[] items = new Item[7] + { + new Item { Path = "/Channel/State/actTNumber[u" + processId + ",1]" }, // ActiveToolId + new Item { Path = "/Channel/State/actDNumber[u" + processId + ",1]" }, // OffsetId + new Item { Path = "/Channel/State/actFrameIndex[u" + processId + "]" }, // Origin + new Item { Path = "DB21.DBB4"}, // Work override + new Item { Path = "DB21.DBB5"}, // Rapid override, + new Item { Path = "/Channel/State/actFeedRateIpo[u" + processId + ", 1]"}, + new Item { Path = "/Nck/Configuration/numCuttEdgeParams[1]"}, // Cutt Edge Params + }; + + // Read data + DataSvc dataSvc = new DataSvc(); + dataSvc.Read(items); + + short origin = 0; + // Convert SIEMENS enumerable to G(N) format es: G54 + if (Convert.ToInt16(items[2].Value) > 0) + { + if (Convert.ToInt16(items[1].Value) >= 5) + origin = (short)(Convert.ToInt16(items[2].Value) + 500); + else + origin = (short)(Convert.ToInt16(items[2].Value) + 53); + } + + OffsetModel offset = new OffsetModel(); + + //Read the ID of the Tool & Edge + short actualToolId = Convert.ToInt16(items[0].Value); + short actualEdgeId = Convert.ToInt16(items[1].Value); + short numCuttEdgeParams = Convert.ToInt16(items[6].Value); + int offsetEdge = (actualEdgeId - 1) * numCuttEdgeParams; + + if (actualToolId != 0 && actualEdgeId != 0) + { + //Setup the items for the tools. Must be read only this value + Item[] itemsToolEdge = new Item[4] + { + new Item { Path = "/Tool/Compensation/edgeData[u1,c"+ actualToolId +","+ (offsetEdge + 3) + "]" }, // $TC_DP3 + new Item { Path = "/Tool/Compensation/edgeData[u1,c"+ actualToolId +","+ (offsetEdge + 6) + "]" }, // $TC_DP6 + new Item { Path = "/Tool/Compensation/edgeData[u1,c"+ actualToolId +","+ (offsetEdge + 12) + "]" }, // $TC_DP12 + new Item { Path = "/Tool/Compensation/edgeData[u1,c"+ actualToolId +","+ (offsetEdge + 15) + "]" } // $TC_DP15 + }; + + dataSvc.Read(itemsToolEdge); + + offset = new OffsetModel() + { + Id = actualEdgeId, + Length = Convert.ToDouble(itemsToolEdge[0].Value), + Radius = Convert.ToDouble(itemsToolEdge[1].Value), + WearLength = Convert.ToDouble(itemsToolEdge[2].Value), + WearRadius = Convert.ToDouble(itemsToolEdge[3].Value), + RealLength = Convert.ToDouble(itemsToolEdge[0].Value) + Convert.ToDouble(itemsToolEdge[2].Value), + RealRadius = Convert.ToDouble(itemsToolEdge[1].Value) + Convert.ToDouble(itemsToolEdge[3].Value) + }; + + /* Other Method. Find it in the Database of the Tools... Too SLow? (Nicola Carminati 08/08/19) + // Find edge + EdgeModel edge = ToolTableData.Where(x => x.Id == Convert.ToInt16(items[0].Value)) + .FirstOrDefault() + .EdgesData.Where(x => x.Id == Convert.ToInt16(items[1].Value)) + .FirstOrDefault(); + + + //Find the Type of the Tool + SiemensEdgesConfiguration toolEdgesConfig = new SiemensEdgesConfiguration(); + List toolTypeConfig = toolEdgesConfig.EdgesConfig[ + ToolTableData.Where(x => x.Id == Convert.ToInt16(items[0].Value)).FirstOrDefault().ToolType + ]; + + if(toolTypeConfig != null && toolTypeConfig.Count > 0) + { + //Read Names of the parameters + String lenghtName = toolTypeConfig.Where(x => x.Path == "$TC_DP3[").FirstOrDefault().Name; + String radiusName = toolTypeConfig.Where(x => x.Path == "$TC_DP6[").FirstOrDefault().Name; + String wearLenghtName = toolTypeConfig.Where(x => x.Path == "$TC_DP12[").FirstOrDefault().Name; + String wearRadiusName = toolTypeConfig.Where(x => x.Path == "$TC_DP15[").FirstOrDefault().Name; + + if(!String.IsNullOrEmpty(wearLenghtName) && !String.IsNullOrEmpty(wearRadiusName) && !String.IsNullOrEmpty(lenghtName) && !String.IsNullOrEmpty(radiusName)) + { + // Convert edgeModel to offsetModel + offset = new OffsetModel() + { + Id = (short)edge.Id, + Length = edge.EdgeAdditionalParams[lenghtName], + Radius = edge.EdgeAdditionalParams[radiusName], + WearLength = edge.EdgeAdditionalParams[wearLenghtName], + WearRadius = edge.EdgeAdditionalParams[wearRadiusName], + RealLength = edge.EdgeAdditionalParams[lenghtName] + edge.EdgeAdditionalParams[wearLenghtName], + RealRadius = edge.EdgeAdditionalParams[radiusName] + edge.EdgeAdditionalParams[wearRadiusName] + }; + + } + + }*/ + + } + + // Creata return model + processData = new SelectedProcessData + { + ActiveOffsetId = Convert.ToInt16(items[1].Value), + Origin = origin, + ProcessMessage = "", + WorkOverride = Convert.ToByte(items[3].Value), + RapidOverride = Convert.ToByte(items[4].Value), + OffsetData = offset, + FeedOverride = Convert.ToDouble(items[5].Value) + }; + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + private CmsError PROC_ReadActiveLine(uint processId, ref string line) + { + try + { + Item item = new Item(); + if (processId == 0) + item.Path = "/Channel/ProgramInfo/actBlock[u1,1]"; // Default + else + item.Path = "/Channel/ProgramInfo/actBlock[u" + processId + ",1]"; + + DataSvc dataSvc = new DataSvc(); + dataSvc.Read(item); + + line = item.Value.ToString(); + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + #endregion PROCESS (PATH) High-level data + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #region PROCESS-AXES (PATH) High-level data + + public override CmsError AXES_RInterpPosition(ushort channel, ref Dictionary axes) + { + try + { + axes = new Dictionary(); + // Cycle between axes + // The dictionary is written asynchronously so i have to create a copy of the dictionary with .ToList() to avoid exceptions + // axes = InterpAxesPosition.ToDictionary(x => x.Key, x => x.Value); This code throws exceptions + lock (InterpAxesPosition) + { + foreach (var axis in InterpAxesPosition.ToList()) + { + axes.Add(axis.Key, axis.Value); + } + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError AXES_RMachinePosition(ushort channel, ref Dictionary axes) + { + try + { + axes = new Dictionary(); + + lock (MachineAxesPosition) + { + // Cycle between axes + // The dictionary is written asynchronously so i have to create a copy of the dictionary with .ToList() to avoid exceptions + foreach (var axis in MachineAxesPosition.ToList()) + { + axes.Add(axis.Key, axis.Value); + } + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError AXES_RProgrPosition(ushort channel, ref Dictionary axes) + { + try + { + axes = new Dictionary(); + lock (ProgrammedAxisPosition) + { + // Cycle between axes + // The dictionary is written asynchronously so i have to create a copy of the dictionary with .ToList() to avoid exceptions + foreach (var axis in ProgrammedAxisPosition.ToList()) + { + axes.Add(axis.Key, axis.Value); + } + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError AXES_RFollowingError(ushort channel, ref Dictionary axes) + { + try + { + axes = new Dictionary(); + lock (InterpAxesPosition) + { + // Cycle between axes + // The dictionary is written asynchronously so i have to create a copy of the dictionary with .ToList() to avoid exceptions + foreach (var axis in InterpAxesPosition.ToList()) + { + axes.Add(axis.Key, axis.Value); + } + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError AXES_RDistanceToGo(ushort channel, ref Dictionary axes) + { + try + { + axes = new Dictionary(); + lock (ToGoAxesPosition) + { + // Cycle between axes + // The dictionary is written asynchronously so i have to create a copy of the dictionary with .ToList() to avoid exceptions + foreach (var axis in ToGoAxesPosition.ToList()) + { + axes.Add(axis.Key, axis.Value); + } + } + } + catch (Exception ex) + { + return ManageException(ex); + } + return NO_ERROR; + } + + private Dictionary AXES_RAxesPos(ushort channel, string positionType) + { + Dictionary axes = new Dictionary(); + List axesConf = new List(); + + CmsError cmsError = AXES_RAxesNames(channel, ref axesConf); + + List items = new List(); + foreach (var conf in axesConf) + { + // Setup the items to be readed + items.Add(new Item() { Path = string.Format("/Channel/{0}[u{1},{2}]", positionType, channel, conf.Id) }); + } + + DataSvc dataSvc = new DataSvc(); + // Read all the items + dataSvc.Read(items.ToArray()); + + int i = 0; + foreach (var conf in axesConf) + { + axes.Add(conf.Id.ToString(), Convert.ToDouble(items[i].Value)); + i++; + } + + return axes; + } + + public override CmsError AXES_RAxesNames(ushort channel, ref List axesData) + { + if (!File.Exists(AXES_FILE_PATH)) + return CmsError.InternalError("File" + AXES_FILE_PATH + " not found", new Exception("File" + AXES_FILE_PATH + " not found")); + + // Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + List configuredAxes = new List(); + + Item[] ncAxes = new Item[MAX_AXES_FOR_PROCESS * 3]; + try + { + // Check if the static object is already populated + if (AxesData.Count == 0) + { + XDocument xmlAxesFile = XDocument.Load(AXES_FILE_PATH); + // Read data from file + configuredAxes = xmlAxesFile + .Root + .Elements() + .Select(x => new AxisModel() + { + Id = Convert.ToInt32(x.Attribute("id").Value), + Name = x.Value, + IsSelectable = false + }) + .Where(x => x.Id != 0) // Parse only active axes + .ToList(); + } + + // Object used for reading data from NC + DataSvc svcData = new DataSvc(); + + bool[] axesAreVisible = new bool[MAX_AXES_FOR_PROCESS]; + // Read from Nc + for (int i = 1; i <= MAX_AXES_FOR_PROCESS; i++) + { + // Set the path to read on which process is the axis + ncAxes[i - 1] = new Item("/Nck/MachineAxis/chanNoAxisIsActive[" + i + "]"); + // Set the path in order to find which axes are visible + ncAxes[i - 1 + MAX_AXES_FOR_PROCESS] = new Item("/NC/_N_CH_TEA_ACX/$MC_DISPLAY_AXIS[u" + channel + "," + i + "]"); + // Set the path of the axes type + ncAxes[i - 1 + (MAX_AXES_FOR_PROCESS * 2)] = new Item("/Nck/Configuration/axisType[" + i + "]"); + } + + svcData.Read(ncAxes); + + for (int i = 0; i < MAX_AXES_FOR_PROCESS; i++) + { + // Set visible field + axesAreVisible[i] = (Convert.ToInt32(ncAxes[i + MAX_AXES_FOR_PROCESS].Value) & 1) == 1; + int processAxes = Convert.ToInt32(ncAxes[i].Value); + // If axis is visible, add it to the output + if (processAxes == channel && axesAreVisible[i]) + { + // Check if axes is configurated axes + var axis = configuredAxes.Where(x => x.Id == (i + 1)).FirstOrDefault(); + if (axis != null) + { + axis.Type = (AXIS_TYPE)Convert.ToInt32(ncAxes[i + (MAX_AXES_FOR_PROCESS * 2)].Value); + AxesData.Add(axis); + } + } + } + + // Get from PLC which axis can be selected + List ids = new List(); + cmsError = MEM_RWByteList(R, 0, AXES_BUTTON_VISIBLE.MemType, AXES_BUTTON_VISIBLE.Address, AXES_BUTTON_VISIBLE.SubAddress, 0, AXES_BUTTON_VISIBLE.Size, ref ids); + if (cmsError.IsError()) + return cmsError; + + // Parse the data readed from PLC + foreach (byte id in ids) + { + if (id != 0) + { + // If axis exists, set it as selectable + var tmpAxis = AxesData.Where(x => x.Id == id).FirstOrDefault(); + if (tmpAxis != null) + tmpAxis.IsSelectable = true; + } + } + + axesData = AxesData; + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError AXES_RSelectedAxis(ref byte axisId) + { + // Read byte from memory + CmsError cmsError = MEM_RWByte(R, 0, SELECTED_AXIS.MemType, SELECTED_AXIS.Address, SELECTED_AXIS.SubAddress, 1, ref axisId); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + public override CmsError AXES_WSelectAxis(byte axisId) + { + // Write byte from memory + CmsError cmsError = MEM_RWByte(W, 0, SELECT_AXIS.MemType, SELECT_AXIS.Address, SELECT_AXIS.SubAddress, 1, ref axisId); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + public override CmsError AXES_ROrigin(int numberOfAxes) + { + DataSvc dataSvc = new DataSvc(); + List ncAxes = new List(); + + List axes = new List(); + CmsError cmsError = AXES_RAxesNames(1, ref axes); + + + for (int i = 1; i <= 4; i++) + { + foreach (var axis in axes) + { + var num = axis.Id + (axes.Last().Id * i); + ncAxes.Add(new Item() + { + Path = "/Channel/UserFrame/linShift[u1, " + num + "]" + }); + } + } + + dataSvc.Read(ncAxes.ToArray()); + + return NO_ERROR; + } + + #endregion PROCESS-AXES (PATH) High-level data + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #region NC Low-level function: single valiable in memory + + //Read-Write a Boolean-Value inside the NC. + public override CmsError MEM_RWBoolean(bool bWrite, int Process, MEMORY_TYPE MemType, int MemTable, int MemIndex, int MemBit, ref bool Value) + { + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + //Check if the Bit Number is Correct + cmsError = CheckBitRange(MemBit); + if (cmsError.IsError()) + return cmsError; + + //Try to get information + try + { + //Setup variables + DataSvc Data = HighPriorityDataSvc(); + + cmsError = ConvertMemToPath(MemType, MemTable, MemIndex, MemBit, 1, 'X', out string itemString); + if (cmsError.IsError()) + return cmsError; + Item item = new Item(itemString); + + //Read-Write Data + if (bWrite) + { + item.Value = Value; + Data.Write(item); + } + else + { + Data.Read(item); + Value = (bool)item.Value; + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + //Read-Write a Byte-Value-List inside the NC. In writing-mode the field "Number" is not required + public override CmsError MEM_RWByte(bool bWrite, int Process, MEMORY_TYPE MemType, int MemTable, int MemIndex, int MemByte, ref byte Value) + { + List ListValue = new List() { Value }; + + //uses the List method with one-element list + CmsError cmsError = MEM_RWByteList(bWrite, Process, MemType, MemTable, MemIndex, MemByte, 1, ref ListValue); + if (cmsError.IsError()) + return cmsError; + + Value = ListValue.First(); + + return NO_ERROR; + } + + //Write a Word-Value inside the NC. In writing-mode the field "Number" is not required + public override CmsError MEM_RWWord(bool bWrite, int Process, MEMORY_TYPE MemType, int MemTable, int MemIndex, ref ushort Value) + { + List ListValue = new List() { Value }; + + //uses the List method with one-element list + CmsError cmsError = MEM_RWWordList(bWrite, Process, MemType, MemTable, MemIndex, 1, ref ListValue); + if (cmsError.IsError()) + return cmsError; + + Value = ListValue.First(); + + return NO_ERROR; + } + + public override CmsError MEM_RWShort(bool bWrite, int Process, MEMORY_TYPE MemType, int MemTable, int MemIndex, ref short Value) + { + List ListValue = new List() { Value }; + + //uses the List method with one-element list + CmsError cmsError = MEM_RWShortList(bWrite, Process, MemType, MemTable, MemIndex, 1, ref ListValue); + if (cmsError.IsError()) + return cmsError; + + Value = ListValue.First(); + + return NO_ERROR; + } + + //Write a Word-Value inside the NC. In writing-mode the field "Number" is not required + public override CmsError MEM_RWDWord(bool bWrite, int Process, MEMORY_TYPE MemType, int MemTable, int MemIndex, ref uint Value) + { + List ListValue = new List() { Value }; + + //uses the List method with one-element list + CmsError cmsError = MEM_RWDWordList(bWrite, Process, MemType, MemTable, MemIndex, 1, ref ListValue); + if (cmsError.IsError()) + return cmsError; + + Value = ListValue.First(); + + return NO_ERROR; + } + + public override CmsError MEM_RWDouble(bool bWrite, int process, MEMORY_TYPE memType, int memTable, int memIndex, ref double value) + { + // Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + // Try to get information + try + { + // Setup variables + DataSvc Data = new DataSvc + { + Timeout = TimeoutConn, + PriorityFlag = SlPriority.highPriority + }; + + cmsError = ConvertMemToPath(memType, memTable, memIndex, 0, 1, 'D', out string itemString); + if (cmsError.IsError()) + return cmsError; + Item item = new Item(itemString); + + + byte[] byteVal; + + // Read-Write Data + if (bWrite) + { + byteVal = BitConverter.GetBytes((Single)value); + item.Value = BitConverter.ToUInt32(byteVal, 0); + Data.Write(item); + } + else + { + Data.Read(item); + byteVal = BitConverter.GetBytes((uint)item.Value); + value = unchecked(Convert.ToDouble(BitConverter.ToSingle(byteVal, 0))); + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + //Write a Int-Value inside the NC. In writing-mode the field "Number" is not required + public override CmsError MEM_RWInteger(bool bWrite, int Process, MEMORY_TYPE MemType, int MemTable, int MemIndex, ref int Value) + { + List ListValue = new List() { Value }; + + //uses the List method with one-element list + CmsError cmsError = MEM_RWIntegerList(bWrite, Process, MemType, MemTable, MemIndex, 1, ref ListValue); + if (cmsError.IsError()) + return cmsError; + + Value = ListValue.First(); + + return NO_ERROR; + } + + //-------------------------------------------------------------------------------------------------------------------------- + // Other-NC Version of Memory-Access Methods + + public override CmsError MEM_RWBoolean(bool bWrite, int Process, MEMORY_TYPE MemType, int MemIndex, int MemBit, ref bool Value) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError MEM_RWByte(bool bWrite, int Process, MEMORY_TYPE MemType, int MemIndex, int MemByte, ref byte Value) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError MEM_RWDWord(bool bWrite, int Process, MEMORY_TYPE MemType, int MemIndex, ref uint Value) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError MEM_RWInteger(bool bWrite, int Process, MEMORY_TYPE MemType, int MemIndex, ref int Value) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError MEM_RWShort(bool bWrite, int Process, MEMORY_TYPE MemType, int MemIndex, ref short Value) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError MEM_RWWord(bool bWrite, int Process, MEMORY_TYPE MemType, int MemIndex, ref ushort Value) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError MEM_RWDouble(bool bWrite, int process, MEMORY_TYPE memType, int memIndex, ref double value) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError MEM_RWDWordList(bool bWrite, int Process, MEMORY_TYPE MemType, int MemIndex, int Number, ref List Value) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError MEM_RWIntegerList(bool bWrite, int Process, MEMORY_TYPE MemType, int MemIndex, int Number, ref List Value) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError MEM_RWShortList(bool bWrite, int Process, MEMORY_TYPE MemType, int MemIndex, int Number, ref List Value) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError MEM_RWWordList(bool bWrite, int Process, MEMORY_TYPE MemType, int MemIndex, int Number, ref List Value) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError MEM_RWByteList(bool bWrite, int Process, MEMORY_TYPE MemType, int MemIndex, int MemByteStart, int Number, ref List Value) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + #endregion NC Low-level function: single valiable in memory + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #region Low level methods + + public override CmsError MEM_RWByteList(bool bWrite, int Process, MEMORY_TYPE MemType, int MemTable, int MemIndex, int MemByteStart, int Number, ref List Value) + { + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + //Try to get/set information + try + { + //Setup variables + DataSvc dataSvc = HighPriorityDataSvc(); + + cmsError = ConvertMemToPath(MemType, MemTable, MemIndex, 0, (bWrite) ? Value.Count : Number, 'B', out string itemString); + if (cmsError.IsError()) + return cmsError; + Item item = new Item(itemString); + + //Read-Write Data + if (bWrite) + { + item.Value = Value.ToArray(); + dataSvc.Write(item); + } + else + { + dataSvc.Read(item); + if (item.Value.GetType().IsArray) + Value = ((object[])item.Value).Cast().ToList(); + else + { + Value.Clear(); + Value.Add((byte)(uint)item.Value); + } + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError MEM_RWWordList(bool bWrite, int Process, MEMORY_TYPE MemType, int MemTable, int MemIndex, int Number, ref List Value) + { + ////Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + //Try to get/set information + try + { + //Setup variables + DataSvc Data = HighPriorityDataSvc(); + cmsError = ConvertMemToPath(MemType, MemTable, MemIndex, 0, (bWrite) ? Value.Count : Number, 'W', out string itemString); + + if (cmsError.IsError()) + return cmsError; + Item item = new Item(itemString); + + //Read-Write Data + if (bWrite) + { + item.Value = Value.ToArray(); + Data.Write(item); + } + else + { + Data.Read(item); + if (item.Value.GetType().IsArray) + Value = Array.ConvertAll(((object[])item.Value).Cast().ToArray(), input => (ushort)input).ToList(); + else + { + Value.Clear(); + Value.Add(Convert.ToUInt16((uint)item.Value)); + } + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError MEM_RWShortList(bool bWrite, int Process, MEMORY_TYPE MemType, int MemTable, int MemIndex, int Number, ref List Value) + { + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + //Try to get/set information + try + { + //Setup variables + DataSvc Data = HighPriorityDataSvc(); + cmsError = ConvertMemToPath(MemType, MemTable, MemIndex, 0, (bWrite) ? Value.Count : Number, 'W', out string itemString); + + if (cmsError.IsError()) + return cmsError; + Item item = new Item(itemString); + + //Read-Write Data + if (bWrite) + { + item.Value = Value.ToArray(); + Data.Write(item); + } + else + { + Data.Read(item); + if (item.Value.GetType().IsArray) + Value = Array.ConvertAll(((object[])item.Value).Cast().ToArray(), input => unchecked((short)input)).ToList(); + else + { + Value.Clear(); + Value.Add(unchecked((short)(uint)item.Value)); + } + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError MEM_RWDWordList(bool bWrite, int Process, MEMORY_TYPE MemType, int MemTable, int MemIndex, int Number, ref List Value) + { + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + //Try to get/set information + try + { + //Setup variables + DataSvc Data = HighPriorityDataSvc(); + cmsError = ConvertMemToPath(MemType, MemTable, MemIndex, 0, (bWrite) ? Value.Count : Number, 'D', out string itemString); + + if (cmsError.IsError()) + return cmsError; + Item item = new Item(itemString); + //Read-Write Data + if (bWrite) + { + item.Value = Value.ToArray(); + Data.Write(item); + } + else + { + Data.Read(item); + if (item.Value.GetType().IsArray) + Value = ((object[])item.Value).Cast().ToList(); + else + { + Value.Clear(); + Value.Add((uint)item.Value); + } + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError MEM_RWIntegerList(bool bWrite, int Process, MEMORY_TYPE MemType, int MemTable, int MemIndex, int Number, ref List Value) + { + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + //Try to get/set information + try + { + //Setup variables + DataSvc Data = HighPriorityDataSvc(); + cmsError = ConvertMemToPath(MemType, MemTable, MemIndex, 0, (bWrite) ? Value.Count : Number, 'D', out string itemString); + if (cmsError.IsError()) + return cmsError; + + Item item = new Item(itemString); + + //Read-Write Data + if (bWrite) + { + item.Value = Value.ToArray(); + Data.Write(item); + } + else + { + Data.Read(item); + if (item.Value.GetType().IsArray) + Value = Array.ConvertAll(((object[])item.Value).Cast().ToArray(), input => unchecked((int)input)).ToList(); + else + { + Value.Clear(); + Value.Add(unchecked((int)(uint)item.Value)); + } + + // Convert BigEndian to LittleEndian + Value = ChangeIntListEndianess(Value); + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + #endregion Low level methods + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #region NC Low-level function: Parameters + + public override CmsError NC_RParam(short Index, short Bit, ref bool Value) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError NC_RParam(short Index, ref byte Value) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError NC_RParam(short Index, ref short Value) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError NC_RParam(short Index, ref int Value) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError NC_RParam(short Index, ref double Value) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + #endregion NC Low-level function: Parameters + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #region File Management + + public override CmsError FILES_RGetFileList(string path, ref List files) + { + string[] rootFolders = { "WKS.DIR", "MPF.DIR", "SPF.DIR" }; + try + { + string tmpPath = FormatPath(path); + + FileSvc fileSvc = new FileSvc(); + // Preapare folder node + Node folderNode = new Node(BASE_FILE_PATH + tmpPath); + // Read files in the folder + List nodeArray = fileSvc.List(folderNode).ToList(); + + // Go through the array of file nodes + foreach (Node element in nodeArray) + { + PreviewFileModel file = new PreviewFileModel(); + if (path == "\\\\") + { + if (rootFolders.Contains(element.Name)) + { + file = new PreviewFileModel() + { + Path = path + "\\" + element.Name, + IsDirectory = element.IsDirNode, + Name = GetStringUntilOrEmpty(element.Name, "."), + AbsolutePath = element.LogicalPath + }; + files.Add(file); + } + } + else + { + file = new PreviewFileModel() + { + Path = path + "\\" + element.Name, + IsDirectory = element.IsDirNode, + Name = element.IsDirNode ? GetStringUntilOrEmpty(element.Name, ".") : element.Name, + AbsolutePath = element.LogicalPath + }; + files.Add(file); + } + + // ACCESS LEVEL CHECK (REMOVED TEMPORARILY) + //if (element.AccessRights.List == AccessLevel.KEY_0) + //{ + // var file = new PreviewFileModel() + // { + // Path = path + "\\" + element.Name, + // IsDirectory = element.IsDirNode, + // Name = element.Name, + // AbsolutePath = element.LogicalPath + // }; + + // files.Add(file); + //} + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError FILES_RGetFileInfo(string path, ref InfoFile fileInfo) + { + try + { + FileSvc fileSvc = new FileSvc(); + // Preapare folder node + Node fileNode = new Node(path); + + if (fileNode != null) + { + string filePath = "C://CMS//Active//TMP//" + fileNode.Name; + FileStream str = new FileStream(filePath, FileMode.Create); + CmsError cmsError = FILES_RProgramToFile(path, str); + if (cmsError.IsError()) + return cmsError; + fileInfo = new InfoFile() + { + CreationDate = fileNode.Attributes.LastAccess, + LastModDate = fileNode.Attributes.LastAccess, + Name = fileNode.Name, + Content = File.ReadAllLines(filePath).ToList(), + // PreviewBase64 = FindImageBase64String(IMAGES_PATH, fileNode.Name), + AbsolutePath = fileNode.LogicalPath + }; + + str.Close(); + File.Delete(filePath); + } + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError FILES_WSetActiveProgram(int processId, string filePath, ref ActiveProgramDataModel data) + { + try + { + // string ncPath = FormatPath(filePath); + + FileSvc fileSvc = new FileSvc(); + + // Preapare folder node + Node selectedNode = new Node(filePath); + + if (!selectedNode.Exists) + return FILE_NOT_FOUND_ERROR; + + // Check if file is stored on NC + if (filePath.StartsWith(BASE_FILE_PATH)) + fileSvc.Select(selectedNode, processId); + else + fileSvc.SelectExtern(selectedNode, processId); + + return FILES_RActiveProgramData(processId, ref data); + } + catch (Exception ex) + { + return ManageException(ex); + } + } + + public override CmsError FILES_WDeactivateProgram(int processId) + { + try + { + string[] piArgs = new string[4]; + piArgs[0] = "/NC"; + piArgs[1] = (200 + processId).ToString(); + piArgs[2] = "/MPF0"; + piArgs[3] = "_N_SELECT"; + + PiSvc pi = new PiSvc(piArgs); + pi.Start(); + } + catch (Exception ex) + { + return ManageException(ex); + } + return NO_ERROR; + } + + public override CmsError FILES_RActiveProgramData(int processId, ref ActiveProgramDataModel programData) + { + try + { + //Setup variables + DataSvc dataSvc = new DataSvc(); + + // Read position and tool data + List itemRead = new List() + { + new Item($"/Channel/ProgramInfo/workPandProgName[u{processId}]"), + new Item($"/Channel/ProgramInfo/actPartProgram[u{processId}]") + }; + + //Read Data + dataSvc.Read(itemRead.ToArray()); + + // Elaborate String + string trimString = ((string)itemRead[0].Value); + trimString = trimString.Replace("_N_", ""); + int lastUnderscore = trimString.LastIndexOf("_"); + if (lastUnderscore >= 0) + trimString = trimString.Remove(lastUnderscore, 1).Insert(lastUnderscore, "."); + + // check if is the NULL Program + if (trimString == "/MPF0") + { + programData = new ActiveProgramDataModel() + { + Path = "", + IsoLines = new List(), + TimeLeft = new DateTime() + }; + return NO_ERROR; + } + + // Separate string into list of lines + List isoLines = itemRead[1] + .Value + .ToString() + .Split('\n') // Line separator + .Skip(1) // The actPartProgram read starting with the line before the current + .ToList(); + + programData = new ActiveProgramDataModel() + { + Path = trimString, + IsoLines = isoLines, + TimeLeft = new DateTime() + }; + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError FILES_UploadPartProgram(string localPath, string name, ref string newFilePath) + { + File.Copy(localPath + name, PART_PRG_PATH + name, true); + + newFilePath = PART_PRG_PATH + name; + + return NO_ERROR; + } + + public override CmsError FILES_CopyProgram(string partProgramPath, string newPartProgramPath, bool failIfExist) + { + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + try + { + //Setup variables + FileSvc FileData = new FileSvc(); + Node sourceNode = new Node(partProgramPath); + Node destNode = new Node(newPartProgramPath); + + //Execute Function + FileData.Copy(sourceNode, destNode, failIfExist); + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError FILES_DeleteProgram(string partProgramPath, string partProgramName) + { + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + try + { + // Setup variables + FileSvc FileData = new FileSvc(); + Node sourceNode = new Node(partProgramPath); + + //Execute Function + FileData.Delete(sourceNode); + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError FILES_RProgramToFile(string partProgramPath, FileStream localFile) + { + // Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + try + { + // Setup variables + string tmpFile = Path.GetTempFileName(); + FileSvc FileData = new FileSvc(); + Node sourceNode = new Node(partProgramPath); + Node destNode = new Node(tmpFile); + + // Execute Function + FileData.Copy(sourceNode, destNode, true); + + FileStream tmpFileStream = new FileStream(tmpFile, FileMode.Open); + + // Write to local file + WriteLocalFile(ReadLocalFile(tmpFileStream), ref localFile); + + tmpFileStream.Close(); + // Delete temporary file + File.Delete(tmpFile); + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError FILES_WProgramFromFile(string partProgramPath, FileStream localFile) + { + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + try + { + // Setup variables + FileSvc FileData = new FileSvc(); + Node sourceNode = new Node(localFile.Name); + Node destNode = new Node(partProgramPath); + + //Execute Function + FileData.Copy(sourceNode, destNode, true); + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError FILES_RQueueData(ref List statusList) + { + return NO_ERROR; + } + + public override CmsError FILES_RQueueDataByProcess(ref QueueStatusModel status, int processId) + { return NO_ERROR; } + + public override CmsError FILES_WStartQueue() + { + return NO_ERROR; + } + + public override CmsError FILES_WStopQueue() + { + return NO_ERROR; + } + + public override CmsError FILES_WLoadNextPartProgram(string localPath, string ncFileName) + { + return NO_ERROR; + } + + public override CmsError FILES_WUploadJobFilesAndActivate(int processId, string jobExtractedPath, string fileToActivate) + { + return NO_ERROR; + } + + public override CmsError FILES_RGetProgramType(ref PROGRAM_TYPE_ENUM programType) + { + programType = PROGRAM_TYPE_ENUM.PART_PROGRAM; + + return NO_ERROR; + } + + public override CmsError FILES_WCleanUploadFolder() + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError FILES_WUploadCustomMainProgramAndActivate(int processId, string customPartProgramContent, ref ActiveProgramDataModel activeData) + { + string customMainName = string.Format(CUSTOM_MAIN_PROGRAM, processId); + + string newFilePath = ""; + CmsError cmsError = FILES_UploadPartProgram(customPartProgramContent, customMainName, ref newFilePath); + if (cmsError.IsError()) + return cmsError; + + cmsError = FILES_WSetActiveProgram(processId, newFilePath, ref activeData); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + private IEnumerable GetLinesFromString(string text) + { + string line; + using (StringReader reader = new StringReader(text)) + { + while ((line = reader.ReadLine()) != null) + { + yield return line; + } + } + } + + private string FormatPath(string path) + { + path = path.TrimStart('\\'); + path = path.TrimStart('/'); + path = path.TrimEnd('\\'); + + return path.Replace('\\', '/'); + } + + #endregion File Management + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #region Siemens Tool Management + + public override CmsError TOOLS_RConfiguration(ref ToolTableConfiguration config) + { + // Set limits + config.MaxTools = MAX_TOOL_NUMER; + config.MaxEdgesPerTools = MAX_EDGES_PER_TOOL; + config.MaxToolsPerFamily = MAX_TOOLS_PER_FAMILY; + config.MaxMultitools = MAX_MULTITOOLS_NUMBER; + config.MaxToolsPerMultitools = MAX_TOOLS_PER_MULTITOOL; + + // Set options + config.MultitoolOptionActive = MULTITOOL_OPTION_ACTIVE; + config.FamilyOptionActive = true; + config.MagPositionOptionActive = true; + config.RadiusMetricType = false; + config.LifeOption = true; + + // Set fields configurations + config.ToolsConfiguration = SiemensToolFieldsConfig; + config.FamiliesConfiguration = SiemensFamilyFieldsConfig; + config.ShanksConfiguration = SiemensShankFieldsConfig; + config.MagazinePosConfiguration = SiemensMagazinePosFieldsConfig; + config.EdgesConfiguration = SiemensEdgesFieldsConfiguration; + + config.EdgesConfiguration.EdgesAdditionalParamsConfiguration = new Dictionary>(); + // Remove path and set only names as additionalParams + foreach (int key in Add_Edges_Param_Config.EdgesConfig.Keys) + { + List tmpNames = new List(); + foreach (var conf in Add_Edges_Param_Config.EdgesConfig[key]) + { + tmpNames.Add(conf.Name); + } + // Set config field + config.EdgesConfiguration.EdgesAdditionalParamsConfiguration.Add(key, tmpNames); + } + + config.Magazines = MagazineConfig; + //config.Magazines = new List(); + //foreach (PositionModel pos in MagazinePositionsData) + //{ + // var tmp = config.Magazines.Where(x => x.Id == pos.MagazineId).FirstOrDefault(); + // if (tmp == null) + // { + // config.Magazines.Add(new MagazineConfigModel() + // { + // Id = pos.MagazineId, + // Type = MAGAZINE_TYPE.CHAIN + // }); + // } + //} + + return NO_ERROR; + } + + #region Tools functions + + public override CmsError TOOLS_RToolsData(ref List toolTable) + { + toolTable = new List(ToolTableData.Select(x => + { + // Find if is loaded in magazine + MountedToolModel tool = MagazineMountedTools.Where(y => y.ToolId == x.Id).FirstOrDefault(); + if (tool != null) + { + x.MagazineId = tool.MagazineId; + x.PositionId = tool.PositionId; + } + else + { + x.MagazineId = 0; + x.PositionId = 0; + } + + // Update multitool id + x.MultitoolId = ToolIsInMultitool(x.Id); + return x; + }) + .ToList()); + return NO_ERROR; + } + + public override CmsError TOOLS_WAddTool(ref SiemensToolModel tool) + { + CmsError cmsError = CheckToolData(ref tool); + if (cmsError.IsError()) + return cmsError; + try + { + //Create Tools + string[] piArgs = new string[6]; + piArgs[0] = "/NC"; + piArgs[1] = "401"; + piArgs[2] = tool.FamilyName.Trim().PadRight(32); //Name (32 char) + piArgs[3] = "00000"; //Tool ID (00000 > autom) + piArgs[4] = "00000"; //Duplo ID (00000 > autom) + piArgs[5] = "_N_TMCRTO"; + + PiSvc pi = new PiSvc(piArgs); + pi.Start(); + + // Get new tool id + tool.Id = GetLastToolId(); + + // Update new tool + cmsError = TOOLS_WUpdateTool(ref tool); + if (cmsError.IsError()) + return cmsError; + + // Get edge additional data + SiemensEdgesConfiguration toolEdgesConfig = new SiemensEdgesConfiguration(); + List toolTypeConfig = toolEdgesConfig.EdgesConfig[tool.ToolType]; + Dictionary edgeData = toolTypeConfig.ToDictionary(x => x.Name, x => 0.0); + // Create new edge + tool.EdgesData = new List() + { + new EdgeModel + { + Id = 1, + ResidualLife = 0, + PreAlmLife = 0, + NominalLife = 0, + EdgeAdditionalParams = edgeData + } + }; + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError TOOLS_WUpdateTool(ref SiemensToolModel tool) + { + CmsError cmsError = CheckToolData(ref tool); + if (cmsError.IsError()) + return cmsError; + + try + { + // TC_TP2 + DataSvc dataSvc = new DataSvc(); + // Create status byte from bit array + BitArray bitArray = new BitArray(new bool[] { tool.IsActive, tool.IsEnabled, tool.IsInhibited, tool.IsMeasured, tool.PreAlarm, tool.InChangeTool, tool.InFixedPlace, tool.IsInUse }); + int[] array = new int[1]; + bitArray.CopyTo(array, 0); + + // Read tool info ( rotation, cooling etc...) + Item toolInfo = new Item("/Tool/Compensation/edgeData[c" + tool.Id + ",25]"); + dataSvc.Read(toolInfo); + int val = Convert.ToInt32(toolInfo.Value); + + bool clockwhise = false, counterClockwhise = false; + + // Convert rotation into boolean + switch (tool.Rotation) + { + case ROTATION.CLOCKWHISE: + clockwhise = true; + counterClockwhise = false; + break; + + case ROTATION.COUNTERCLOCKWHISE: + clockwhise = false; + counterClockwhise = true; + break; + } + + // Set rotation data + val = SetBitValue(val, clockwhise, 9); + val = SetBitValue(val, counterClockwhise, 10); + // Set cooling + val = SetBitValue(val, tool.Cooling1, 11); + val = SetBitValue(val, tool.Cooling2, 12); + + toolInfo.Value = val; + + List items = new List() + { + // TC_TP2 + new Item("/Tool/Data/toolIdent[" + tool.Id + "]") { Value = tool.FamilyName }, + // TC_TP3 + new Item() { Path = "/Tool/Data/toolsize_left[" + tool.Id + "]", Value = tool.LeftSize }, + // TC_TP4 + new Item() { Path = "/Tool/Data/toolsize_right[" + tool.Id + "]", Value = tool.RightSize }, + // TC_TP7 + new Item() { Path = "/Tool/Data/toolplace_spec[" + tool.Id + "]", Value = tool.MagazinePositionType }, + // TC_TP8 + new Item() { Path = "/Tool/Data/toolStateL[" + tool.Id + "]", Value = array[0] }, + // TC_DP1 + new Item() { Path = "/Tool/Compensation/edgeData[c" + tool.Id + ",1]", Value = tool.ToolType }, + // TC_DP25 + { toolInfo }, + // Max speed + new Item() { Path = "/Tool/Data/toolMaxVelo[" + tool.Id + "]", Value = tool.MaxSpeed }, + // Max acceleration + // new Item() { Path = "/Tool/Data/toolMaxAcc[" + tool.Id + "]", Value = tool.MaxAcceleration }, + + // Custom fields + new Item() {Path = "/Tool/User/data[c1," + tool.Id + "]", Value = tool.Load}, + + new Item() {Path = "/Tool/User/data[c2," + tool.Id + "]", Value = tool.Gamma}, + + new Item() {Path = "/Tool/User/data[c3," + tool.Id + "]", Value = tool.MaxLoadPctAutoload}, + + new Item() {Path = "/Tool/User/data[c4," + tool.Id + "]", Value = tool.MinLoadPctAutoload}, + + new Item() {Path = "/Tool/User/data[c5," + tool.Id + "]", Value = tool.ToolTypeCode}, + }; + + if (LIFE_OPTION_ACTIVE) // TC_TP9 + items.Add(new Item() { Path = "/Tool/Data/toolMon[" + tool.Id + "]", Value = (int)tool.LifeType }); + + dataSvc.Write(items.ToArray()); + + Item childId = new Item() { Path = "/Tool/Data/duploNo[" + tool.Id + "]" }; + dataSvc.Read(childId); + tool.ChildId = Convert.ToInt32(childId.Value); + } + catch (Exception ex) + { + return ManageException(ex); + } + return NO_ERROR; + } + + public override CmsError TOOLS_WDeleteTool(int id) + { + // Find if tool exists + var tool = ToolTableData.Where(x => x.Id == id).FirstOrDefault(); + if (tool == null) + return INCORRECT_PARAMETERS_ERROR; + + // Check if tool is mounted in magazine + bool isMounted = MagazineMountedTools.Exists(x => x.ToolId == tool.Id); + if (isMounted) + return TOOL_IS_MOUNTED_ERROR; + + try + { + // Create string parameters + string[] piArgs = new string[4]; + piArgs[0] = "/NC"; + piArgs[1] = "401"; + piArgs[2] = id.ToString().PadLeft(5, '0'); // Tool ID (> 00000) + piArgs[3] = "_N_DELETO"; + // Start NC delete command + PiSvc pi = new PiSvc(piArgs); + pi.Start(); + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + private CmsError CheckToolData(ref SiemensToolModel tool) + { + int toolId = tool.Id; + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + // Check if it can be added a tool + if (ToolTableData.Count == MAX_TOOL_NUMER) + return MAX_TOOL_REACHED_ERROR; + // Check if family has reached max tool number + string family = tool.FamilyName; + int toolsWithSameFamily = ToolTableData.Where(x => x.FamilyName == family && x.Id != toolId).Count(); + if (toolsWithSameFamily >= MAX_TOOLS_PER_FAMILY) + return MAX_FAMILY_REACHED_ERROR; + + if (tool.FamilyName.Count() > 32) + tool.FamilyName = tool.FamilyName.Substring(0, 32); + + return NO_ERROR; + } + + #endregion Tools functions + + #region Shanks functions + + public override CmsError TOOLS_RShanksData(ref List shanksData) + { + return NO_ERROR; + // *SHANK FIX* + shanksData = MultitoolsData; + + foreach (ShankModel shank in shanksData) + { + // Get magazine and position id + MountedToolModel mountedTool = MagazineMountedTools.Where(y => y.ToolId == shank.Id).FirstOrDefault(); + if (mountedTool != null) + { + shank.MagazineId = mountedTool.MagazineId; + shank.PositionId = mountedTool.PositionId; + } + else + { + shank.MagazineId = 0; + shank.PositionId = 0; + } + + // Populate childs + foreach (ShankChildModel child in shank.ChildsTools) + { + // Find tool by id + SiemensToolModel tool = ToolTableData.Where(x => x.Id == child.Id).FirstOrDefault(); + if (tool != null) + { + child.FamilyName = tool.FamilyName; + child.ToolType = tool.ToolType; + } + } + } + + return NO_ERROR; + } + + public override CmsError TOOLS_WAddShank(ref ShankModel shank) + { + return NO_ERROR; + + // Check if you can add a multitool + if (MultitoolsData.Count >= MAX_MULTITOOLS_NUMBER) + return MAX_MULTITOOL_REACHED_ERROR; + + // Check data + CmsError cmsError = CheckMultitoolData(ref shank, false); + if (cmsError.IsError()) + return cmsError; + + try + { + //Create Shank with NC Pi service + string[] piArgs = new string[8]; + piArgs[0] = "/NC"; + piArgs[1] = "401"; + piArgs[2] = shank.Name.Trim().PadRight(32); + piArgs[3] = "-0001"; // Reserved + piArgs[4] = "00000"; // "00000" or “-0001” -> Nc choice / “00001” not allowed + piArgs[5] = MAX_TOOLS_PER_MULTITOOL.ToString().PadLeft(3, '0');// shank.MaxChilds.ToString().PadLeft(3, '0'); // From "002" to "$MN_MAX_TOOLS_PER_MULTITOOL" // 001 not allowed + piArgs[6] = "1"; // “1”..”3” tipo di riconoscimento distanza tra utensili nel multitool + piArgs[7] = "_N_TMCRMT"; + + // PI create command + PiSvc pi = new PiSvc(piArgs); + pi.Start(); + + // Find new tool id + shank.Id = GetLastMultitoolId(); + + DataSvc dataSvc = new DataSvc(); + + // WriteMultitool position type = 0 in order to load tools + for (int i = 0; i < MAX_TOOLS_PER_MULTITOOL; i++) + { + int paramId = (i * 6) + 3; + + Item item = new Item() + { + Path = string.Format("/Tool/MTPlace/mtPlaceData[c{0},{1}]", shank.Id, paramId), + Value = 0 + }; + dataSvc.Write(item); + } + // Update data + cmsError = TOOLS_WUpdateShank(ref shank); + if (cmsError.IsError()) + return cmsError; + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError TOOLS_WUpdateShank(ref ShankModel shank) + { + return NO_ERROR; + + CmsError cmsError = CheckMultitoolData(ref shank, true); + if (cmsError.IsError()) + return cmsError; + + try + { + DataSvc dataSvc = new DataSvc(); + // Set status byte + BitArray bitArray = new BitArray(new bool[] { false, shank.IsEnabled, shank.IsInhibited, false, false, shank.InChangeTool, shank.InFixedPlace, shank.InUse }); + int[] array = new int[1]; + bitArray.CopyTo(array, 0); + + List items = new List() + { + // TC_MTP2 + new Item("/Tool/MT/multitoolIdent[" + shank.Id + "]") { Value = shank.Name }, + // TC_MTP3 + new Item() { Path = "/Tool/MT/multitoolsize_left[" + shank.Id + "]", Value = shank.LeftSize <= 0 ? 1 : shank.LeftSize }, + // TC_MTP4 + new Item() { Path = "/Tool/MT/multitoolsize_right[" + shank.Id + "]", Value = shank.RightSize <= 0 ? 1 : shank.RightSize }, + // TC_TMP7 + new Item() { Path = "/Tool/MT/multitoolplace_spec[" + shank.Id + "]", Value = shank.MagazinePositionType <= 0 ? 1 : shank.MagazinePositionType }, + // TC_MTP8 + new Item() { Path = "/Tool/MT/multitoolStateL[" + shank.Id + "]", Value = array[0] } + }; + + dataSvc.Write(items.ToArray()); + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError TOOLS_WDeleteShank(int id) + { + return NO_ERROR; + + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + // Find if exists + var multitool = MultitoolsData.Where(x => x.Id == id).FirstOrDefault(); + if (multitool == null) + return INCORRECT_PARAMETERS_ERROR; + // Check if multitool is mounted in magazine + bool isMounted = MagazineMountedTools.Exists(x => x.ToolId == multitool.Id); + if (isMounted) + return TOOL_IS_MOUNTED_ERROR; + try + { + // Create string parameters + string[] piArgs = new string[7]; + piArgs[0] = "/NC"; + piArgs[1] = "401"; + piArgs[2] = "".PadRight(32); + piArgs[3] = "00000"; + piArgs[4] = id.ToString().PadLeft(5, '0'); // Tool ID (> 00000) + piArgs[5] = "1"; // 0 No delete childs, 1 delete childs + piArgs[6] = "_N_TMDLMT"; + // Start NC delete command + PiSvc pi = new PiSvc(piArgs); + pi.Start(); + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + #endregion Shanks functions + + #region Families functions + + public override CmsError TOOLS_RFamilyData(ref List families) + { + families = FamiliesData; + foreach (FamilyModel family in families) + { + // Get family childs tools + family.ChildTools = ToolTableData + .Where(x => x.FamilyName == family.Name) + .Select(x => new FamilyChildModel() + { + Id = x.Id, + ChildId = x.ChildId, + ToolType = x.ToolType + }) + .ToList(); + // Set current family child tools + family.ChildTools + .Sort((p, q) => p.ChildId.CompareTo(q.ChildId)); + } + + return NO_ERROR; + } + + public override CmsError TOOLS_WAddFamily(ref FamilyModel family) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_WUpdateFamilyData(string oldName, string newName) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_WDeleteFamily(string name) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + #endregion Families functions + + #region Edges functions + + public override CmsError TOOLS_WAddEdge(int toolId, ref EdgeModel edge) + { + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + var tool = ToolTableData.Where(x => x.Id == toolId).FirstOrDefault(); + + if (tool == null) + return INCORRECT_PARAMETERS_ERROR; + + if (tool.EdgesData.Count >= MAX_EDGES_PER_TOOL) + return MAX_EDGES_PER_TOOL_REACHED_ERROR; + + List ids = Enumerable.Range(1, MAX_EDGES_PER_TOOL).ToList(); + + foreach (var edgeVal in tool.EdgesData) + { + ids.Remove(edgeVal.Id); + } + + // Get next edge id + int nextEdgeId = ids[0]; + + try + { + // Create strings parameters + string[] piArgs = new string[5]; + piArgs[0] = "/NC"; + piArgs[1] = "401"; + piArgs[2] = toolId.ToString().PadLeft(5, '0'); //Tool ID + piArgs[3] = "00000"; //Cutt. edge ID (00000 > autom) + piArgs[4] = "_N_CRCEDN"; + // Start NC add command + PiSvc pi = new PiSvc(piArgs); + pi.Start(); + + edge.Id = nextEdgeId; + + cmsError = TOOLS_WUpdateEdge(toolId, ref edge); + if (cmsError.IsError()) + return cmsError; + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError TOOLS_WUpdateEdge(int toolId, ref EdgeModel edge) + { + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + SiemensToolModel tool = ToolTableData.Where(x => x.Id == toolId).FirstOrDefault(); + if (tool == null) + return INCORRECT_PARAMETERS_ERROR; + if (tool.ToolType == 9999) + return INCORRECT_PARAMETERS_ERROR; + try + { + // Initialize edges configuration + SiemensEdgesConfiguration toolEdgesConfig = new SiemensEdgesConfiguration(); + // Get config for current tool type + List toolTypeConfig = toolEdgesConfig.EdgesConfig[tool.ToolType]; + DataSvc dataSvc = new DataSvc(); + List items = new List(); + + int edgeLifeOffset = (edge.Id - 1) * 9; + if (LIFE_OPTION_ACTIVE) // Check if life option is active + { + switch (tool.LifeType) + { + // Add item choosing based on life + case SIEMENS_LIFE_TYPE.TIME: + { + items.Add(new Item() { Path = string.Format("/Tool/Supervision/data[c{0}, {1}]", tool.Id, edgeLifeOffset + 1), Value = edge.PreAlmLife }); + items.Add(new Item() { Path = string.Format("/Tool/Supervision/data[c{0}, {1}]", tool.Id, edgeLifeOffset + 2), Value = edge.NominalLife }); + items.Add(new Item() { Path = string.Format("/Tool/Supervision/data[c{0}, {1}]", tool.Id, edgeLifeOffset + 5), Value = edge.ResidualLife }); + } + break; + + case SIEMENS_LIFE_TYPE.COUNT: + { + items.Add(new Item() { Path = string.Format("/Tool/Supervision/data[c{0}, {1}]", tool.Id, edgeLifeOffset + 3), Value = edge.PreAlmLife }); + items.Add(new Item() { Path = string.Format("/Tool/Supervision/data[c{0}, {1}]", tool.Id, edgeLifeOffset + 6), Value = edge.NominalLife }); + items.Add(new Item() { Path = string.Format("/Tool/Supervision/data[c{0}, {1}]", tool.Id, edgeLifeOffset + 4), Value = edge.ResidualLife }); + } + break; + + case SIEMENS_LIFE_TYPE.WEAR: + { + items.Add(new Item() { Path = string.Format("/Tool/Supervision/data[c{0}, {1}]", tool.Id, edgeLifeOffset + 7), Value = edge.PreAlmLife }); + items.Add(new Item() { Path = string.Format("/Tool/Supervision/data[c{0}, {1}]", tool.Id, edgeLifeOffset + 9), Value = edge.NominalLife }); + items.Add(new Item() { Path = string.Format("/Tool/Supervision/data[c{0}, {1}]", tool.Id, edgeLifeOffset + 8), Value = edge.ResidualLife }); + } + break; + } + } + // Edge params + int edgeParamsIndex = ((edge.Id - 1) * 35); + + // Set edge id type + items.Add(new Item() { Path = string.Format("/Tool/Compensation/edgeData[c{0},{1}]", tool.Id, edgeParamsIndex + 1), Value = tool.ToolType }); + + // Update edge type to 9 + items.Add(new Item() { Path = string.Format("/Tool/Compensation/edgeData[c{0}, {1}]", tool.Id, edgeParamsIndex + 2), Value = 9 }); + + // Set edge additional params, read by configuration + foreach (EdgeConfigModel conf in toolTypeConfig) + { + if (edge.EdgeAdditionalParams.ContainsKey(conf.Name)) + { + items.Add(new Item() { Path = string.Format("/Tool/Compensation/edgeData[c{0}, {1}]", tool.Id, edgeParamsIndex + conf.Number), Value = edge.EdgeAdditionalParams[conf.Name] }); + } + } + + dataSvc.Write(items.ToArray()); + } + catch (Exception ex) + { + return ManageException(ex); + } + return NO_ERROR; + } + + public override CmsError TOOLS_WDeleteEdge(int toolId, int edgeId) + { + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + // Find tool + var tool = ToolTableData.Where(x => x.Id == toolId).FirstOrDefault(); + // If tool not exists, return + if (tool == null) + return INCORRECT_PARAMETERS_ERROR; + // if edge not exists, return + if (tool.EdgesData.Where(x => x.Id == edgeId).FirstOrDefault() == null) + return INCORRECT_PARAMETERS_ERROR; + // If there is only 1 edge, return with error + if (tool.EdgesData.Count == 1) + return INCORRECT_PARAMETERS_ERROR; + try + { + // Create strings parameters + string[] piArgs = new string[5]; + piArgs[0] = "/NC"; + piArgs[1] = "401"; + piArgs[2] = toolId.ToString().PadLeft(5, '0'); //Tool ID (> 00000) + piArgs[3] = edgeId.ToString().PadLeft(5, '0'); //Cutt. edge ID (> 00000) + piArgs[4] = "_N_DELECE"; + // Start NC delete command + PiSvc pi = new PiSvc(piArgs); + pi.Start(); + } + catch (Exception ex) + { + return ManageException(ex); + } + return NO_ERROR; + } + + #endregion Edges functions + + #region Load/Unload functions + + public override CmsError TOOLS_WLoadToolInMagazine(int magazineId, NewToolInMagazineModel newMagazineTool, ref MountedToolModel newMountedTool) + { + // Check if magazine is occupied + if (MagazineAction.Action != MAGAZINE_ACTIONS.READY) + return MAGAZINE_BUSY_ERROR; + + // Get mag config + SiemensMagazineConfigModel magConfig = MagazineConfig.Where(x => x.Id == magazineId).FirstOrDefault(); + if (magConfig == null || !magConfig.LoadingIsActive) + return INCORRECT_PARAMETERS_ERROR; + + // Get magazine position type + PositionModel position = MagazinePositionsData.Where(x => x.PositionId == newMagazineTool.PositionId && x.MagazineId == magazineId).FirstOrDefault(); + if (position == null || position.Disabled) + return INCORRECT_PARAMETERS_ERROR; + + if (position.Occupied) + return MAGAZINE_POSITION_OCCUPIED_ERROR; + + // Get tool data + var tool = GetToolOrMultitool(newMagazineTool.ToolId); + if (tool == null) + return INCORRECT_PARAMETERS_ERROR; + + // Check if magazine position is occupied + MountedToolModel magPos = MagazineMountedTools + .Where(x => x.MagazineId == magazineId && x.PositionId == newMagazineTool.PositionId) + .FirstOrDefault(); + + if (magPos != null) + return MAGAZINE_POSITION_OCCUPIED_ERROR; + + // Get position type + int newToolPositionType = tool is SiemensToolModel ? + (tool as SiemensToolModel).MagazinePositionType : + (tool as ShankModel).MagazinePositionType; + + // Check type + if (newToolPositionType != position.Type) + return TOOL_AND_POSITION_NOT_MATCHING_ERROR; + + // Check if tool can fit in the position considering disabled positions + if (magConfig.Type != SIEMENS_MAGAZINE_TYPE.BOX_MAGAZINE) + { + foreach (var pos in MagazinePositionsData) + { + if (pos.Disabled && pos.MagazineId == magazineId) + { + // If magazine is circular, move position before ( for left case ) or after ( right case ) the location you want to mount the tool + var right = pos.PositionId < newMagazineTool.PositionId ? pos.PositionId + magConfig.MaxPositions : pos.PositionId; + var left = pos.PositionId > newMagazineTool.PositionId ? pos.PositionId - magConfig.MaxPositions : pos.PositionId; + + // Calculate right space needed + double rightToBeMount = newMagazineTool.PositionId + ((tool as SiemensToolModel).RightSize / 2.0); + if (right < rightToBeMount) + return MAGAZINE_POSITION_OCCUPIED_ERROR; + + // Left check + // Calculate left space needed + double leftToBeMounted = newMagazineTool.PositionId - ((tool as SiemensToolModel).LeftSize / 2.0); + if (left > leftToBeMounted) + return MAGAZINE_POSITION_OCCUPIED_ERROR; + } + } + } + else + { + // Check if near positions are disabled + var posizionDisabled = MagazinePositionsData.Where( + x => x.MagazineId == magazineId && x.Disabled == true && + ((x.PositionId > newMagazineTool.PositionId && x.PositionId <= newMagazineTool.PositionId + (tool as SiemensToolModel).RightSize / 2.0) + || (x.PositionId < newMagazineTool.PositionId && x.PositionId >= newMagazineTool.PositionId - (tool as SiemensToolModel).LeftSize / 2.0))) + .ToList(); + + if (posizionDisabled.Count() > 0) + return MAGAZINE_POSITION_OCCUPIED_ERROR; + } + + + // Check if tool can fit in the position considering other tools + foreach (var mountedTool in MagazineMountedTools) + { + // Check if is not the same position && if is different check if the position is on the same magazine + if (mountedTool.PositionId != newMagazineTool.PositionId && mountedTool.MagazineId == magazineId) + { + // Get mounted tool data + int toolIndex = ToolTableData.FindIndex(x => x.Id == mountedTool.ToolId); + if (toolIndex > -1) + { + int decPosition, incPosition; + decPosition = incPosition = mountedTool.PositionId; + // If the magazine is a circular magazine move position before ( for left case ) or after ( right case ) the location you want to mount the tool + if (magConfig.Type != SIEMENS_MAGAZINE_TYPE.BOX_MAGAZINE) + { + // If magazine is circular, move position before ( for left case ) or after ( right case ) the location you want to mount the tool + decPosition = decPosition < newMagazineTool.PositionId ? decPosition + magConfig.MaxPositions : decPosition; + incPosition = incPosition > newMagazineTool.PositionId ? incPosition - magConfig.MaxPositions : incPosition; + + // Right check + // Calculate left space occupied + double leftMounted = decPosition - (ToolTableData[toolIndex].LeftSize / 2.0); + // Calculate right space needed + double rightToBeMount = newMagazineTool.PositionId + ((tool as SiemensToolModel).RightSize / 2.0); + if (leftMounted < rightToBeMount) + return MAGAZINE_POSITION_OCCUPIED_ERROR; + + // Left check + // Calculate right space occupied + double rightMounted = incPosition + (ToolTableData[toolIndex].RightSize / 2.0); + // Calculate left space needed + double leftToBeMounted = newMagazineTool.PositionId - ((tool as SiemensToolModel).LeftSize / 2.0); + if (rightMounted > leftToBeMounted) + return MAGAZINE_POSITION_OCCUPIED_ERROR; + } + else + { + // Right check + if (newMagazineTool.PositionId < mountedTool.PositionId) + { + // Calculate left space occupied + double leftMounted = mountedTool.PositionId - (ToolTableData[toolIndex].LeftSize / 2.0); + // Calculate right space needed + double rightToBeMount = newMagazineTool.PositionId + ((tool as SiemensToolModel).RightSize / 2.0); + if (leftMounted < rightToBeMount) + return MAGAZINE_POSITION_OCCUPIED_ERROR; + } + + // Left check + // Calculate right space occupied + if (newMagazineTool.PositionId > mountedTool.PositionId) + { + double rightMounted = mountedTool.PositionId + (ToolTableData[toolIndex].RightSize / 2.0); + // Calculate left space needed + double leftToBeMounted = newMagazineTool.PositionId - ((tool as SiemensToolModel).LeftSize / 2.0); + if (rightMounted > leftToBeMounted) + return MAGAZINE_POSITION_OCCUPIED_ERROR; + } + } + } + } + } + + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + try + { + //Load tool in magazine + string[] piArgs = new string[8]; + piArgs[0] = "/NC"; + piArgs[1] = "401"; + piArgs[2] = newMagazineTool.ToolId.ToString().PadLeft(5, '0'); //Tool ID (> 00000) + piArgs[3] = magConfig.LoadPosition.ToString().PadLeft(5, '0'); ; // Manina carico (valore fisso) + piArgs[4] = "09999"; // Magazzino di carico (valore fisso) + piArgs[5] = newMagazineTool.PositionId.ToString().PadLeft(5, '0'); // Manina di destinazione (dove caricare l'utensile) + piArgs[6] = magazineId.ToString().PadLeft(5, '0'); // Magazzino di destinazione (dove caricare l'utensile) + piArgs[7] = "_N_TMMVTL"; + + // Start NC load command + PiSvc pi = new PiSvc(piArgs); + pi.Start(); + } + catch (Exception ex) + { + return ManageException(ex); + } + + // Mount temporarily till the Siemens notification arrives + MoveToolInMagazineList(newMagazineTool.ToolId, magazineId, newMagazineTool.PositionId); + + newMountedTool = new MountedToolModel() + { + MagazineId = magazineId, + PositionId = newMagazineTool.PositionId, + ToolId = newMagazineTool.ToolId, + ChildTool = tool as SiemensToolModel, + ChildShank = null // Todo when multitools work + }; + + return NO_ERROR; + } + + public override CmsError TOOLS_WUnloadToolFromMagazine(int magazineId, int positionId) + { + if (MagazineAction.Action != MAGAZINE_ACTIONS.READY) + return MAGAZINE_BUSY_ERROR; + + // Get mag config + SiemensMagazineConfigModel magConfig = MagazineConfig.Where(x => x.Id == magazineId).FirstOrDefault(); + if (magConfig == null || !magConfig.LoadingIsActive) + return INCORRECT_PARAMETERS_ERROR; + + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + try + { + //UnLoad tool in magazine + string[] piArgs = new string[8]; + piArgs[0] = "/NC"; + piArgs[1] = "401"; + piArgs[2] = "-0001"; // Tool ID (Fixed, no ID) + piArgs[3] = positionId.ToString().PadLeft(5, '0'); // Manina carico (valore fisso) + piArgs[4] = magazineId.ToString().PadLeft(5, '0'); // Magazzino di carico (valore fisso) + piArgs[5] = magConfig.LoadPosition.ToString().PadLeft(5, '0'); //Manina carico (valore fisso) + piArgs[6] = "09999"; // Magazzino da cui scaricare l'utensile + piArgs[7] = "_N_TMMVTL"; + + // Start NC load command + PiSvc pi = new PiSvc(piArgs); + pi.Start(); + } + catch (Exception ex) + { + return ManageException(ex); + } + + //// Smount temporarily till the Siemens notification arrives + int magPosIndex = MagazineMountedTools.FindIndex(x => x.MagazineId == magazineId && x.PositionId == positionId); + if (magPosIndex >= 0) + MagazineMountedTools.Remove(MagazineMountedTools[magPosIndex]); + + return NO_ERROR; + } + + public override CmsError TOOLS_WLoadToolIntoShank(int shankId, int positionId, int toolId) + { + return NO_ERROR; + + // Check if mt exists + ShankModel shank = MultitoolsData.Where(x => x.Id == shankId).FirstOrDefault(); + if (shank == null) + return INCORRECT_PARAMETERS_ERROR; + // Check if tool can be loaded + if (shank.ChildsTools.Count >= MAX_TOOLS_PER_MULTITOOL) + return MAX_TOOLS_PER_MULTITOOL_REACHED_ERROR; + + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + try + { + DataSvc dataSvc = new DataSvc(); + + int paramId = ((positionId - 1) * 6) + 5; + // Write parameter into multitool parameters + Item item = new Item() + { + Path = string.Format("/Tool/MTPlace/mtPlaceData[c{0},{1}]", shankId, paramId), + Value = toolId + }; + dataSvc.Write(item); + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError TOOLS_WUnloadToolFromShank(int shankId, int positionId) + { + return NO_ERROR; + + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + try + { + DataSvc dataSvc = new DataSvc(); + int paramId = ((positionId - 1) * 6) + 5; + // TC_MTP2 + Item item = new Item() + { + Path = string.Format("/Tool/MTPlace/mtPlaceData[c{0},{1}]", shankId, paramId), + Value = 0 + }; + dataSvc.Write(item); + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError TOOLS_WStartTDILoading(ushort magazineId, ushort positionId) + { + List words = new List() + { + (ushort)(((int)SIEMENS_TDI_ACTION.LOAD << 8) + positionId), + magazineId + }; + + CmsError cmsError = MEM_RWWordList(W, 1, BALLUF_ACTION_DATA.MemType, BALLUF_ACTION_DATA.Address, BALLUF_ACTION_DATA.SubAddress, 2, ref words); + if (cmsError.IsError()) + return cmsError; + + return PLC_WStrobe(BALLUF_ACTION_ACK, BALLUF_ACTION_STROBE, 1); + } + + public override CmsError TOOLS_WStartTDIUnloading(ushort magazineId, ushort positionId, ushort toolId) + { + var mountedTool = MagazineMountedTools.Where(x => x.ToolId == toolId).FirstOrDefault(); + if (mountedTool == null || (mountedTool.ToolId != toolId && mountedTool.PositionId != positionId)) + return INCORRECT_PARAMETERS_ERROR; + + List words = new List() + { + (ushort)(((int)SIEMENS_TDI_ACTION.UNLOAD << 8) + positionId), + magazineId, + toolId + }; + + CmsError cmsError = MEM_RWWordList(W, 1, BALLUF_ACTION_DATA.MemType, BALLUF_ACTION_DATA.Address, BALLUF_ACTION_DATA.SubAddress, 2, ref words); + if (cmsError.IsError()) + return cmsError; + + return PLC_WStrobe(BALLUF_ACTION_ACK, BALLUF_ACTION_STROBE, 1); + } + + public override CmsError TOOLS_WEmptyBallufTablet(SiemensToolModel tool) + { + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + // Setup status byte + BitArray bitArray = new BitArray(new bool[] { tool.IsActive, tool.IsEnabled, tool.IsInhibited, tool.IsMeasured, tool.PreAlarm, tool.InChangeTool, tool.InFixedPlace, tool.IsInUse }); + int[] statusArray = new int[1]; + bitArray.CopyTo(statusArray, 0); + + // Setup dimensions byte ( byte is formed by nibble => left_size right_size 0001 0001 ) + ushort dimensions = (ushort)((((tool.LeftSize << 4) + tool.RightSize) << 8) + 17); // 17 = 0001 0001 -> + DataSvc dataSvc = new DataSvc(); + // Main data + byte[] familyName = Encoding.ASCII.GetBytes(tool.FamilyName); + List items = new List { + new Item(){ Path = string.Format("DB{0}.DBB0", BALLUF_EMPTY_TABLE.Address), Value = tool.ChildId }, + new Item(){ Path = string.Format("DB{0}.DBB2[" + familyName.Length +"]", BALLUF_EMPTY_TABLE.Address), Value = familyName }, + new Item(){ Path = string.Format("DB{0}.DBW34", BALLUF_EMPTY_TABLE.Address), Value = dimensions }, + new Item(){ Path = string.Format("DB{0}.DBW36", BALLUF_EMPTY_TABLE.Address), Value = tool.MagazinePositionType }, + new Item(){ Path = string.Format("DB{0}.DBW38", BALLUF_EMPTY_TABLE.Address), Value = statusArray[0] }, + new Item(){ Path = string.Format("DB{0}.DBW40", BALLUF_EMPTY_TABLE.Address), Value = (int)tool.LifeType }, + new Item(){ Path = string.Format("DB{0}.DBD42", BALLUF_EMPTY_TABLE.Address), Value = tool.MaxSpeed }, + new Item(){ Path = string.Format("DB{0}.DBD46", BALLUF_EMPTY_TABLE.Address), Value = tool.Load }, + new Item(){ Path = string.Format("DB{0}.DBD50", BALLUF_EMPTY_TABLE.Address), Value = tool.Gamma }, + new Item(){ Path = string.Format("DB{0}.DBD54", BALLUF_EMPTY_TABLE.Address), Value = tool.MaxLoadPctAutoload }, + new Item(){ Path = string.Format("DB{0}.DBD58", BALLUF_EMPTY_TABLE.Address), Value = tool.MinLoadPctAutoload }, + new Item(){ Path = string.Format("DB{0}.DBD62", BALLUF_EMPTY_TABLE.Address), Value = tool.ToolTypeCode }, + //new Item(){ Path = string.Format("DB{0}.DBB64:STRING", BALLUF_EMPTY_TABLE.Address), Value = tool.FamilyName }, + + new Item(){ Path = string.Format("DB{0}.DBW70", BALLUF_EMPTY_TABLE.Address), Value = 1 }, + + // Edge data + new Item(){ Path = string.Format("DB{0}.DBW86", BALLUF_EMPTY_TABLE.Address), Value = tool.ToolType }, + new Item(){ Path = string.Format("DB{0}.DBW88", BALLUF_EMPTY_TABLE.Address), Value = 9 }, + }; + + EdgeModel edge = tool.EdgesData[0]; + + SiemensEdgesConfiguration toolEdgesConfig = new SiemensEdgesConfiguration(); + // Get config for current tool type + List toolTypeConfig = toolEdgesConfig.EdgesConfig[tool.ToolType]; + // Set edge additional params, read by configuration + foreach (EdgeConfigModel conf in toolTypeConfig) + { + if (edge.EdgeAdditionalParams.ContainsKey(conf.Name) && toolEdgesConfig.TDIEdgeFields.ContainsKey(conf.Path)) + { + items.Add(new Item() + { + Path = string.Format(toolEdgesConfig.TDIEdgeFields[conf.Path], BALLUF_EMPTY_TABLE.Address), + Value = edge.EdgeAdditionalParams[conf.Name] + }); + } + } + + // Life Parameters + switch (tool.LifeType) + { + case SIEMENS_LIFE_TYPE.TIME: + { + items.AddRange(new List() + { + new Item() { Path = string.Format("DB{0}.DBD186", BALLUF_EMPTY_TABLE.Address), Value = edge.ResidualLife }, // MOP2 + new Item() { Path = string.Format("DB{0}.DBD194", BALLUF_EMPTY_TABLE.Address), Value = edge.NominalLife }, // MOP11 + new Item() { Path = string.Format("DB{0}.DBD182", BALLUF_EMPTY_TABLE.Address), Value = edge.PreAlmLife } // MOP1 + }); + } + break; + + case SIEMENS_LIFE_TYPE.COUNT: + { + items.Add(new Item() { Path = string.Format("DB{0}.DBW192", BALLUF_EMPTY_TABLE.Address), Value = edge.ResidualLife }); // MOP4 + items.Add(new Item() { Path = string.Format("DB{0}.DBW198", BALLUF_EMPTY_TABLE.Address), Value = edge.NominalLife }); // MOP13 + items.Add(new Item() { Path = string.Format("DB{0}.DBW190", BALLUF_EMPTY_TABLE.Address), Value = edge.PreAlmLife }); // MOP3 + } + break; + + case SIEMENS_LIFE_TYPE.WEAR: + { + items.Add(new Item() { Path = string.Format("DB{0}.DBD204", BALLUF_EMPTY_TABLE.Address), Value = edge.ResidualLife }); // MOP6 + items.Add(new Item() { Path = string.Format("DB{0}.DBD208", BALLUF_EMPTY_TABLE.Address), Value = edge.NominalLife }); // MOP15 + items.Add(new Item() { Path = string.Format("DB{0}.DBD200", BALLUF_EMPTY_TABLE.Address), Value = edge.PreAlmLife }); // MOP5 + } + break; + } + + try + { + dataSvc.Write(items.ToArray()); + } + catch (Exception ex) + { + return ManageException(ex); + } + + return WBallufAction(SIEMENS_TDI_ACTION.ABORT); + } + + public override CmsError TOOLS_WAbortBallufTablet() + { + return WBallufAction(SIEMENS_TDI_ACTION.ABORT); + } + + private CmsError WBallufAction(SIEMENS_TDI_ACTION action) + { + byte act = (byte)action; + CmsError cmsError = MEM_RWByte(W, 1, BALLUF_ACTION_DATA.MemType, BALLUF_ACTION_DATA.Address, BALLUF_ACTION_DATA.SubAddress, 0, ref act); + if (cmsError.IsError()) + return cmsError; + + return PLC_WStrobe(BALLUF_ACTION_ACK, BALLUF_ACTION_STROBE, 1); + } + + #endregion Load/Unload functions + + public override CmsError TOOLS_RMagazinePositions(ref List positions) + { + positions = MagazinePositionsData; + return NO_ERROR; + } + + public override CmsError TOOLS_WUpdatePosition(PositionModel position) + { + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + try + { + DataSvc dataSvc = new DataSvc(); + int paramId = ((position.PositionId - 1) * 11) + 5; + // TC_MTP2 + Item item = new Item() + { + Path = string.Format("/Tool/Magazine/placeData[c{0} , {1}]", position.MagazineId, paramId) + }; + dataSvc.Read(item); + + item.Value = SetBitValue(Convert.ToInt32(item.Value), position.Disabled, 1); + dataSvc.Write(item); + } + catch (Exception ex) + { + return ManageException(ex); + } + + return NO_ERROR; + } + + public override CmsError TOOLS_RMountedTools(int magazineId, ref List magazinePos) + { + if (magazineId <= 0) + return INCORRECT_PARAMETERS_ERROR; + // Filter by magazine id + magazinePos = MagazineMountedTools + .Where(x => x.MagazineId == magazineId) + .ToList(); + + foreach (var pos in magazinePos) + { + var tool = GetToolOrMultitool(pos.ToolId); + if (tool is SiemensToolModel) + pos.ChildTool = tool as SiemensToolModel; + else if (tool is ShankModel) + pos.ChildShank = tool as ShankModel; + } + + return NO_ERROR; + } + + public override CmsError TOOLS_RAvailableTools(ref List multiTools, ref List tools) + { + List occupiedIds = new List(); + // Find ids of tools mounted in the magazines + foreach (var mounted in MagazineMountedTools) + { + var tmp = mounted as MountedToolModel; + + var tool = GetToolOrMultitool(tmp.ToolId); + + //if (tool is ShankModel) // If multitool + //{ + // occupiedIds.Add((tool as ShankModel).Id); // Add multitool id + //} else + if (tool is SiemensToolModel) // If tool + { + occupiedIds.Add((tool as SiemensToolModel).Id); + } + } + + //// Add tools mounted in multitools + //foreach (var multi in MultitoolsData) + //{ + // if (multi.ChildsTools.Count > 0) + // mountedIds.AddRange(multi.ChildsTools.Select(x => x.Id).ToList()); + //} + + // Filter tools + tools = ToolTableData + .Where(x => !occupiedIds.Contains(x.Id)) + .ToList(); + + //// Filter multitools + //multiTools = MultitoolsData + // .Where(x => !mountedIds.Contains(x.Id)) + // .ToList(); + + return NO_ERROR; + } + + private object GetToolOrMultitool(int toolId) + { + int toolIndex = ToolTableData.FindIndex(x => x.Id == toolId); + if (toolIndex >= 0) + { + return ToolTableData[toolIndex]; + } + //else + //{ + // int multiIndex = MultitoolsData.FindIndex(x => x.Id == toolId); + // if (multiIndex >= 0) + // return MultitoolsData[multiIndex]; + //} + + return null; + } + + public override CmsError TOOLS_RMagazineAction(ref MagazineActionModel magazineAction) + { + magazineAction = MagazineAction; + return NO_ERROR; + } + + #endregion Siemens Tool Management + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #region Nc Tool Manager + + public override CmsError TOOLS_RMagazineConfig(ref List config) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_WOptions(ToolManagerOptionsModel options) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_ROffset(short offsetId, ref OffsetModel offset) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_WOffset(short offsetId, ref OffsetModel offset) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_WStartEditData() + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_WStopEditData() + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_WUpdateTools(List list) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_WUpdateFamilies(List list) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_WUpdateShanks(List list) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_WUpdateMagazinePositions(List list) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_WStartEditTooling(int magazineId) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_WStopEditTooling(int magazineId) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_WRestoreBackup() + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_RUpdatedToolsData(ref Dictionary updatedStatus, ref Dictionary updatedLives) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_RStoredData(ref List tools, ref List families, ref List shanks) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_RMagazineBlock(ref List ids) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_WFreeMagazines() + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_RMagazineStatus(ref Dictionary magazineStatus) + { + return FUNCTION_NOT_ALLOWED_ERROR; + } + + public override CmsError TOOLS_RAdatpivePathStep(ref Byte step) + { + // Check ACK + CmsError cmsError = MEM_RWByte(R, 0, SELF_ADAPTIVE_PATH.MemType, SELF_ADAPTIVE_PATH.Address, SELF_ADAPTIVE_PATH.SubAddress, 0, ref step); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + public override CmsError TOOLS_WAdatpivePathStep(Byte step) + { + // Check ACK + CmsError cmsError = MEM_RWByte(W, 0, SELF_ADAPTIVE_PATH.MemType, SELF_ADAPTIVE_PATH.Address, SELF_ADAPTIVE_PATH.SubAddress, 0, ref step); + if (cmsError.IsError()) + return cmsError; + + return NO_ERROR; + } + + #endregion Nc Tool Manager + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #region Subordinate Private Functions + + private DataSvc HighPriorityDataSvc() + { + return new DataSvc() + { + PriorityFlag = SlPriority.highPriority, + Timeout = TimeoutConn + }; + } + + private DataSvc DefaultPriorityDataSvc() + { + return new DataSvc() + { + PriorityFlag = SlPriority.defaultPriority, + Timeout = TimeoutConn + }; + } + + private DataSvc LowPriorityDataSvc() + { + return new DataSvc() + { + PriorityFlag = SlPriority.lowPriority, + Timeout = TimeoutConn + }; + } + + // Manage the Alarms - Called automatically on changes + private void AlarmsChanged(Guid guid, Alarm[] alarms) + { + try + { + if (alarms != null) + SiemensAlarms = alarms.ToArray(); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + private void NcLanguageChanged(string language) + { + SiemensAlmSvc.UnSubscribe(AlarmsChanged); + // SiemensAlmSvc.Dispose(); + SiemensAlmSvc = new AlarmSvc(language); + SiemensAlmSvc.Subscribe(AlarmsChanged); + } + + private int SetBitValue(int intVal, bool val, int bitIndex) + { + if (val) + return intVal | (1 << (bitIndex - 1)); + else + return intVal & ~(1 << (bitIndex - 1)); + } + + //Manage the Mode + private PROC_MODE ConvertToSTEPMode(uint mode, uint JogMode, uint AdvMode) + { + if (mode == 0) + { + if (AdvMode == 0) + return (JogMode < 6) ? PROC_MODE.JOGINC : PROC_MODE.JOG; + else if (AdvMode == 1) + return PROC_MODE.RETPROF; + else if (AdvMode == 2) + return PROC_MODE.TEACH; + else if (AdvMode == 3) + return PROC_MODE.REF; + } + else if (mode == 1) + return PROC_MODE.MDI; + else if (mode == 2) + return PROC_MODE.AUTO; + + return PROC_MODE.ERROR; + } + + //Manage the Status + private PROC_STATUS ConvertToSTEPStatus(uint status) + { + switch (status) + { + case 0: return PROC_STATUS.IDLE; + case 1: return PROC_STATUS.RUN; + case 2: return PROC_STATUS.HOLD; + } + return PROC_STATUS.ERROR; + } + + //Check Bit In Range + private CmsError CheckBitRange(int bitnum) + { + if (bitnum < 0 || bitnum > 7) + return BIT_NOT_IN_RANGE_ERROR; + + return NO_ERROR; + } + + // Check if Memory Area is corrected + private CmsError ConvertMemToPath(MEMORY_TYPE MemoryType, int Address, int SubAddress, int SubBit, int Qty, char MemAccess, out string item) + { + char[] allowedAccess = { 'X', 'B', 'W', 'D' }; + + //Check if is the right area and allowed type + if (!MemoryType.ToString().StartsWith(SIEMENS_MEMTYPE) || !allowedAccess.Contains(MemAccess) || Qty < 1) + { + item = ""; + return INCORRECT_PARAMETERS_ERROR; + } + else + { + //If is Bit Access change access type + if (MemAccess == 'X') + item = "DB" + Address + ".DB" + MemAccess + SubAddress + "." + SubBit; + else + item = "DB" + Address + ".DB" + MemAccess + SubAddress + "[" + Qty + "]"; + + return NO_ERROR; + } + } + + // Check if NC is connected + private CmsError CheckConnection() + { + if (!NC_IsConnected()) + return NOT_CONNECTED_ERROR; + + return NO_ERROR; + } + + /// + /// Check if PLC is responding to Ping + /// + /// + private CmsError CheckS7Ping() + { + + // faccio ping... + if(testPing() != IPStatus.Success) + return PLC_IP_NOT_FOUND_ERROR; + return NO_ERROR; + } + + + /// + /// Ping test to configured Ip address + /// + /// + private IPStatus testPing() + { + IPStatus answ = IPStatus.Unknown; ; + IPAddress address; + PingReply reply; + Ping pingSender = new Ping(); + address = IPAddress.Loopback; + IPAddress.TryParse(this.Ip, out address); + reply = pingSender.Send(address, 100); + answ = reply.Status; + return answ; + } + + //Manage the Exception Launch + private CmsError ManageException(Exception ex) + { + //Catch the Siemens exceptions + if (ex is OperateMissingOptionException && ex.Message.Contains(OptionHMINotRunning) || ex.Message.Contains("CORBA")) + { + Connected = false; + return SIEMENS_HMI_NOT_RUNNING_ERROR; + } + else if (ex is FileNotFoundException && ex.Message.Contains(HMIDllName)) + { + return SIEMENS_ENVIRONMENT_NOT_FOUND_ERROR; + } + else if (ex.Message.Contains(NcNotFound) || ex.Message.Contains(NcNotFound2) || ex.Message.Contains(NcNotFound3) || ex.Message.Contains("Read() failed:")) + { + Connected = false; + return NOT_CONNECTED_ERROR; + } + else if (ex.Message.Contains("m_pSlToolMngmntSvc")) + { + return SIEMENS_TOOL_TABLE_ERROR; + } + else + { + return CmsError.InternalError(ex.Message, ex); + } + } + + // Create and return CmsError object + private CmsError GetError(string message) + { + return CmsError.NcError(message); + } + + //Read Static Data + private CmsError ReadStaticNCData() + { + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + //Read oly one time every X seconds + if (DateTime.Now - Last_Static_Read > new TimeSpan(NC_MIN_SEC_READ_STATIC_DATA * TimeSpan.TicksPerSecond)) + { + //Try to get information + try + { + DataSvc ReadStaticData = DefaultPriorityDataSvc(); + Item ItemNcType = new Item(NC_TYPE_PATH); + Item ItemNcVersion = new Item(NC_VERSION_PATH); + Item ItemMaxChannelNo = new Item(MAX_CHANNEL_NO_PATH); + Item ItemConfChannelNo = new Item(CONF_CHANNEL_NO_PATH); + Item ItemLanguage = new Item(LANGUAGE_PATH); + Item ItemSerialNumber = new Item(SERIAL_NO_PATH); + Item ItemUnitOfMeasure = new Item(UNIT_OF_MEASURE); + cmsError = ConvertMemToPath(MATR_MACCH_SIEMENS.MemType, MATR_MACCH_SIEMENS.Address, MATR_MACCH_SIEMENS.SubAddress, 0, 1, 'W', out string itemString); + + if (cmsError.IsError()) + return cmsError; + Item ItemMachineNumber = new Item(itemString); + + //Read All Data + ReadStaticData.Read(ItemNcType); + ReadStaticData.Read(ItemNcVersion); + ReadStaticData.Read(ItemMaxChannelNo); + ReadStaticData.Read(ItemConfChannelNo); + ReadStaticData.Read(ItemLanguage); + ReadStaticData.Read(ItemSerialNumber); + ReadStaticData.Read(ItemMachineNumber); + ReadStaticData.Read(ItemUnitOfMeasure); + + //Setup variables + Cnc_name = GetName((uint)ItemNcType.Value); + Cnc_SftVersion = Regex.Replace(((double)ItemNcVersion.Value).ToString(), ".{2}", "$0.").TrimEnd('.'); ; + Cnc_SeriesNum = ((string)ItemSerialNumber.Value); + + MaxChannelNo = (uint)ItemMaxChannelNo.Value; + ConfChannelNo = (uint)ItemConfChannelNo.Value; + SiemensLanguage = (uint)ItemLanguage.Value; + Cms_MachNumber = ((uint)ItemMachineNumber.Value).ToString(); + UnitOfMeasure = (uint)ItemUnitOfMeasure.Value == 0 ? MILLIMETERS : INCHES; + + //Save NOW + Last_Static_Read = DateTime.Now; + } + catch (Exception ex) + { + return ManageException(ex); + } + } + + return NO_ERROR; + } + + // Convert the internal Name var in Readable STEP Name + private string GetName(uint value) + { + string name = "Siemens "; + switch (value) + { + case 0: name += "840D pl"; break; + case 1000: name += "FM-NC"; break; + case 2000: name += "810D pl"; break; + case 3000: name += "802S"; break; + case 4000: name += "802D pl"; break; + case 5000: name += "840Di pl"; break; + case 6000: name += "SOLUTIONLINE"; break; + case 10700: name += "840D sl"; break; + case 14000: name += "802D sl T/M - N/G - C/U"; break; + case 15000: name += "840Di sl"; break; + } + return name; + } + + //Convert to Step Language + private CultureInfo ConvertToSTEPLanguage(uint language) + { + switch (language) + { + case 1: return new CultureInfo("de"); + case 2: return new CultureInfo("fr"); + case 3: return new CultureInfo("en"); + case 4: return new CultureInfo("es"); + case 6: return new CultureInfo("it"); + case 7: return new CultureInfo("nl"); + case 8: return new CultureInfo("zh-CHS"); + case 9: return new CultureInfo("sv"); + case 18: return new CultureInfo("hu"); + case 19: return new CultureInfo("fi"); + case 26: return new CultureInfo("el"); + case 28: return new CultureInfo("cs"); + case 50: return new CultureInfo("pt-BR"); + case 53: return new CultureInfo("pl"); + case 55: return new CultureInfo("da"); + case 57: return new CultureInfo("ru"); + case 65: return new CultureInfo("hr-HR"); + case 68: return new CultureInfo("sk"); + case 69: return new CultureInfo("sl"); + case 72: return new CultureInfo("ro"); + case 75: return new CultureInfo("bg"); + case 80: return new CultureInfo("zh-CHT"); + case 85: return new CultureInfo("ko"); + case 87: return new CultureInfo("ja"); + case 89: return new CultureInfo("tr"); + case 122: return new CultureInfo("id"); + case 212: return new CultureInfo("th"); + case 213: return new CultureInfo("vi"); + case 230: return new CultureInfo("ms"); + default: return new CultureInfo("en"); + } + } + + //Convert to Step Language + private string ConvertToNCLanguage(CultureInfo language) + { + return language.ThreeLetterISOLanguageName; + } + + private int SwapIntEndianFormat(int value) + { + var b1 = (value >> 0) & 0xff; + var b2 = (value >> 8) & 0xff; + var b3 = (value >> 16) & 0xff; + var b4 = (value >> 24) & 0xff; + + return b1 << 24 | b2 << 16 | b3 << 8 | b4 << 0; + } + + private short SwapShortEndianFormat(short value) + { + var b1 = (value >> 0) & 0xff; + var b2 = (value >> 8) & 0xff; + + return (short)(b1 << 8 | b2 << 0); + } + + private ushort SwapShortEndianFormat(ushort value) + { + var b1 = (value >> 0) & 0xff; + var b2 = (value >> 8) & 0xff; + + return (ushort)(b1 << 8 | b2 << 0); + } + + private List ChangeIntListEndianess(List bigEndianvalues) + { + List littleEndianValues = new List(); + foreach (int value in bigEndianvalues) + { + var a = SwapIntEndianFormat(value); + littleEndianValues.Add(a); + } + + return littleEndianValues; + } + + private List ChangeUShortListEndianess(List bigEndianvalues) + { + List littleEndianValues = new List(); + foreach (ushort value in bigEndianvalues) + { + var a = SwapShortEndianFormat(value); + littleEndianValues.Add(a); + } + + return littleEndianValues; + } + + private bool PositionContainsTool(MountedToolModel mounted, int toolId) + { + if (mounted.ToolId == toolId) + return true; + //else + //{ + // // Check if tool is a multitool child + // foreach (var multi in MultitoolsData) + // { + // // Check childs id + // int index = multi.ChildsTools.FindIndex(x => x.Id == toolId); + // if (index >= 0) + // return true; + // } + //} + + return false; + } + + //private void CheckData(object obj, List config) + //{ + // foreach(PropertyInfo prop in obj.GetType().GetProperties()) + // { + // bool val = config.Where(x => x.Name == prop.Name).Select(x => x.); + // } + //} + + private string ConvertStepToSiemensScreen(SCREEN_PAGE page) + { + switch (page) + { + case SCREEN_PAGE.Siemens_Machine: return "AreaMachine"; + case SCREEN_PAGE.Siemens_Parameter: return "AreaParameter"; + case SCREEN_PAGE.Siemens_Program: return "AreaProgramEdit"; + case SCREEN_PAGE.Siemens_ProgramManager: return "AreaProgramManager"; + case SCREEN_PAGE.Siemens_Setup: return "AreaStartup"; + case SCREEN_PAGE.Siemens_Diagnostics: return "AreaDiagnosis"; + default: return ""; + } + } + + #endregion Subordinate Private Functions + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #region Siemens Tool private functions + + private string[] ReadToolTableFile() + { + // Create a configuration file + FileStream f = new FileStream(LOCALE_TOOL_FILE_PATH, FileMode.Create); + + // Read siemens configuration file + CmsError cmsError = FILES_RProgramToFile(NC_TOOL_FILE_PATH, f); + f.Close(); + + return File.ReadAllLines(LOCALE_TOOL_FILE_PATH); + } + + private void MagazinePositionEnabled_OnChange(Guid guid, Item[] items, DataSvcStatus[] status) + { + int i = 0; + // Parse each new item + foreach (Item item in items) + { + if (status[i].Ok) + { + // Get Ids + string[] ids = item.SymbolicName.Split('_'); + int magazineId = Convert.ToInt32(ids[0]); + int positionId = Convert.ToInt32(ids[1]); + + foreach (PositionModel pos in MagazinePositionsData) + { + // Find position + if (pos.PositionId == positionId && pos.MagazineId == magazineId) + { + // Set Value + pos.Disabled = GetBitValue(Convert.ToInt32(item.Value), 0); + } + } + } + + i++; + } + } + + private void MagazineAction_OnChange(Guid guid, Item item, DataSvcStatus status) + { + CmsError cmsError = NO_ERROR; + if (Connected == false) + NC_Connect(); + + List wordList = new List(); + cmsError = MEM_RWWordList(R, 0, MAGAZINE_ACTION.MemType, MAGAZINE_ACTION.Address, MAGAZINE_ACTION.SubAddress + 2, 6, ref wordList); + if (cmsError.IsError()) + { + MagazineAction = new MagazineActionModel() + { + Action = MAGAZINE_ACTIONS.NOT_READY, + Tool = null, + SecondTool = null, + OriginMagazine = 0, + OriginPosition = 0, + DestinationMagazine = 0, + DestinationPosition = 0 + }; + } + else + { + MagazineActionToolModel tool = null; + MagazineActionToolModel secondTool = null; + + // Get the first tool if exists + ushort toolId = wordList[0]; + if (toolId != 0) + tool = ToolTableData + .Where(x => x.Id == toolId) + .Select(x => new MagazineActionToolModel() + { + Id = x.Id, + IsMultitool = false, + Name = x.FamilyName, + ToolType = x.ToolType + }).FirstOrDefault(); + + // Get the second tool if exists + toolId = wordList[1]; + if (toolId != 0) + secondTool = ToolTableData + .Where(x => x.Id == toolId) + .Select(x => new MagazineActionToolModel() + { + Id = x.Id, + IsMultitool = false, + Name = x.FamilyName, + ToolType = x.ToolType + }).FirstOrDefault(); + + // Populate model with new data + MagazineAction = new MagazineActionModel() + { + Action = (MAGAZINE_ACTIONS)Convert.ToInt32(item.Value), + Tool = tool, + SecondTool = secondTool, + OriginMagazine = wordList[4], + OriginPosition = wordList[5], + DestinationMagazine = wordList[2], + DestinationPosition = wordList[3] + }; + } + } + + private void PopulateToolsTableFromFileStrings(string[] toolsStrings) + { + SiemensEdgesConfiguration toolEdgesConfig = new SiemensEdgesConfiguration(); + + int lastFirstId = 0; + int lastSecondId = 0; + int toolIndex = 0; + int edgeIndex = 0; + // int multitoolIndex = 0; + + // Foreach string + for (int i = 0; i < toolsStrings.Count(); i++) + { + string actualString = toolsStrings[i]; // Get actual string data + + GetIdsFromSiemensToolString(actualString, out int firstId, out int secondId); // find ids from current string + + if (firstId != 0) + { + // If tool is changed, change current index tool + if (lastFirstId != firstId) + { + toolIndex = ToolTableData.FindIndex(x => x.Id == firstId); + // multitoolIndex = MultitoolsData.FindIndex(x => x.Id == firstId); + } + + // Check if the key string has only 1 id + if (secondId == 0) + { + switch (GetStringUntilOrEmpty(actualString)) // Cut string until [ character + { + case "$TC_TP1": + { + ToolTableData.Add(new SiemensToolModel() + { + Id = firstId, + ChildId = Convert.ToInt32(actualString.Split('=').LastOrDefault()) + }); + // Update Index + toolIndex = ToolTableData.Count - 1; + } + break; + + case "$TC_TP2": + { + string familyName = actualString.Split('=').LastOrDefault().Replace("\"", ""); + ToolTableData[toolIndex].FamilyName = familyName; + // Add new family with new tool + AddOrUpdateFamilyChild(familyName); + } + break; + + case "$TC_TP3": + ToolTableData[toolIndex].LeftSize = Convert.ToByte(actualString.Split('=').LastOrDefault()); + break; + + case "$TC_TP4": + ToolTableData[toolIndex].RightSize = Convert.ToByte(actualString.Split('=').LastOrDefault()); + break; + + case "$TC_TP7": + ToolTableData[toolIndex].MagazinePositionType = Convert.ToInt32(actualString.Split('=').LastOrDefault()); + break; + + case "$TC_TP8": + { + // Get tool status and read each bit + int toolStatus = Convert.ToInt32(actualString.Split('=').LastOrDefault()); + + ToolTableData[toolIndex].IsActive = GetBitValue(toolStatus, 0); + ToolTableData[toolIndex].IsEnabled = GetBitValue(toolStatus, 1); + ToolTableData[toolIndex].IsInhibited = GetBitValue(toolStatus, 2); + ToolTableData[toolIndex].IsMeasured = GetBitValue(toolStatus, 3); + ToolTableData[toolIndex].PreAlarm = GetBitValue(toolStatus, 4); + ToolTableData[toolIndex].InChangeTool = GetBitValue(toolStatus, 5); + ToolTableData[toolIndex].InFixedPlace = GetBitValue(toolStatus, 6); + ToolTableData[toolIndex].IsInUse = GetBitValue(toolStatus, 7); + } + break; + + case "$TC_TP9": + ToolTableData[toolIndex].LifeType = (SIEMENS_LIFE_TYPE)Convert.ToInt32(actualString.Split('=').LastOrDefault()); + break; + + case "$TC_TP_MAX_VELO": + ToolTableData[toolIndex].MaxSpeed = Convert.ToDouble(actualString.Split('=').LastOrDefault(), numberFormat); + break; + + //case "$TC_TP_MAX_ACC": + // ToolTableData[toolIndex].MaxAcceleration = Convert.ToDouble(actualString.Split('=').LastOrDefault(), numberFormat); + // break; + // Custom CMS fields + case "$TC_TPC1": + ToolTableData[toolIndex].Load = Convert.ToInt32(actualString.Split('=').LastOrDefault(), numberFormat); + break; + + case "$TC_TPC2": + ToolTableData[toolIndex].Gamma = Convert.ToInt32(actualString.Split('=').LastOrDefault(), numberFormat); + break; + + case "$TC_TPC3": + ToolTableData[toolIndex].MaxLoadPctAutoload = Convert.ToInt32(actualString.Split('=').LastOrDefault(), numberFormat); + break; + + case "$TC_TPC4": + ToolTableData[toolIndex].MinLoadPctAutoload = Convert.ToInt32(actualString.Split('=').LastOrDefault(), numberFormat); + break; + + case "$TC_TPC5": + ToolTableData[toolIndex].ToolTypeCode = Convert.ToInt32(actualString.Split('=').LastOrDefault(), numberFormat); + break; + + //*SHANK FIX*case "$TC_MTPN": + // { + // // Insert new multitool + // MultitoolsData.Add(new ShankModel() + // { + // Id = firstId, + // MaxChilds = Convert.ToInt32(actualString.Split('=').LastOrDefault()) + // }); + // // Update Index + // multitoolIndex = MultitoolsData.Count - 1; + // } + // break; + + //case "$TC_MTP2": + // MultitoolsData[multitoolIndex].Name = actualString.Split('=').LastOrDefault().Replace("\"", ""); + // break; + + //case "$TC_MTP3": + // MultitoolsData[multitoolIndex].LeftSize = Convert.ToInt32(actualString.Split('=').LastOrDefault()); + // break; + + //case "$TC_MTP4": + // MultitoolsData[multitoolIndex].RightSize = Convert.ToInt32(actualString.Split('=').LastOrDefault()); + // break; + + //case "$TC_MTP7": + // MultitoolsData[multitoolIndex].MagazinePositionType = Convert.ToInt32(actualString.Split('=').LastOrDefault()); + // break; + + //case "$TC_MTP8": + // { + // // Get tool status + // byte toolStatus = Convert.ToByte(actualString.Split('=').LastOrDefault()); + + // MultitoolsData[multitoolIndex].IsEnabled = GetBitValue(toolStatus, 1); + // MultitoolsData[multitoolIndex].IsInhibited = GetBitValue(toolStatus, 2); + // MultitoolsData[multitoolIndex].InChangeTool = GetBitValue(toolStatus, 3); + // MultitoolsData[multitoolIndex].InFixedPlace = GetBitValue(toolStatus, 4); + // MultitoolsData[multitoolIndex].InUse = GetBitValue(toolStatus, 7); + // } + // break; + + case "$TC_MAP1": + { + // Magazine type + SiemensMagazineConfigModel mag = MagazineConfig.Where(x => x.Id == firstId).FirstOrDefault(); + if (mag == null) + { + bool active = true; + SIEMENS_MAGAZINE_TYPE type = (SIEMENS_MAGAZINE_TYPE)Convert.ToInt32(actualString.Split('=').LastOrDefault()); + if (type == SIEMENS_MAGAZINE_TYPE.MAGAZINE_LOADING_STATION || type == SIEMENS_MAGAZINE_TYPE.MAGAZINE_TOOL_BUFFER) + active = false; + + MagazineConfig.Add(new SiemensMagazineConfigModel() + { + Id = (short)firstId, + Type = (SIEMENS_MAGAZINE_TYPE)Convert.ToInt32(actualString.Split('=').LastOrDefault()), + LoadingIsActive = active + }); + } + else + mag.Type = (SIEMENS_MAGAZINE_TYPE)Convert.ToInt32(actualString.Split('=').LastOrDefault()); + } + break; + + case "$TC_MAP2": + { + // Magazine Name + SiemensMagazineConfigModel mag = MagazineConfig.Where(x => x.Id == firstId).FirstOrDefault(); + if (mag != null) + mag.Name = actualString.Split('=').LastOrDefault().Replace("\"", ""); + } + break; + + case "$TC_MAP7": + { + // Add max number of magazine positions + SiemensMagazineConfigModel mag = MagazineConfig.Where(x => x.Id == firstId).FirstOrDefault(); + if (mag != null) + mag.MaxPositions = Convert.ToInt32(actualString.Split('=').LastOrDefault()); + } + break; + } + } + else // If the key string has 2 ids ex: $TC_DP1[1,3] + { + // If secondId is changed, change current edge id + if (lastSecondId != secondId && toolIndex >= 0) + edgeIndex = ToolTableData[toolIndex].EdgesData.FindIndex(x => x.Id == secondId); + + switch (GetStringUntilOrEmpty(actualString)) + { + case "$TC_DP1": + { + if (secondId == 1) // Read tool type from first edge type + ToolTableData[toolIndex].ToolType = Convert.ToInt32(actualString.Split('=').LastOrDefault()); + // Add new edge + ToolTableData[toolIndex].EdgesData.Add(new EdgeModel() { Id = secondId }); + edgeIndex = ToolTableData[toolIndex].EdgesData.Count - 1; // Update Index + } + break; + + case "$TC_MOP1": + { + SiemensToolModel tool = ToolTableData[toolIndex]; + if (tool.LifeType == SIEMENS_LIFE_TYPE.TIME) + { + tool + .EdgesData[edgeIndex] + .PreAlmLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + case "$TC_MOP2": + { + SiemensToolModel tool = ToolTableData[toolIndex]; + if (tool.LifeType == SIEMENS_LIFE_TYPE.TIME) + { + ToolTableData[toolIndex] + .EdgesData[edgeIndex] + .ResidualLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + case "$TC_MOP11": + { + SiemensToolModel tool = ToolTableData[toolIndex]; + if (tool.LifeType == SIEMENS_LIFE_TYPE.TIME) + { + ToolTableData[toolIndex] + .EdgesData[edgeIndex] + .NominalLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + case "$TC_MOP3": + { + SiemensToolModel tool = ToolTableData[toolIndex]; + if (tool.LifeType == SIEMENS_LIFE_TYPE.COUNT) + { + ToolTableData[toolIndex] + .EdgesData[edgeIndex] + .PreAlmLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + case "$TC_MOP4": + { + SiemensToolModel tool = ToolTableData[toolIndex]; + if (tool.LifeType == SIEMENS_LIFE_TYPE.COUNT) + { + ToolTableData[toolIndex] + .EdgesData[edgeIndex] + .ResidualLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + case "$TC_MOP13": + { + SiemensToolModel tool = ToolTableData[toolIndex]; + if (tool.LifeType == SIEMENS_LIFE_TYPE.COUNT) + { + ToolTableData[toolIndex] + .EdgesData[edgeIndex] + .NominalLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + case "$TC_MOP6": + { + SiemensToolModel tool = ToolTableData[toolIndex]; + if (tool.LifeType == SIEMENS_LIFE_TYPE.WEAR) + { + tool + .EdgesData[edgeIndex] + .ResidualLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + case "$TC_MOP15": + { + SiemensToolModel tool = ToolTableData[toolIndex]; + if (tool.LifeType == SIEMENS_LIFE_TYPE.WEAR) + { + ToolTableData[toolIndex] + .EdgesData[edgeIndex] + .NominalLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + case "$TC_MOP5": + { + SiemensToolModel tool = ToolTableData[toolIndex]; + if (tool.LifeType == SIEMENS_LIFE_TYPE.WEAR) + { + ToolTableData[toolIndex] + .EdgesData[edgeIndex] + .PreAlmLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + //case "$TC_DP2": + case "$TC_DP3": + case "$TC_DP4": + case "$TC_DP5": + case "$TC_DP6": + case "$TC_DP7": + case "$TC_DP8": + case "$TC_DP9": + case "$TC_DP10": + case "$TC_DP11": + case "$TC_DP12": + case "$TC_DP13": + case "$TC_DP14": + case "$TC_DP15": + case "$TC_DP16": + case "$TC_DP17": + case "$TC_DP21": + case "$TC_DP22": + case "$TC_DP23": + case "$TC_DP24": + case "$TC_DPV": + case "$TC_DPV3": + case "$TC_DPV4": + case "$TC_DPV5": + case "$TC_DPNT": + { + SiemensToolModel tool = ToolTableData[toolIndex]; + //// Clear tool + //tool + // .EdgesData[edgeIndex] + // .EdgeAdditionalParams + // .Clear(); + // Get tool type additional parameters + if (toolEdgesConfig.EdgesConfig.ContainsKey(tool.ToolType)) + { + // Find if actual param exist for the tool type + List toolTypeConfig = toolEdgesConfig.EdgesConfig[tool.ToolType]; + EdgeConfigModel paramConfig = toolTypeConfig + .Where(x => x.Path == (GetStringUntilOrEmpty(actualString) + "[")) + .FirstOrDefault(); + + // If Exist + if (paramConfig != null) + { + // Add additional param + tool + .EdgesData[edgeIndex] + .EdgeAdditionalParams + .Add(paramConfig.Name, Convert.ToDouble(actualString.Split('=').LastOrDefault(), numberFormat)); + } + } + } + break; + + case "$TC_DP25": + { + SiemensToolModel tool = ToolTableData[toolIndex]; + // Sets tool value only with the first edge value + if (tool.EdgesData[edgeIndex].Id == 1) + { + // Get tool general information + var toolInfo = Convert.ToInt32(actualString.Split('=').LastOrDefault()); + + // Convert rotation data + ROTATION rotation = ROTATION.NONE; + if (GetBitValue(toolInfo, 8)) + rotation = ROTATION.CLOCKWHISE; + else if (GetBitValue(toolInfo, 9)) + rotation = ROTATION.COUNTERCLOCKWHISE; + // Set new data + + tool.Cooling1 = GetBitValue(toolInfo, 10); + tool.Cooling2 = GetBitValue(toolInfo, 11); + tool.Rotation = rotation; + } + } + break; + + case "$TC_MPP1": + { + MagazinePositionsData.Add(new PositionModel() + { + PositionId = secondId, + MagazineId = firstId, + PhysicalType = (POSITION_TYPE)Convert.ToInt32(actualString.Split('=').LastOrDefault()) + }); + } + break; + + case "$TC_MPP2": + { + int index = MagazinePositionsData.FindIndex(x => x.PositionId == secondId && x.MagazineId == firstId); + if (index >= 0) + MagazinePositionsData[index].Type = Convert.ToInt32(actualString.Split('=').LastOrDefault()); + //*SHANK FIX*MagazinePositionsData.Add(new PositionModel() + //{ + // PositionId = secondId, + // MagazineId = firstId, + // Type = Convert.ToInt32(actualString.Split('=').LastOrDefault()) + //}); + } + break; + + case "$TC_MPP4": + { + int index = MagazinePositionsData.FindIndex(x => x.PositionId == secondId && x.MagazineId == firstId); + if (index >= 0) + { + MagazinePositionsData[index].Disabled = GetBitValue(Convert.ToInt32(actualString.Split('=').LastOrDefault()), 0); + MagazinePositionsData[index].Occupied = GetBitValue(Convert.ToInt32(actualString.Split('=').LastOrDefault()), 2); + } + } + break; + + case "$TC_MPP6": + { + int toolId = Convert.ToInt32(actualString.Split('=').LastOrDefault()); + if (toolId != 0) + { + MoveToolInMagazineList(toolId, firstId, secondId); + } + } + break; + + //*SHANK FIX*case "$TC_MTPP6": + // { + // // Find tool by id + // int toolId = Convert.ToInt32(actualString.Split('=').LastOrDefault()); + // if (toolId != 0) + // { + // // Add new multitool child + // MultitoolsData[multitoolIndex].ChildsTools.Add(new ShankChildModel() + // { + // Id = toolId, + // MultitoolId = secondId + // }); + // } + // } + // break; + + case "$TC_MDP1": + { + // Add max number of magazine positions + SiemensMagazineConfigModel mag = MagazineConfig.Where(x => x.Id == firstId).FirstOrDefault(); + if (mag != null) + mag.LoadPosition = secondId; + } + break; + } + } + } + } + } + + private SiemensToolModel CreateToolFromId(int toolIdToGet, string[] toolsStrings) + { + SiemensEdgesConfiguration toolEdgesConfig = new SiemensEdgesConfiguration(); + SiemensToolModel outputTool = new SiemensToolModel(); + int lastSecondId = 0; + int edgeIndex = 0; + + // Foreach string + for (int i = 0; i < toolsStrings.Count(); i++) + { + string actualString = toolsStrings[i]; // Get actual string data + + GetIdsFromSiemensToolString(actualString, out int firstId, out int secondId); // find ids from current string + + if (firstId != 0 && firstId == toolIdToGet) + { + if (secondId == 0) + { + switch (GetStringUntilOrEmpty(actualString)) // Cut string until [ character + { + case "$TC_TP1": + { + outputTool = new SiemensToolModel() + { + Id = firstId, + ChildId = Convert.ToInt32(actualString.Split('=').LastOrDefault()) + }; + } + break; + + case "$TC_TP2": + { + string familyName = actualString.Split('=').LastOrDefault().Replace("\"", ""); + outputTool.FamilyName = familyName; + // Add new family with new tool + AddOrUpdateFamilyChild(familyName); + } + break; + + case "$TC_TP3": + outputTool.LeftSize = Convert.ToByte(actualString.Split('=').LastOrDefault()); + break; + + case "$TC_TP4": + outputTool.RightSize = Convert.ToByte(actualString.Split('=').LastOrDefault()); + break; + + case "$TC_TP7": + outputTool.MagazinePositionType = Convert.ToInt32(actualString.Split('=').LastOrDefault()); + break; + + case "$TC_TP8": + { + // Get tool status and read each bit + int toolStatus = Convert.ToInt32(actualString.Split('=').LastOrDefault()); + + outputTool.IsActive = GetBitValue(toolStatus, 0); + outputTool.IsEnabled = GetBitValue(toolStatus, 1); + outputTool.IsInhibited = GetBitValue(toolStatus, 2); + outputTool.IsMeasured = GetBitValue(toolStatus, 3); + outputTool.PreAlarm = GetBitValue(toolStatus, 4); + outputTool.InChangeTool = GetBitValue(toolStatus, 5); + outputTool.InFixedPlace = GetBitValue(toolStatus, 6); + outputTool.IsInUse = GetBitValue(toolStatus, 7); + } + break; + + case "$TC_TP9": + outputTool.LifeType = (SIEMENS_LIFE_TYPE)Convert.ToInt32(actualString.Split('=').LastOrDefault()); + break; + + case "$TC_TP_MAX_VELO": + outputTool.MaxSpeed = Convert.ToDouble(actualString.Split('=').LastOrDefault(), numberFormat); + break; + + //case "$TC_TP_MAX_ACC": + // outputTool.MaxAcceleration = Convert.ToDouble(actualString.Split('=').LastOrDefault(), numberFormat); + // break; + // Custom CMS fields + case "$TC_TPC1": + outputTool.Load = Convert.ToInt32(actualString.Split('=').LastOrDefault(), numberFormat); + break; + + case "$TC_TPC2": + outputTool.Gamma = Convert.ToInt32(actualString.Split('=').LastOrDefault(), numberFormat); + break; + + case "$TC_TPC3": + outputTool.MaxLoadPctAutoload = Convert.ToInt32(actualString.Split('=').LastOrDefault(), numberFormat); + break; + + case "$TC_TPC4": + outputTool.MinLoadPctAutoload = Convert.ToInt32(actualString.Split('=').LastOrDefault(), numberFormat); + break; + + case "$TC_TPC5": + outputTool.ToolTypeCode = Convert.ToInt32(actualString.Split('=').LastOrDefault(), numberFormat); + break; + } + } + else + { + // If secondId is changed, change current edge id + if (lastSecondId != secondId) + edgeIndex = outputTool.EdgesData.FindIndex(x => x.Id == secondId); + + switch (GetStringUntilOrEmpty(actualString)) + { + case "$TC_DP1": + { + if (secondId == 1) // Read tool type from first edge type + outputTool.ToolType = Convert.ToInt32(actualString.Split('=').LastOrDefault()); + // Add new edge + outputTool.EdgesData.Add(new EdgeModel() { Id = secondId }); + edgeIndex = outputTool.EdgesData.Count - 1; // Update Index + } + break; + + case "$TC_MOP1": + { + if (outputTool.LifeType == SIEMENS_LIFE_TYPE.TIME) + { + outputTool + .EdgesData[edgeIndex] + .PreAlmLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + case "$TC_MOP2": + { + if (outputTool.LifeType == SIEMENS_LIFE_TYPE.TIME) + { + outputTool + .EdgesData[edgeIndex] + .ResidualLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + case "$TC_MOP11": + { + if (outputTool.LifeType == SIEMENS_LIFE_TYPE.TIME) + { + outputTool + .EdgesData[edgeIndex] + .NominalLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + case "$TC_MOP3": + { + if (outputTool.LifeType == SIEMENS_LIFE_TYPE.COUNT) + { + outputTool + .EdgesData[edgeIndex] + .PreAlmLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + case "$TC_MOP4": + { + if (outputTool.LifeType == SIEMENS_LIFE_TYPE.COUNT) + { + outputTool + .EdgesData[edgeIndex] + .ResidualLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + case "$TC_MOP13": + { + if (outputTool.LifeType == SIEMENS_LIFE_TYPE.COUNT) + { + outputTool + .EdgesData[edgeIndex] + .NominalLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + case "$TC_MOP6": + { + if (outputTool.LifeType == SIEMENS_LIFE_TYPE.WEAR) + { + outputTool + .EdgesData[edgeIndex] + .ResidualLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + case "$TC_MOP15": + { + if (outputTool.LifeType == SIEMENS_LIFE_TYPE.WEAR) + { + outputTool + .EdgesData[edgeIndex] + .NominalLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + case "$TC_MOP5": + { + if (outputTool.LifeType == SIEMENS_LIFE_TYPE.WEAR) + { + outputTool + .EdgesData[edgeIndex] + .PreAlmLife = Convert.ToDouble(actualString.Split('=').LastOrDefault()); + } + } + break; + + //case "$TC_DP2": + case "$TC_DP3": + case "$TC_DP4": + case "$TC_DP5": + case "$TC_DP6": + case "$TC_DP7": + case "$TC_DP8": + case "$TC_DP9": + case "$TC_DP10": + case "$TC_DP11": + case "$TC_DP12": + case "$TC_DP13": + case "$TC_DP14": + case "$TC_DP15": + case "$TC_DP16": + case "$TC_DP17": + case "$TC_DP21": + case "$TC_DP22": + case "$TC_DP23": + case "$TC_DP24": + case "$TC_DPV": + case "$TC_DPV3": + case "$TC_DPV4": + case "$TC_DPV5": + case "$TC_DPNT": + { + //// Clear tool + //outputTool + // .EdgesData[edgeIndex] + // .EdgeAdditionalParams + // .Clear(); + // Get tool type additional parameters + if (toolEdgesConfig.EdgesConfig.ContainsKey(outputTool.ToolType)) + { + // Find if actual param exist for the tool type + List toolTypeConfig = toolEdgesConfig.EdgesConfig[outputTool.ToolType]; + EdgeConfigModel paramConfig = toolTypeConfig + .Where(x => x.Path == (GetStringUntilOrEmpty(actualString) + "[")) + .FirstOrDefault(); + + // If Exist + if (paramConfig != null) + { + // Add additional param + outputTool + .EdgesData[edgeIndex] + .EdgeAdditionalParams + .Add(paramConfig.Name, Convert.ToDouble(actualString.Split('=').LastOrDefault(), numberFormat)); + } + } + } + break; + + case "$TC_DP25": + { + // Sets tool values with first edge value + if (outputTool.EdgesData[edgeIndex].Id == 1) + { + // Get tool general information + var toolInfo = Convert.ToInt32(actualString.Split('=').LastOrDefault()); + + // Convert rotation data + ROTATION rotation = ROTATION.NONE; + if (GetBitValue(toolInfo, 8)) + rotation = ROTATION.CLOCKWHISE; + else if (GetBitValue(toolInfo, 9)) + rotation = ROTATION.COUNTERCLOCKWHISE; + // Set new data + + outputTool.Cooling1 = GetBitValue(toolInfo, 10); + outputTool.Cooling2 = GetBitValue(toolInfo, 11); + outputTool.Rotation = rotation; + } + } + break; + } + } + } + } + + return outputTool; + } + + private EdgeModel SetUpEdgeData(string[] toolsString, SIEMENS_LIFE_TYPE lifeType, int toolId, int edgeId) + { + EdgeModel edgeData = new EdgeModel + { + Id = edgeId + }; + + switch (lifeType) + { + case SIEMENS_LIFE_TYPE.TIME: + { + edgeData.ResidualLife = Convert.ToDouble(toolsString.FirstOrDefault(X => X.StartsWith("$TC_MOP2[" + toolId + "," + edgeId)).Split('=').LastOrDefault(), numberFormat); + edgeData.NominalLife = Convert.ToDouble(toolsString.FirstOrDefault(X => X.StartsWith("$TC_MOP11[" + toolId + "," + edgeId)).Split('=').LastOrDefault(), numberFormat); + edgeData.PreAlmLife = Convert.ToDouble(toolsString.FirstOrDefault(X => X.StartsWith("$TC_MOP1[" + toolId + "," + edgeId)).Split('=').LastOrDefault(), numberFormat); + } + break; + + case SIEMENS_LIFE_TYPE.COUNT: + { + edgeData.ResidualLife = Convert.ToDouble(toolsString.FirstOrDefault(X => X.StartsWith("$TC_MOP4[" + toolId + "," + edgeId)).Split('=').LastOrDefault(), numberFormat); + edgeData.NominalLife = Convert.ToDouble(toolsString.FirstOrDefault(X => X.StartsWith("$TC_MOP13[" + toolId + "," + edgeId)).Split('=').LastOrDefault(), numberFormat); + edgeData.PreAlmLife = Convert.ToDouble(toolsString.FirstOrDefault(X => X.StartsWith("$TC_MOP3[" + toolId + "," + edgeId)).Split('=').LastOrDefault(), numberFormat); + } + break; + + case SIEMENS_LIFE_TYPE.WEAR: + { + // TODO: Check params + edgeData.ResidualLife = Convert.ToDouble(toolsString.FirstOrDefault(X => X.StartsWith("$TC_MOP6[" + toolId + "," + edgeId)).Split('=').LastOrDefault(), numberFormat); + edgeData.NominalLife = Convert.ToDouble(toolsString.FirstOrDefault(X => X.StartsWith("$TC_MOP15[" + toolId + "," + edgeId)).Split('=').LastOrDefault(), numberFormat); + edgeData.PreAlmLife = Convert.ToDouble(toolsString.FirstOrDefault(X => X.StartsWith("$TC_MOP5[" + toolId + "," + edgeId)).Split('=').LastOrDefault(), numberFormat); + } + break; + } + + return edgeData; + } + + private void ToolMngmtSvcHandler(Guid guid, ToolInfo[] toolInfos) + { + for (int i = 0; i < toolInfos.Count(); i++) + { // Choose behavior based on the actions5 + ActionsHandler(toolInfos[i]); + } + } + + private void ActionsHandler(ToolInfo toolInfo) + { + switch (toolInfo.action) + { + case ToolAction.TOOL_DELETED: + { + // Find tool + SiemensToolModel tool = ToolTableData.FirstOrDefault(t => t.Id == toolInfo.tNo); + if (tool != null) + { + // Delete Families + SiemensToolModel sameFamilyTool = ToolTableData.FirstOrDefault(x => x.FamilyName == tool.FamilyName && x.Id != tool.Id); + if (sameFamilyTool == null) + { + FamiliesData.RemoveAll(x => x.Name == tool.FamilyName); + } + + // Dismount tool if is mounted in magazine + if (MagazineMountedTools.FirstOrDefault(x => x.ToolId == tool.Id) != null) + MoveToolInMagazineList(tool.Id, 0, 0); + + // Remove + ToolTableData.Remove(tool); + } + //*SHANK FIX* else if (MULTITOOL_OPTION_ACTIVE) + // { + // // if tool not exist, find into shanks + // ShankModel shank = MultitoolsData.FirstOrDefault(t => t.Id == toolInfo.tNo); + // if (shank != null) + // try + // { + // Item item = new Item(string.Format("/Tool/MT/multitoolMyPlace[u1, {0}]", toolInfo.tNo)); + // DataSvc dataSvc = new DataSvc(); + // dataSvc.Read(item); + // } + // catch (Exception ex) + // { + // MultitoolsData.Remove(shank); + // } + // } + } + break; + + case ToolAction.TOOL_CREATED: + { + string[] toolsStrings = ReadToolTableFile(); + + SiemensToolModel newTool = CreateToolFromId((int)toolInfo.tNo, toolsStrings); + + if (newTool != null) + { + ToolTableData.Add(newTool); + AddOrUpdateFamilyChild(newTool.FamilyName); + + // Read magazine id and position id from NC + DataSvc dataSvc = new DataSvc(); + Item[] item = new Item[] { + new Item(){ Path = string.Format("/Tool/Data/toolInMag[{0}]", (int)toolInfo.tNo) }, + new Item(){ Path = string.Format("/Tool/Data/toolInPlace[{0}]", toolInfo.tNo) } + }; + dataSvc.Read(item); + + int magazineId = Convert.ToInt32(item[0].Value); + int positionId = Convert.ToInt32(item[1].Value); + + if (magazineId != 0 && positionId != 0) + MoveToolInMagazineList(newTool.Id, magazineId, positionId); + } + //*SHANK FIX*else if (MULTITOOL_OPTION_ACTIVE) + //{ + // ShankModel newMultitool = CreateMultitoolFromId((int)toolInfo.tNo, toolsStrings); + // MultitoolsData.Add(newMultitool); + //} + } + break; + + case ToolAction.TOOL_DATA_CHANGED: + { + string[] toolsStrings = ReadToolTableFile(); + + // Find edited toolIndex + int toolIndex = ToolTableData.FindIndex(t => t.Id == toolInfo.tNo); + // If the id belongs to a tool + if (toolIndex != -1) + { + // Get tool new data + SiemensToolModel newTool = CreateToolFromId((int)toolInfo.tNo, toolsStrings); + + // *ASSISTED TOOLING FIX* + // After one reset in an assisted tooling procedure siemens send a "tool_data_changed" message + // Check if tool is not mounted and remove from magazine + + + // Read magazine id and position id from NC + DataSvc dataSvc = new DataSvc(); + Item[] item = new Item[] { + new Item(){ Path = string.Format("/Tool/Data/toolInMag[{0}]", (int)toolInfo.tNo) }, + new Item(){ Path = string.Format("/Tool/Data/toolInPlace[{0}]", toolInfo.tNo) } + }; + dataSvc.Read(item); + + int magazineId = Convert.ToInt32(item[0].Value); + int positionId = Convert.ToInt32(item[1].Value); + + MoveToolInMagazineList(newTool.Id, magazineId, positionId); + + // Replace the element + if (newTool != null) + ToolTableData[toolIndex] = newTool; + } + + //*SHANK FIX*else if (MULTITOOL_OPTION_ACTIVE) + //{ + // // Find if its a multitool + // int multitoolIndex = MultitoolsData.FindIndex(t => t.Id == toolInfo.tNo); + + // if (multitoolIndex != -1) + // { + // // Create model with new data + // ShankModel newShank = CreateMultitoolFromId((int)toolInfo.tNo, toolsStrings); + // // Replace element + // if (newShank != null) + // MultitoolsData[multitoolIndex] = newShank; + // } + // else + // { + // ShankModel newMultitool = CreateMultitoolFromId((int)toolInfo.tNo, toolsStrings); + // MultitoolsData.Add(newMultitool); + // } + //} + + Array.Clear(toolsStrings, 0, toolsStrings.Count()); + } + break; + + case ToolAction.TOOL_MOVED: + { + int magazineId = 0; + int positionId = 0; + + var tool = GetToolOrMultitool(Convert.ToInt32(toolInfo.tNo)); + if (tool is SiemensToolModel) + { + try + { + // Read magazine id and position id from NC + DataSvc dataSvc = new DataSvc(); + Item[] item = new Item[] { + new Item(){ Path = string.Format("/Tool/Data/toolInMag[{0}]", (int)toolInfo.tNo) }, + new Item(){ Path = string.Format("/Tool/Data/toolInPlace[{0}]", toolInfo.tNo) } + }; + dataSvc.Read(item); + + magazineId = Convert.ToInt32(item[0].Value); + positionId = Convert.ToInt32(item[1].Value); + + } + catch (Exception ex) + { + magazineId = 0; + positionId = 0; + } + } + + MoveToolInMagazineList((int)toolInfo.tNo, magazineId, positionId); + + // moved MULTITOOL handler, add when Siemens Library bugs have been fixed + //*SHANK FIX*catch (Exception ex) + //{ + // int shankIdx = MultitoolsData.FindIndex(x => x.Id == toolInfo.tNo); + // if (shankIdx < 0) + // { + // // Check that the move is inside a multitool + // item = new Item() { Path = string.Format("/Tool/Data/toolInMultitool[{0}]", toolInfo.tNo) }; + // dataSvc.Read(item); + // // Check if readed multitool id exists + // int mtIndex = MultitoolsData.FindIndex(x => x.Id == Convert.ToInt32(item.Value)); + // if (mtIndex >= 0) + // { + // int childIndex = MultitoolsData[mtIndex].ChildsTools.FindIndex(x => x.Id == toolInfo.tNo); + // if (childIndex < 0) + // { + // MultitoolsData[mtIndex].ChildsTools.Add(new ShankChildModel() + // { + // Id = Convert.ToInt32(toolInfo.tNo), + // MultitoolId = MultitoolsData[mtIndex].ChildsTools.Count + 1 // TODO ADD TOOL DATA OR REMOVE + // }); + // } + // } + // } + //} + } + break; + } + } + + private void MoveToolInMagazineList(int toolId, int magazineId, int positionId) + { + // If load magazine != 0, add new tool + if (magazineId != 0 && positionId != 0) + { + // Find tool by id + var tool = GetToolOrMultitool(toolId); + if (tool != null) + { + if (magazineId == 9998) + { + // Get old tool position + MountedToolModel toolMounted = MagazineMountedTools + .Where(x => x.ToolId == toolId) + .FirstOrDefault(); + + if (toolMounted != null) + { + // Set magazine position as occupied + var position = MagazinePositionsData.Where(x => + x.MagazineId == toolMounted.MagazineId + && x.PositionId == toolMounted.PositionId) + .FirstOrDefault(); + + if (position != null) + position.Occupied = true; + } + } + else + { + // Free a position + var position = MagazinePositionsData.Where(x => x.MagazineId == magazineId && x.PositionId == positionId).FirstOrDefault(); + if (position != null) + position.Occupied = false; + } + + // Remove tool from list + MagazineMountedTools.RemoveAll(mountTool => PositionContainsTool(mountTool, toolId)); + + // Find if position exist + MountedToolModel mounted = MagazineMountedTools + .Where(x => x.MagazineId == magazineId && x.PositionId == positionId) + .FirstOrDefault(); + + if (mounted != null) + return; + + // Add tool to list + MagazineMountedTools.Add(new MountedToolModel() + { + MagazineId = magazineId, + PositionId = positionId, + ToolId = toolId + }); + } + } + else + { + // Remove tool from list + MagazineMountedTools.RemoveAll(mountTool => PositionContainsTool(mountTool, toolId)); + } + } + + private int GetLastToolId() + { + Item item = new Item() + { + Path = "/Tool/Catalogue/TnumWZV" + }; + + DataSvc dataSvc = new DataSvc(); + dataSvc.Read(item); + + return Convert.ToInt32(item.Value); + + // First implementation before the path was found + //Get tool ids + //List toolIds = ToolTableData.Select(x => x.Id).ToList(); + //// Sort tools ids array + //toolIds.Sort((x, y) => x.CompareTo(y)); + + //if (toolIds.Count == 0) + // return 1; + + //for (int i = 0; i < toolIds.Count - 1; i++) + //{ + // // If next id is different than previus + 1, there is an empty space in the array of numbers + // if (toolIds[i] + 1 != toolIds[i + 1]) + // { + // // Check if the empty space is a multitool + // ShankModel shank = MultitoolsData.Where(x => x.Id == (toolIds[i] + 1)).FirstOrDefault(); + // if (shank == null) + // { + // // return new id + // return toolIds[i] + 1; + // } + // } + //} + //// If there isn't an empty space return max id + 1 + //return toolIds[toolIds.Count - 1] + 1; + } + + private int GetLastMultitoolId() + { + Item item = new Item() + { + Path = "/Tool/MTCatalogue/MTnumWZV" + }; + + DataSvc dataSvc = new DataSvc(); + dataSvc.Read(item); + + return Convert.ToInt32(item.Value); + } + + private int GetLastEdgeId(int toolId) + { + // Get edgeIds ids + List edgeIds = ToolTableData.Where(x => x.Id == toolId).FirstOrDefault()?.EdgesData.Select(x => x.Id).ToList(); + // Sort tools ids array + edgeIds.Sort((x, y) => x.CompareTo(y)); + + if (edgeIds.Count == 0) + return 1; + + for (int i = 0; i < edgeIds.Count - 1; i++) + { + // If next id is different than previus + 1, there is an empty space in the array of numbers + if (edgeIds[i] + 1 != edgeIds[i + 1]) + { + // return new id + return edgeIds[i] + 1; + } + } + + // If there isn't an empty space return max id + 1 + return edgeIds[edgeIds.Count - 1] + 1; + } + + private void AddOrUpdateFamilyChild(string familyName) + { + // Find family + int familyIndex = FamiliesData.FindIndex(x => x.Name == familyName); + if (familyIndex < 0) + { + // Create family and add child + FamiliesData.Add(new FamilyModel() + { + Name = familyName + }); + } + } + + private static void GetIdsFromSiemensToolString(string text, out int toolId, out int edgeId) + { + toolId = 0; + edgeId = 0; + + if (!string.IsNullOrWhiteSpace(text)) + { + // Get indexes from string + int startingData = text.IndexOf("[", StringComparison.Ordinal) + 1; + int secondData = text.IndexOf(",", StringComparison.Ordinal) + 1; + int endingData = text.IndexOf("]", StringComparison.Ordinal); + // If the string is matching with the pattern STRING[N]=N or STRING[N,M]=N + if (startingData > 0 && endingData > 0) + // STRING[N,M]=N case + if (secondData > 0) + { + toolId = Convert.ToInt32(text.Substring(startingData, secondData - (startingData + 1))); + edgeId = Convert.ToInt32(text.Substring(secondData, endingData - (secondData))); + } + else // STRING[N]=N case + { + toolId = Convert.ToInt32(text.Substring(startingData, endingData - (startingData))); + edgeId = 0; + } + } + } + + #endregion Siemens Tool private functions + + #region Multitool Private region + + private void MultitoolsNumber_OnChange(Guid guid, Item item, DataSvcStatus status) + { + // Check if an element has been deleted + if ((uint)item.Value < multitoolsNumber) + { + // for each saved multitool + for (int i = 0; i < MultitoolsData.Count; i++) + { + try + { + // Check if exists + Item toolData = new Item(string.Format("/Tool/MT/multitoolMyPlace[u1, {0}]", MultitoolsData[i].Id)); + DataSvc dataSvc = new DataSvc(); + dataSvc.Read(toolData); + } + catch (Exception) + { + // Remove from list + MultitoolsData.RemoveAt(i); + } + } + } + // Update multitool counter + multitoolsNumber = (uint)item.Value; + } + + private int ToolIsInMultitool(int toolId) + { + // Loop through multitools + //foreach (ShankModel multi in MultitoolsData) + //{ + // if (multi.ChildsTools.Count() > 0) + // { + // // Find tool id in multitool childs + // int childIndex = multi.ChildsTools.FindIndex(x => x.Id == toolId); + // if (childIndex >= 0) + // return multi.Id; + // } + //} + + return 0; + } + + private CmsError CheckMultitoolData(ref ShankModel shank, bool isUpdate) + { + //Check if the NC is Connected + CmsError cmsError = CheckConnection(); + if (cmsError.IsError()) + return cmsError; + + // Truncate name + if (shank.Name.Count() > 32) + shank.Name = shank.Name.Substring(0, 32); + + int totalNumberOfChilds = 0; + foreach (ShankModel multi in MultitoolsData) + { + if (shank.Name == multi.Name && shank.Id != multi.Id) + return INCORRECT_PARAMETERS_ERROR; + // Calculate max number of childs + totalNumberOfChilds += multi.MaxChilds; + } + + // Check if there are enough locations + if (!isUpdate && totalNumberOfChilds + MAX_TOOLS_PER_MULTITOOL > MAX_MULTITOOLS_LOCATIONS) + return MAX_MULTITOOL_LOCATION_REACHED_ERROR; + + return NO_ERROR; + } + + private ShankModel CreateMultitoolFromId(int multitoolId, string[] toolsStrings) + { + SiemensEdgesConfiguration toolEdgesConfig = new SiemensEdgesConfiguration(); + + // Find tool status status + var toolStatusByte = toolsStrings.FirstOrDefault(X => X.StartsWith("$TC_MTP8[" + multitoolId)); + if (toolStatusByte == null) + return null; + + int toolStatus = Convert.ToInt32(toolStatusByte.Split('=').LastOrDefault()); + + // Find shank, in order to get childs + ShankModel oldShank = MultitoolsData.Where(x => x.Id == multitoolId).FirstOrDefault(); + + // Create shank model + ShankModel shank = new ShankModel() + { + Id = multitoolId, + Name = toolsStrings.FirstOrDefault(x => x.Contains("$TC_MTP2[" + multitoolId)).Split('=').LastOrDefault().Replace("\"", ""), + LeftSize = Convert.ToByte(toolsStrings.FirstOrDefault(X => X.StartsWith("$TC_MTP3[" + multitoolId)).Split('=').LastOrDefault()), + RightSize = Convert.ToByte(toolsStrings.FirstOrDefault(X => X.StartsWith("$TC_MTP4[" + multitoolId)).Split('=').LastOrDefault()), + MagazinePositionType = Convert.ToByte(toolsStrings.FirstOrDefault(x => x.StartsWith("$TC_MTP7[" + multitoolId)).Split('=').LastOrDefault()), + MaxChilds = Convert.ToInt32(toolsStrings.FirstOrDefault(x => x.StartsWith("$TC_MTPN[" + multitoolId)).Split('=').LastOrDefault()), + IsEnabled = GetBitValue(toolStatus, 1), + IsInhibited = GetBitValue(toolStatus, 2), + InChangeTool = GetBitValue(toolStatus, 5), + InFixedPlace = GetBitValue(toolStatus, 6), + InUse = GetBitValue(toolStatus, 7), + ChildsTools = new List() + }; + + // Populate shank childs + for (int i = 1; i <= MAX_TOOLS_PER_MULTITOOL; i++) + { + // Find if position exists + var multitoolPos = toolsStrings.FirstOrDefault(x => x.Contains("$TC_MTPP6[" + multitoolId + "," + i)); + if (multitoolPos != null) + { + // If not empty + int toolId = Convert.ToInt32(multitoolPos.Split('=').LastOrDefault()); + if (toolId != 0) + { + shank.ChildsTools.Add(new ShankChildModel() + { + Id = toolId, + MultitoolId = i + }); + } + } + } + + // Check position in magazine + // Read magazine id from memory + DataSvc dataSvc = new DataSvc(); + Item item = new Item() { Path = string.Format("/Tool/MT/multitoolInMag[{0}]", multitoolId) }; + // Read magazine position + dataSvc.Read(item); + int magazineId = Convert.ToInt32(item.Value); + item = new Item() { Path = string.Format("/Tool/MT/multitoolInPlace[{0}]", multitoolId) }; + dataSvc.Read(item); + int positionId = Convert.ToInt32(item.Value); + + MoveToolInMagazineList(multitoolId, magazineId, positionId); + + return shank; + } + + #endregion Multitool Private region + } + + internal static class MEMORY_ADDRESS + { + // aree Parametri + + // aree Moduli + + // riscaldi superiori + + // riscaldi inferiori + + // produzione + + // ciclo produzione + + + internal const int TABLE = 258; + + internal static MEMORY_CELL NC_WATCHDOG = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 0, 1); + internal static MEMORY_CELL ACTIVE_WATCHDOG = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2, 1); + + internal static MEMORY_CELL ACTIVE_CLIENT = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 4, 1); + + internal static MEMORY_CELL FUNCTION_ACCESS = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 6, 8); + + internal static MEMORY_CELL PRE_POST_POWER_ON = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2574, 2); + internal static MEMORY_CELL PRE_POST_POWER_ON_CLICKABLE = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2576, 2); + internal static MEMORY_CELL PRE_POST_POWER_ON_ACK = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2578, 2); + internal static MEMORY_CELL PRE_POST_POWER_ON_CLICKED = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2580, 2); + + internal static MEMORY_CELL AXIS_RESET_PROCEDURE = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2608, 1); + + internal static MEMORY_CELL PROCESS_STATUS = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2582, 24); + internal static MEMORY_CELL SELECTED_PROCESS = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2582, 24); + internal static MEMORY_CELL SELECT_PROCESS = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2606, 1); + + internal static MEMORY_CELL COUNTERS = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 0, 40); + + internal static MEMORY_CELL SELECTED_AXIS = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2626, 1); + internal static MEMORY_CELL SELECT_AXIS = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2627, 1); + + internal static MEMORY_CELL NC_SOFTKEYS_VALUE = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2610, 4); + internal static MEMORY_CELL NC_SOFTKEYS_CLICKABLE = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2614, 4); + internal static MEMORY_CELL NC_SOFT_KEYS_ACK = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2618, 4); + internal static MEMORY_CELL NC_SOFT_KEYS_CLICKED = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2622, 4); + + internal static MEMORY_CELL USER_SOFTKEYS_VALUE = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2628, 16); + internal static MEMORY_CELL USER_SOFTKEYS_CLICKABLE = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2644, 16); + internal static MEMORY_CELL USER_SOFT_KEYS_ACK = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2660, 16); + internal static MEMORY_CELL USER_SOFT_KEYS_CLICKED = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2676, 16); + + internal static MEMORY_CELL ALARMS_STATUS = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 14, 128); + internal static MEMORY_CELL ALARMS_DATA = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 142, 1024); + + internal static MEMORY_CELL ALARM_ACK = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2190, 128); + internal static MEMORY_CELL ALARM_RESTORATION_STROBE = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2318, 128); + internal static MEMORY_CELL ALARM_REFRESH_STROBE = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2446, 128); + + internal static MEMORY_CELL HEADS_DATA = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2692, 240); + + internal static MEMORY_CELL HEADS_ACK = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2932, 4); + internal static MEMORY_CELL HEADS_STROBE_INCREMENT = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2936, 4); + internal static MEMORY_CELL HEADS_STROBE_DECREMENT = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2940, 4); + + internal static MEMORY_CELL COUNTERS_DATA = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 2944, 64); + internal static MEMORY_CELL COUNTER_IS_RESETTABLE = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 3008, 2); + internal static MEMORY_CELL COUNTER_IS_RESETTABLE_ACK = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 3010, 2); + internal static MEMORY_CELL COUNTER_IS_RESETTABLE_STROBE = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 3012, 2); + + internal static MEMORY_CELL M155_INPUT_NEEDED = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 3014, 1); + internal static MEMORY_CELL M155_INPUT_ACK = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 3015, 1); + internal static MEMORY_CELL M155_INPUT_STROBE = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 3016, 1); + + internal static MEMORY_CELL M156_INPUT_NEEDED = new MEMORY_CELL(MEMORY_TYPE.Osai_MW, 4333, 1); + internal static MEMORY_CELL M156_INPUT_ACK = new MEMORY_CELL(MEMORY_TYPE.Osai_MW, 4335, 1); + internal static MEMORY_CELL M156_INPUT_STROBE = new MEMORY_CELL(MEMORY_TYPE.Osai_MW, 4337, 1); + internal static MEMORY_CELL M156_INPUT_ID_LIST = new MEMORY_CELL(MEMORY_TYPE.Osai_MW, 4339, 8); + + internal static MEMORY_CELL M154_ACK = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 3042, 1); + internal static MEMORY_CELL M154_STROBE = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 3043, 1); + internal static MEMORY_CELL M154_SWITCH_ONOFF = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 0, 2); + + internal static MEMORY_CELL AXES_BUTTON_VISIBLE = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 3044, 16); + + internal static MEMORY_CELL MAGAZINE_ACTION = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 4000, 16); + + internal static MEMORY_CELL BALLUF_ACTION_ACK = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 4014, 1); + internal static MEMORY_CELL BALLUF_ACTION_STROBE = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 4015, 1); + internal static MEMORY_CELL BALLUF_ACTION_DATA = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, TABLE, 4016, 1); + + //old CMS-Control variables + internal static MEMORY_CELL HEADS_WORKED_TIMES = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, 254, 60, 4); + internal static MEMORY_CELL HEAD_RESET_WORKED_TIME = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, 255, 92, 4); + internal static MEMORY_CELL MACHINE_WORKED_TIME = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, 255, 94, 4); + internal static MEMORY_CELL MACHINE_RESET_WORKED_TIME = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, 255, 98, 4); + internal static MEMORY_CELL CANDY_MEM = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, 255, 130, 1); + internal static MEMORY_CELL EXP_CANDY_MEM = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, 255, 92, 1); + + + internal static MEMORY_CELL SELF_ADAPTIVE_PATH = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, 253, 16, 4); + + internal static MEMORY_CELL BALLUF_EMPTY_TABLE = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, 111, 0, 486); + + // Machine number + internal static MEMORY_CELL MATR_MACCH_SIEMENS = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, 255, 0, 1); + internal static MEMORY_CELL NEW_MATR_MACC = new MEMORY_CELL(MEMORY_TYPE.Siemens_DB, 258, 3060, 4); + } +} \ No newline at end of file