public static void Create(IEnumerable <IBlock> blocks, string path, PortalPlc owningPlc)
        {
            if (blocks == null)
            {
                throw new ArgumentNullException(nameof(blocks));
            }
            IEnumerable <DataBlock> dataBlocks;

            if ((dataBlocks = blocks.OfType <DataBlock>())?.Count() <= 0)
            {
                throw new ArgumentException("Blocks does not contain any valid DataBlocks.", nameof(blocks));
            }

            KepwareConfiguration.CreateInternal(dataBlocks, path, owningPlc);
        }
        public static void Create(IEnumerable <IBlock> blocks, string path, PortalPlc parentPlc, WinccExportType exportType, TiaPortalVersion portalVersion)
        {
            if (blocks == null)
            {
                throw new ArgumentNullException(nameof(blocks));
            }
            IEnumerable <DataBlock> dataBlocks;

            if ((dataBlocks = blocks.OfType <DataBlock>())?.Count() <= 0)
            {
                throw new ArgumentException("Blocks does not contain any valid DataBlocks.", nameof(blocks));
            }

            WinccConfiguration.CreateInternal(dataBlocks, path, parentPlc, exportType, portalVersion);
        }
        public static void Create(IEnumerable <IBlock> blocks, string path, PortalPlc parentPlc, AlarmworxSettings settings)
        {
            if (blocks == null)
            {
                throw new ArgumentNullException(nameof(blocks));
            }
            IEnumerable <DataBlock> dataBlocks;

            if ((dataBlocks = blocks.OfType <DataBlock>())?.Count() <= 0)
            {
                throw new ArgumentException("Blocks does not contain any valid DataBlocks.", nameof(blocks));
            }

            AlarmWorxConfiguration.CreateInternal(dataBlocks, path, parentPlc, settings);
        }
Example #4
0
        public static void ResolveArrayChildren(DataEntry entry, PortalPlc parentPlc)
        {
            if (entry.DataType != DataType.ARRAY)
            {
                return;
            }

            var arrayStart = parentPlc?.GetConstantValue(entry.ArrayStartIndex) ?? entry.ArrayStartIndex.Value;
            var arrayEnd   = parentPlc?.GetConstantValue(entry.ArrayEndIndex) ?? entry.ArrayEndIndex.Value;

            _ = entry.ArrayDataEntry.CalculateSize(parentPlc);
            entry.Children = new LinkedList <DataEntry>();

            // First populate the array Children with the correct number and type of children
            for (var i = arrayStart; i <= arrayEnd; i++)
            {
                entry.Children.AddLast(new DataEntry(entry.Name + $"[{i}]", entry.ArrayDataEntry.DataType, entry.Comment + $" ({i})", entry.ArrayDataEntry.Children,
                                                     entry.ArrayDataEntry.DataTypeName, entry.ArrayDataEntry.StringLength));
            }

            // re-calculate the addresses of the children
            entry.CalcluateAddresses(parentPlc);
        }
        private static void CreateInternal(IEnumerable <DataBlock> dataBlocks, string path, string opcServerPrefix, PortalPlc parentPlc)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }
            if (!FileHelpers.IsValidFilePath(path, ".csv"))
            {
                throw new ArgumentException(path + " is not a valid path.", nameof(path));
            }

            try
            {
                using (var file = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.Read))
                    using (var writer = new StreamWriter(file))
                    {
                        AlarmWorxConfiguration.WriteHeaders(writer);

                        foreach (var block in dataBlocks)
                        {
                            if (block == null)
                            {
                                throw new ArgumentNullException(nameof(block));
                            }
                            if (block.Children?.Count <= 0)
                            {
                                throw new ArgumentException("Block '" + block.Name + "' contains no data", nameof(block));
                            }

                            foreach (var child in block)
                            {
                                WriteAlarmRow(writer, child, block.Name + ".", block.Comment);
                            }
                        }
                        AlarmWorxConfiguration.WriteFooter(writer);

                        writer.Flush();
                    }
            }
            catch (Exception e)
            {
                throw new SiemensException("Could not write AlarmWorX configuration", e);
            }

            void WriteAlarmRow(StreamWriter writer, DataEntry entry, string prependNameText, string prependCommentText)
            {
                string stackedComment;

                if (string.IsNullOrWhiteSpace(prependCommentText))
                {
                    stackedComment = entry.Comment.Replace(",", "-");
                }
                else if (prependCommentText.EndsWith(" - "))
                {
                    stackedComment = prependCommentText + entry.Comment;
                }
                else
                {
                    stackedComment = prependCommentText + " - " + entry.Comment;
                }

                switch (entry.DataType)
                {
                case DataType.ARRAY:
                    TagHelper.ResolveArrayChildren(entry, parentPlc);
                    foreach (var child in entry.Children)
                    {
                        WriteAlarmRow(writer, child, prependNameText, prependNameText);
                    }
                    break;

                case DataType.STRUCT:
                    foreach (var child in entry.Children)
                    {
                        WriteAlarmRow(writer, child, prependNameText + entry.Name + ".", stackedComment);
                    }
                    break;

                case DataType.UDT:
                    foreach (var child in parentPlc.UserDataTypes.FirstOrDefault(u => u.Name == entry.DataTypeName))
                    {
                        WriteAlarmRow(writer, child, prependNameText + entry.Name + ".", stackedComment);
                    }
                    break;

                case DataType.BOOL:
                    var row = new AlarmWorxRow
                    {
                        LocationPath   = @"\\Alarm Configurations\" + ALARM_FOLDER,
                        Name           = ALARM_FOLDER + "." + prependNameText + entry.Name,
                        Description    = stackedComment,
                        LastModified   = DateTime.Now.ToString(),
                        Input1         = opcServerPrefix + "\\" + prependNameText + entry.Name,
                        BaseText       = stackedComment, // Message text
                        DigMessageText = " ",            // Prevents 'Digital Alarm' text at the end of each message
                        DigLimit       = "1",            // Alarm state value needs to be 1 for a digital
                        DigSeverity    = "500",          // Default severity is 500
                        DigRequiresAck = "1"             // Require an acknowledge by default
                    };

                    writer.WriteLine(row.ToString());
                    break;

                default:
                    throw new ArgumentException("Cannot export datatype: " + entry.DataType.ToString() + " to AlarmWorX configuration");
                }
            }
        }
 public static void Create(DataBlock block, string path, string opcServerPrefix, PortalPlc parentPlc)
 {
     AlarmWorxConfiguration.Create(new[] { block }, path, opcServerPrefix, parentPlc);
 }
        private static void CreateInternal(IEnumerable <DataBlock> dataBlocks, string path, PortalPlc parentPlc, WinccExportType exportType, TiaPortalVersion portalVersion)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }
            if (!FileHelpers.IsValidFilePath(path, ".xlsx"))
            {
                throw new ArgumentException(path + " is not a valid path.", nameof(path));
            }

            var    currentAlarmRow = 2;
            var    currentTagRow   = 2;
            string dataBlockName;
            var    proTags = new List <string>();

            using (var document = new ExcelPackage())
            {
                var tagWorksheet   = document.Workbook.Worksheets.Add(TagWorksheetName);
                var alarmWorksheet = document.Workbook.Worksheets.Add(AlarmWorksheetName);

                WinccConfiguration.WriteXlsxHeaders(document.Workbook, exportType, portalVersion);

                foreach (var db in dataBlocks)
                {
                    dataBlockName = db.Name;
                    db.CalcluateAddresses(parentPlc);

                    foreach (var entry in db.Children)
                    {
                        ProcessDataEntry(alarmWorksheet, entry, string.Empty, new Address(), db.Name);
                    }

                    if (exportType != WinccExportType.Professional)
                    {
                        WriteComfortAdvancedTagRow(tagWorksheet, db, "HMI_Connection_1");
                    }
                }

                if (exportType == WinccExportType.Professional)
                {
                    foreach (var tag in proTags)
                    {
                        WriteProfessionalTagRow(tagWorksheet, tag, "HMI_Connection_1");
                    }
                }

                using (Stream file = new FileStream(path, FileMode.Create))
                {
                    document.SaveAs(file);
                }
            }

            void ProcessDataEntry(ExcelWorksheet worksheet, DataEntry entry, string prependText, Address addressOffset, string prependTag = "")
            {
                string stackedComment;

                if (string.IsNullOrWhiteSpace(prependText))
                {
                    stackedComment = entry.Comment;
                }
                else if (prependText.EndsWith(" - "))
                {
                    stackedComment = prependText + entry.Comment;
                }
                else
                {
                    stackedComment = prependText + " - " + entry.Comment;
                }

                string stackedTag;

                if (string.IsNullOrWhiteSpace(prependTag))
                {
                    stackedTag = entry.Name;
                }
                else if (prependText.EndsWith("."))
                {
                    stackedTag = prependTag + entry.Name;
                }
                else
                {
                    stackedTag = prependTag + "." + entry.Name;
                }

                switch (entry.DataType)
                {
                case DataType.BOOL:
                    var alarmNumber = currentAlarmRow - 1;

                    var row = WinccConstants.GetAlarmRow(exportType, portalVersion);
                    row[WinccExportField.Id]        = alarmNumber.ToString();
                    row[WinccExportField.Name]      = $"Discrete_alarm_{alarmNumber}";
                    row[WinccExportField.AlarmText] = stackedComment;
                    row[WinccExportField.InfoText]  = stackedComment;

                    if (exportType == WinccExportType.Professional)
                    {
                        row[WinccExportField.TriggerTag] = stackedTag.Replace('.', '_');

                        proTags.Add(stackedTag);
                    }
                    else                             // WinCC Comfort/Advanced
                    {
                        row[WinccExportField.TriggerTag] = dataBlockName;
                        row[WinccExportField.TriggerBit] = AddressToTriggerBit(addressOffset + entry.Address.Value).ToString();
                    }

                    var column = 1;
                    foreach (var item in row)
                    {
                        worksheet.Cells[currentAlarmRow, column].Style.Numberformat.Format = "@";
                        worksheet.Cells[currentAlarmRow, column++].Value = item;
                    }

                    currentAlarmRow++;
                    break;

                case DataType.UDT:
                case DataType.STRUCT:
                    entry.CalcluateAddresses(parentPlc);
                    foreach (var newEntry in entry.Children)
                    {
                        ProcessDataEntry(worksheet, newEntry, stackedComment, addressOffset + entry.Address.Value, stackedTag);
                    }
                    break;

                case DataType.ARRAY:
                    TagHelper.ResolveArrayChildren(entry, parentPlc);

                    // write a new entry for each of the children
                    foreach (var child in entry.Children)
                    {
                        ProcessDataEntry(worksheet, child, prependText, entry.Address.Value + addressOffset, stackedTag);
                    }
                    break;

                default:
                    throw new SiemensException("Unsupported data type for WinCC alarms: " + entry.Name + ", " + entry.DataType.ToString());
                }
            }

            void WriteComfortAdvancedTagRow(ExcelWorksheet worksheet, DataBlock dataBlock, string connectionName)
            {
                string dataType, address;

                var dbLength = dataBlock.CalculateSize(parentPlc).Byte;

                var wordLength = (int)Math.Ceiling(dbLength / 2.0);

                if (dbLength > 2)
                {
                    dataType = $"Array [0..{wordLength - 1}] of Word";
                    address  = $"%DB{dataBlock.Number}.DBX0.0";
                }
                else
                {
                    dataType   = "Word";
                    address    = $"%DB{dataBlock.Number}.DBW0";
                    wordLength = 0;
                }

                var row = WinccConstants.GetTagRow(exportType, portalVersion);

                row[WinccExportField.Name]       = dataBlock.Name;
                row[WinccExportField.Connection] = connectionName;
                row[WinccExportField.DataType]   = dataType;
                row[WinccExportField.Length]     = ((wordLength + 1) * 2).ToString();
                row[WinccExportField.Address]    = address;

                var column = 1;

                foreach (var item in row)
                {
                    worksheet.Cells[currentTagRow, column].Style.Numberformat.Format = "@";
                    worksheet.Cells[currentTagRow, column++].Value = item;
                }

                currentTagRow++;
            }

            void WriteProfessionalTagRow(ExcelWorksheet worksheet, string tag, string connectionName)
            {
                var row = WinccConstants.GetTagRow(exportType, portalVersion);

                row[WinccExportField.Name]       = tag.Replace('.', '_');
                row[WinccExportField.Connection] = connectionName;
                row[WinccExportField.PlcTag]     = tag;

                var column = 1;

                foreach (var item in row)
                {
                    worksheet.Cells[currentTagRow, column].Style.Numberformat.Format = "@";
                    worksheet.Cells[currentTagRow, column++].Value = item;
                }

                currentTagRow++;
            }

            int AddressToTriggerBit(Address address)
            {
                if (address.Byte % 2 == 0)
                {
                    return((address.Byte + 1) * 8 + address.Bit);
                }
                else
                {
                    return((address.Byte - 1) * 8 + address.Bit);
                }
            }
        }
 public static void Create(IBlock block, string path, PortalPlc parentPlc, WinccExportType exportType, TiaPortalVersion portalVersion)
 {
     WinccConfiguration.Create(new[] { block }, path, parentPlc, exportType, portalVersion);
 }
        private static void ExportDataBlockToFile(DataBlock block, TextWriter writer, PortalPlc parentPlc)
        {
            block.CalcluateAddresses(parentPlc);
            foreach (var entry in block)
            {
                AddDataEntry(entry, block.Name + ".", new Address());
            }

            void AddDataEntry(DataEntry entry, string entryPrefix, Address parentOffset)
            {
                var addressPrefix = "";
                var type          = "";

                switch (entry.DataType)
                {
                case DataType.ARRAY:
                    TagHelper.ResolveArrayChildren(entry, parentPlc);

                    // write a new entry for each of the children
                    foreach (var child in entry.Children)
                    {
                        AddDataEntry(child, entryPrefix, entry.Address.Value + parentOffset);
                    }
                    break;

                case DataType.BOOL:
                    addressPrefix = "DBX";
                    type          = "Boolean";
                    break;

                case DataType.BYTE:
                    addressPrefix = "DBB";
                    type          = "Byte";
                    break;

                case DataType.CHAR:
                    addressPrefix = "DBB";
                    type          = "Char";
                    break;

                case DataType.DATE:
                case DataType.DATE_AND_TIME:
                    addressPrefix = "DATE";
                    type          = "Date";
                    break;

                case DataType.TIME:
                case DataType.DINT:
                    addressPrefix = "DBD";
                    type          = "Long";
                    break;

                case DataType.DWORD:
                    addressPrefix = "DBD";
                    type          = "Dword";
                    break;

                case DataType.INT:
                    addressPrefix = "DBW";
                    type          = "Short";
                    break;

                case DataType.REAL:
                    addressPrefix = "DBD";
                    type          = "Float";
                    break;

                case DataType.STRING:
                    addressPrefix = "STRING";
                    type          = "String";
                    break;

                case DataType.UDT:
                case DataType.STRUCT:
                    entry.CalcluateAddresses(parentPlc);
                    foreach (var child in entry)
                    {
                        AddDataEntry(child, entryPrefix + entry.Name + ".", entry.Address.Value + parentOffset);
                    }
                    break;

                case DataType.WORD:
                    addressPrefix = "DBW";
                    type          = "Word";
                    break;

                default:
                    throw new SiemensException("Data type: '" + entry.DataType.ToString() + "' not supported.");
                }

                if (TagHelper.IsPrimitive(entry.DataType))
                {
                    var absoluteAddress = parentOffset + entry.Address.Value;

                    var addressString = "DB" + block.Number + "." + addressPrefix + absoluteAddress.Byte;
                    if (entry.DataType == DataType.BOOL)
                    {
                        addressString += "." + absoluteAddress.Bit;
                    }
                    else if (entry.DataType == DataType.STRING)
                    {
                        addressString += "." + (parentPlc?.GetConstantValue(entry.StringLength) ?? entry.StringLength.Value).ToString();
                    }

                    var entryItems = new string[16]
                    {
                        entryPrefix + entry.Name,
                        addressString,
                        type,
                        "1",
                        "R/W",
                        "100",
                        string.Empty,
                        string.Empty,
                        string.Empty,
                        string.Empty,
                        string.Empty,
                        string.Empty,
                        string.Empty,
                        string.Empty,
                        string.Empty,
                        entry.Comment
                    };

                    writer.WriteLine(string.Join(",", entryItems));
                }
            }
        }
        private static void CreateInternal(IEnumerable <DataBlock> blocks, string path, PortalPlc parentPlc)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }
            if (!FileHelpers.IsValidFilePath(path, ".csv"))
            {
                throw new ArgumentException(path + " is not a valid path.", nameof(path));
            }

            try
            {
                using (var file = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.Read))
                {
                    var writer = new StreamWriter(file);

                    KepwareConfiguration.WriteHeaders(writer);

                    foreach (var block in blocks)
                    {
                        if (block == null)
                        {
                            throw new ArgumentNullException(nameof(block));
                        }
                        if (block.Children?.Count <= 0)
                        {
                            throw new ArgumentException("Block '" + block.Name + "' contains no data", nameof(block));
                        }

                        KepwareConfiguration.ExportDataBlockToFile(block, writer, parentPlc);
                    }

                    writer.Flush();
                }
            }
            catch (Exception e)
            {
                throw new SiemensException("Could not write Kepware configuration", e);
            }
        }
 public static void Create(DataBlock block, string path, PortalPlc owningPlc)
 {
     KepwareConfiguration.CreateInternal(new[] { block }, path, owningPlc);
 }
 public static void Create(DataBlock block, string path, PortalPlc parentPlc, AlarmworxSettings settings)
 {
     AlarmWorxConfiguration.Create(new[] { block }, path, parentPlc, settings);
 }