Exemple #1
0
        /// <summary>
        /// Обновить сигналы КП элементов групп, начиная с заданного узла дерева
        /// </summary>
        private void UpdateSignals(TreeNode startGrNode)
        {
            // проверка корректности заданного узла дерева
            if (!(startGrNode.Tag is ElemGroup))
            {
                return;
            }

            // определение начального индекса тегов КП
            TreeNode  prevGrNode    = startGrNode.PrevNode;
            ElemGroup prevElemGroup = prevGrNode == null ? null : prevGrNode.Tag as ElemGroup;
            int       tagInd        = prevElemGroup == null ? 0 : prevElemGroup.StartKPTagInd + prevElemGroup.Elems.Count;

            // обновление групп и их элементов
            int grNodeCnt = grsNode.Nodes.Count;

            for (int i = startGrNode.Index; i < grNodeCnt; i++)
            {
                TreeNode  grNode    = grsNode.Nodes[i];
                ElemGroup elemGroup = grNode.Tag as ElemGroup;
                int       elemSig   = tagInd + 1;
                elemGroup.StartKPTagInd = tagInd;
                tagInd += elemGroup.Elems.Count;

                foreach (TreeNode elemNode in grNode.Nodes)
                {
                    ElemInfo elem = elemNode.Tag as ElemInfo;
                    elem.Signal = elemSig++;
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Отобразить свойства группы элементов
        /// </summary>
        private void ShowElemGroupProps(ElemGroup elemGroup)
        {
            numGrAddress.Value       = 1;
            numGrAddress.Minimum     = AddrShift;
            numGrAddress.Maximum     = ushort.MaxValue + AddrShift;
            numGrAddress.Hexadecimal = !DecAddr;
            ShowFuncCode(elemGroup);

            if (elemGroup == null)
            {
                chkGrActive.Checked         = false;
                txtGrName.Text              = "";
                cbGrTableType.SelectedIndex = 0;
                numGrAddress.Value          = AddrShift;
                lblGrAddressHint.Text       = "";
                numGrElemCnt.Value          = 1;
                gbElemGroup.Enabled         = false;
            }
            else
            {
                chkGrActive.Checked         = elemGroup.Active;
                txtGrName.Text              = elemGroup.Name;
                cbGrTableType.SelectedIndex = (int)elemGroup.TableType;
                numGrAddress.Value          = elemGroup.Address + AddrShift;
                lblGrAddressHint.Text       = string.Format(KpPhrases.AddressHint, AddrNotation, AddrShift);
                numGrElemCnt.Value          = 1;
                numGrElemCnt.Maximum        = elemGroup.MaxElemCnt;
                numGrElemCnt.Value          = elemGroup.Elems.Count;
                gbElemGroup.Enabled         = true;
            }
        }
Exemple #3
0
        /// <summary>
        /// Создать узел группы элементов
        /// </summary>
        private TreeNode NewElemGroupNode(ElemGroup elemGroup)
        {
            string   name   = elemGroup.Name == "" ? KpPhrases.DefGrName : elemGroup.Name;
            TreeNode grNode = new TreeNode(name + " (" + ModbusUtils.GetTableTypeName(elemGroup.TableType) + ")");

            grNode.ImageKey = grNode.SelectedImageKey = elemGroup.Active ? "group.png" : "group_inactive.png";
            grNode.Tag      = elemGroup;

            ushort elemAddr = elemGroup.Address;
            int    elemSig  = elemGroup.StartKPTagInd + 1;

            foreach (Elem elem in elemGroup.Elems)
            {
                ElemInfo elemInfo = new ElemInfo()
                {
                    Elem      = elem,
                    ElemGroup = elemGroup,
                    Settings  = template.Sett,
                    Address   = elemAddr,
                    Signal    = elemSig++
                };

                grNode.Nodes.Add(NewElemNode(elemInfo));
                elemAddr += (ushort)elem.Quantity;
            }

            return(grNode);
        }
Exemple #4
0
        /// <summary>
        /// Обновить узлы элементов выбранной группы
        /// </summary>
        private void UpdateElemNodes(TreeNode grNode = null)
        {
            treeView.BeginUpdate();

            if (grNode == null)
            {
                grNode = selNode;
            }

            if (grNode.Tag is ElemGroup)
            {
                ElemGroup elemGroup = (ElemGroup)grNode.Tag;
                ushort    elemAddr  = elemGroup.Address;
                int       elemSig   = elemGroup.StartKPTagInd + 1;

                foreach (TreeNode elemNode in grNode.Nodes)
                {
                    ElemInfo elemInfo = elemNode.Tag as ElemInfo;
                    elemInfo.Address = elemAddr;
                    elemInfo.Signal  = elemSig++;
                    elemNode.Text    = elemInfo.Caption;
                    elemAddr        += (ushort)elemInfo.Elem.Length;
                }
            }

            treeView.EndUpdate();
        }
Exemple #5
0
        private void btnDelete_Click(object sender, EventArgs e)
        {
            if (selElemGroup != null)
            {
                // удаление группы элементов
                template.ElemGroups.Remove(selElemGroup);
                grsNode.Nodes.Remove(selNode);
            }
            else if (selElemInfo != null)
            {
                // удаление элемента
                ElemGroup elemGroup = selElemInfo.ElemGroup;
                elemGroup.Elems.Remove(selElemInfo.Elem);
                TreeNode grNode = selNode.Parent;
                grsNode.Nodes.Remove(selNode);

                UpdateElemNodes(grNode);
                UpdateSignals(grNode);
                ShowElemProps(selElemInfo);
            }
            else if (selCmd != null)
            {
                // удаление команды
                template.Cmds.Remove(selCmd);
                cmdsNode.Nodes.Remove(selNode);
            }

            // установка признака изменения
            Modified = true;
        }
Exemple #6
0
 /// <summary>
 /// Установить значения тегов КП в соответствии со значениями элементов группы
 /// </summary>
 private void SetTagsData(ElemGroup elemGroup)
 {
     for (int i = 0, j = elemGroup.StartKPTagInd + i, cnt = elemGroup.Elems.Count; i < cnt; i++, j++)
     {
         SetCurData(j, elemGroup.GetElemVal(i), BaseValues.CnlStatuses.Defined);
     }
 }
Exemple #7
0
 /// <summary>
 /// Sets the data of the element group tags.
 /// </summary>
 private void SetTagData(ElemGroup elemGroup)
 {
     for (int elemIdx = 0, tagIdx = elemGroup.StartTagIdx + elemIdx, cnt = elemGroup.Elems.Count;
          elemIdx < cnt; elemIdx++, tagIdx++)
     {
         DeviceData.Set(tagIdx, elemGroup.GetElemVal(elemIdx));
     }
 }
Exemple #8
0
 /// <summary>
 /// Отобразить свойства группы элементов
 /// </summary>
 private void ShowElemGroupProps(ElemGroup elemGroup)
 {
     ctrlElemGroup.Visible   = true;
     ctrlElemGroup.Settings  = template.Sett;
     ctrlElemGroup.ElemGroup = elemGroup;
     ctrlElem.Visible        = false;
     ctrlCmd.Visible         = false;
 }
Exemple #9
0
        /// <summary>
        /// Установить значения тегов КП в соответствии со значениями элементов группы
        /// </summary>
        private void SetTagsData(ElemGroup elemGroup)
        {
            int len = elemGroup.ElemVals.Length;

            for (int i = 0, j = elemGroup.StartKPTagInd + i; i < len; i++, j++)
            {
                SetCurData(j, elemGroup.GetElemVal(i), BaseValues.CnlStatuses.Defined);
            }
        }
Exemple #10
0
        private void btnMoveDown_Click(object sender, EventArgs e)
        {
            // перемещение объекта вниз
            TreeNode nextNode = selNode.NextNode;
            int      nextInd  = nextNode.Index;

            if (selElemGroup != null)
            {
                // перемещение группы элементов вниз
                ElemGroup nextElemGroup = nextNode.Tag as ElemGroup;

                template.ElemGroups.RemoveAt(nextInd);
                template.ElemGroups.Insert(nextInd - 1, nextElemGroup);

                grsNode.Nodes.RemoveAt(nextInd);
                grsNode.Nodes.Insert(nextInd - 1, nextNode);

                UpdateSignals(nextNode);
            }
            else if (selElemInfo != null)
            {
                // перемещение элемента вниз
                ElemInfo nextElemInfo = nextNode.Tag as ElemInfo;

                selElemInfo.ElemGroup.Elems.RemoveAt(nextInd);
                selElemInfo.ElemGroup.Elems.Insert(nextInd - 1, nextElemInfo.Elem);

                TreeNode grNode = selNode.Parent;
                grNode.Nodes.RemoveAt(nextInd);
                grNode.Nodes.Insert(nextInd - 1, nextNode);

                UpdateElemNodes(grNode);
                ShowElemProps(selElemInfo);
            }
            else if (selCmd != null)
            {
                // перемещение команды вниз
                ModbusCmd nextCmd = nextNode.Tag as ModbusCmd;

                template.Cmds.RemoveAt(nextInd);
                template.Cmds.Insert(nextInd - 1, nextCmd);

                cmdsNode.Nodes.RemoveAt(nextInd);
                cmdsNode.Nodes.Insert(nextInd - 1, nextNode);
            }

            // установка доступности кнопок
            btnMoveUp.Enabled   = selNode.PrevNode != null;
            btnMoveDown.Enabled = selNode.NextNode != null;

            // установка признака изменения
            Modified = true;
        }
Exemple #11
0
        private TreeNode cmdsNode;               // узел дерева "Команды"


        /// <summary>
        /// Конструктор, ограничивающий создание формы без параметров
        /// </summary>
        private FrmDevTemplate()
        {
            InitializeComponent();

            appDirs         = null;
            initialFileName = "";
            fileName        = "";
            saveOnly        = false;

            template     = null;
            modified     = false;
            selElemGroup = null;
            selElemInfo  = null;
            selCmd       = null;
            selNode      = null;
            grsNode      = treeView.Nodes["grsNode"];
            cmdsNode     = treeView.Nodes["cmdsNode"];
        }
Exemple #12
0
        private void treeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            // отображение выбранного объекта и его свойств
            selNode = e.Node;
            object tag = selNode.Tag;

            selElemGroup = tag as ElemGroup;
            selElemInfo  = tag as ElemInfo;
            selCmd       = tag as ModbusCmd;

            if (selElemGroup != null)
            {
                ShowElemGroupProps(selElemGroup);
            }
            else if (selElemInfo != null)
            {
                ShowElemProps(selElemInfo);
            }
            else if (selCmd != null)
            {
                ShowCmdProps(selCmd);
            }
            else if (selNode == grsNode)
            {
                ShowElemGroupProps(null);
            }
            else if (selNode == cmdsNode)
            {
                ShowCmdProps(null);
            }
            else // не выполняется
            {
                DisableProps();
            }

            // установка доступности кнопок
            btnAddElem.Enabled = selElemGroup != null || selElemInfo != null;
            bool nodeIsOk = selElemGroup != null || selCmd != null ||
                            selElemInfo != null && selElemInfo.ElemGroup.Elems.Count > 1 /*последний не удалять*/;

            btnMoveUp.Enabled   = nodeIsOk && selNode.PrevNode != null;
            btnMoveDown.Enabled = nodeIsOk && selNode.NextNode != null;
            btnDelete.Enabled   = nodeIsOk;
        }
Exemple #13
0
        private void btnAddElemGroup_Click(object sender, EventArgs e)
        {
            // создание группы элементов и добавление в шаблон устройства
            ElemGroup elemGroup = template.CreateElemGroup(TableType.DiscreteInputs);

            elemGroup.Elems.Add(elemGroup.CreateElem());
            int ind = selNode != null && selNode.Tag is ElemGroup ? selNode.Index + 1 : template.ElemGroups.Count;

            template.ElemGroups.Insert(ind, elemGroup);

            // создание узла дерева группы элементов
            TreeNode grNode = NewElemGroupNode(elemGroup);

            grsNode.Nodes.Insert(ind, grNode);
            UpdateSignals(grNode);
            grNode.Expand();
            treeView.SelectedNode = grNode;
            ctrlElemGroup.SetFocus();

            // установка признака изменения
            Modified = true;
        }
Exemple #14
0
        private void btnAddElem_Click(object sender, EventArgs e)
        {
            // создание элемента и добавление в шаблон устройства
            ElemGroup elemGroup  = selElemGroup == null ? selElemInfo.ElemGroup : selElemGroup;
            int       maxElemCnt = DataUnit.GetMaxElemCnt(elemGroup.TableType);

            if (elemGroup.Elems.Count >= maxElemCnt)
            {
                MessageBox.Show(string.Format(KpPhrases.ElemCntExceeded, maxElemCnt),
                                CommonPhrases.WarningCaption, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            ElemInfo elemInfo = new ElemInfo();

            elemInfo.Elem = new Elem()
            {
                ElemType = elemGroup.DefElemType
            };
            elemInfo.ElemGroup = elemGroup;
            elemInfo.Settings  = template.Sett;
            int ind = selNode.Tag is ElemInfo ? selNode.Index + 1 : elemGroup.Elems.Count;

            elemGroup.Elems.Insert(ind, elemInfo.Elem);

            // создание узла дерева элемента
            TreeNode elemNode = NewElemNode(elemInfo);
            TreeNode grNode   = selNode.Tag is ElemInfo ? selNode.Parent : selNode;

            grNode.Nodes.Insert(ind, elemNode);
            UpdateElemNodes(grNode);
            UpdateSignals(grNode);
            treeView.SelectedNode = elemNode;
            ctrlElem.SetFocus();

            // установка признака изменения
            Modified = true;
        }
Exemple #15
0
        /// <summary>
        /// Заполнить дерево в соответствии с шаблоном устройства
        /// </summary>
        private void FillTree()
        {
            // обнуление выбранных объектов и снятие признака изменения
            selElemGroup = null;
            selElemInfo  = null;
            selCmd       = null;
            selNode      = null;
            ShowElemGroupProps(null);
            Modified = false;

            // приостановка отрисовки дерева
            treeView.BeginUpdate();

            // очистка дерева
            grsNode.Nodes.Clear();
            cmdsNode.Nodes.Clear();
            treeView.SelectedNode = grsNode;

            // заполнение узла групп элементов
            foreach (ElemGroup elemGroup in template.ElemGroups)
            {
                grsNode.Nodes.Add(NewElemGroupNode(elemGroup));
            }

            // заполнение узла команд
            foreach (ModbusCmd modbusCmd in template.Cmds)
            {
                cmdsNode.Nodes.Add(NewCmdNode(modbusCmd));
            }

            // раскрытие основных узлов дерева
            grsNode.Expand();
            cmdsNode.Expand();

            // возобновление отрисовки дерева
            treeView.EndUpdate();
        }
Exemple #16
0
 /// <summary>
 /// Отобразить код функции группы элементов
 /// </summary>
 private void ShowFuncCode(ElemGroup elemGroup)
 {
     txtGrFuncCode.Text = elemGroup == null ? "" :
                          string.Format("{0} ({1}H)", elemGroup.FuncCode, elemGroup.FuncCode.ToString("X2"));
 }
Exemple #17
0
        /// <summary>
        /// Выполнить сеанс опроса КП
        /// </summary>
        public override void Session()
        {
            base.Session();

            if (deviceTemplate == null)
            {
                WriteToLog(Localization.UseRussian ?
                           "Нормальное взаимодействие с КП невозможно, т.к. шаблон устройства не загружен" :
                           "Normal device communication is impossible because device template has not been loaded");
                Thread.Sleep(ReqParams.Delay);
                lastCommSucc = false;
            }
            else if (elemGroupCnt > 0)
            {
                // выполнение запросов по группам элементов
                int elemGroupInd = 0;
                while (elemGroupInd < elemGroupCnt && lastCommSucc)
                {
                    ElemGroup elemGroup = elemGroups[elemGroupInd];
                    lastCommSucc = false;
                    int tryNum = 0;

                    while (RequestNeeded(ref tryNum))
                    {
                        // выполнение запроса
                        if (request(elemGroup))
                        {
                            lastCommSucc = true;
                            SetTagsData(elemGroup); // установка значений тегов КП
                        }

                        // завершение запроса
                        FinishRequest();
                        tryNum++;
                    }

                    if (lastCommSucc)
                    {
                        // переход к следующей группе элементов
                        elemGroupInd++;
                    }
                    else if (tryNum > 0)
                    {
                        // установка неопределённого статуса тегов КП текущей и следующих групп, если запрос неудачный
                        while (elemGroupInd < elemGroupCnt)
                        {
                            elemGroup = elemGroups[elemGroupInd];
                            InvalidateCurData(elemGroup.StartKPTagInd, elemGroup.ElemVals.Length);
                            elemGroupInd++;
                        }
                    }
                }
            }
            else
            {
                WriteToLog(Localization.UseRussian ?
                           "Отсутствуют элементы для запроса" :
                           "No elements for request");
                Thread.Sleep(ReqParams.Delay);
            }

            // расчёт статистики
            CalcSessStats();
        }
Exemple #18
0
 /// <summary>
 /// Конструктор
 /// </summary>
 public CtrlElemGroup()
 {
     InitializeComponent();
     elemGroup = null;
     Settings  = null;
 }
Exemple #19
0
        /// <summary>
        /// Initializes the device tags.
        /// </summary>
        public override void InitDeviceTags()
        {
            DeviceTemplate deviceTemplate = GetDeviceTemplate();

            if (deviceTemplate == null)
            {
                return;
            }

            // create device model
            deviceModel      = CreateDeviceModel();
            deviceModel.Addr = (byte)NumAddress;

            // add model elements and device tags
            foreach (ElemGroupConfig elemGroupConfig in deviceTemplate.ElemGroups)
            {
                bool      groupActive   = elemGroupConfig.Active;
                bool      groupCommands = groupActive && elemGroupConfig.ReadOnlyEnabled;
                ElemGroup elemGroup     = null;
                TagGroup  tagGroup      = new TagGroup(elemGroupConfig.Name)
                {
                    Hidden = !groupActive
                };
                int elemIndex = 0;

                if (groupActive)
                {
                    elemGroup             = deviceModel.CreateElemGroup(elemGroupConfig.DataBlock);
                    elemGroup.Name        = elemGroupConfig.Name;
                    elemGroup.Address     = (ushort)elemGroupConfig.Address;
                    elemGroup.StartTagIdx = DeviceTags.Count;
                }

                foreach (ElemConfig elemConfig in elemGroupConfig.Elems)
                {
                    // add model element
                    if (groupActive)
                    {
                        Elem elem = elemGroup.CreateElem();
                        elem.Name      = elemConfig.Name;
                        elem.ElemType  = elemConfig.ElemType;
                        elem.ByteOrder = ModbusUtils.ParseByteOrder(elemConfig.ByteOrder) ??
                                         deviceTemplate.Options.GetDefaultByteOrder(ModbusUtils.GetDataLength(elemConfig.ElemType));
                        elemGroup.Elems.Add(elem);
                    }

                    // add model command
                    if (groupCommands && !elemConfig.ReadOnly && !string.IsNullOrEmpty(elemConfig.TagCode))
                    {
                        deviceModel.Cmds.Add(
                            CreateModbusCmd(deviceTemplate.Options, elemGroupConfig, elemConfig, elemIndex));
                    }

                    // add device tag
                    tagGroup.AddTag(elemConfig.TagCode, elemConfig.Name).SetFormat(GetTagFormat(elemConfig));
                    elemIndex++;
                }

                if (groupActive)
                {
                    elemGroup.InitReqPDU();
                    elemGroup.InitReqADU(deviceModel.Addr, transMode);
                    deviceModel.ElemGroups.Add(elemGroup);
                }

                DeviceTags.AddGroup(tagGroup);
            }

            // add model commands
            foreach (CmdConfig cmdConfig in deviceTemplate.Cmds)
            {
                deviceModel.Cmds.Add(CreateModbusCmd(deviceTemplate.Options, cmdConfig));
            }

            deviceModel.InitCmdMap();
            CanSendCommands = deviceModel.Cmds.Count > 0;
            InitModbusPoll();
        }
Exemple #20
0
        /// <summary>
        /// Performs a communication session.
        /// </summary>
        public override void Session()
        {
            base.Session();

            if (deviceModel == null)
            {
                Log.WriteLine(Locale.IsRussian ?
                              "Невозможно опросить устройство, потому что модель устройства не определена" :
                              "Unable to poll the device because device model is undefined");
                SleepPollingDelay();
                LastRequestOK = false;
            }
            else if (deviceModel.ElemGroups.Count > 0)
            {
                // request element groups
                int elemGroupCnt = deviceModel.ElemGroups.Count;
                int elemGroupIdx = 0;

                while (elemGroupIdx < elemGroupCnt && LastRequestOK)
                {
                    ElemGroup elemGroup = deviceModel.ElemGroups[elemGroupIdx];
                    LastRequestOK = false;
                    int tryNum = 0;

                    while (RequestNeeded(ref tryNum))
                    {
                        // perform request
                        if (modbusPoll.DoRequest(elemGroup))
                        {
                            LastRequestOK = true;
                            SetTagData(elemGroup);
                        }

                        FinishRequest();
                        tryNum++;
                    }

                    if (LastRequestOK)
                    {
                        // next element group
                        elemGroupIdx++;
                    }
                    else if (tryNum > 0)
                    {
                        // set tag data as undefined for the current and the next element groups
                        while (elemGroupIdx < elemGroupCnt)
                        {
                            elemGroup = deviceModel.ElemGroups[elemGroupIdx];
                            DeviceData.Invalidate(elemGroup.StartTagIdx, elemGroup.Elems.Count);
                            elemGroupIdx++;
                        }
                    }
                }
            }
            else
            {
                Log.WriteLine(Locale.IsRussian ?
                              "Отсутствуют элементы для запроса" :
                              "No elements to request");
                SleepPollingDelay();
            }

            FinishSession();
        }
Exemple #21
0
            /// <summary>
            /// Копировать модель устройства из заданной
            /// </summary>
            public void CopyFrom(DeviceModel srcDeviceModel)
            {
                if (srcDeviceModel == null)
                    throw new ArgumentNullException("srcDeviceModel");

                // очистка списков групп элементов и команд
                ElemGroups.Clear();
                Cmds.Clear();

                // копирование групп элементов
                foreach (ElemGroup srcGroup in srcDeviceModel.ElemGroups)
                {
                    ElemGroup elemGroup = new ElemGroup(srcGroup.TableType)
                    {
                        Address = srcGroup.Address,
                        Name = srcGroup.Name,
                        StartKPTagInd = srcGroup.StartKPTagInd,
                        StartSignal = srcGroup.StartSignal,
                    };

                    foreach (Elem srcElem in srcGroup.Elems)
                    {
                        elemGroup.Elems.Add(new Elem()
                        {
                            Name = srcElem.Name,
                            ElemType = srcElem.ElemType
                        });
                    }

                    ElemGroups.Add(elemGroup);
                }

                // копирование команд
                foreach (Cmd srcCmd in srcDeviceModel.Cmds)
                {
                    Cmds.Add(new Cmd(srcCmd.TableType)
                    {
                        Multiple = srcCmd.Multiple,
                        ElemCnt = srcCmd.ElemCnt,
                        Address = srcCmd.Address,
                        Name = srcCmd.Name,
                        CmdNum = srcCmd.CmdNum
                    });
                }
            }
Exemple #22
0
            /// <summary>
            /// Загрузить шаблон устройства
            /// </summary>
            public bool LoadTemplate(string fileName, out string errMsg)
            {
                try
                {
                    // очистка списков групп элементов и команд
                    ElemGroups.Clear();
                    Cmds.Clear();

                    // загрузка шаблона устройства
                    XmlDocument xmlDoc = new XmlDocument();
                    xmlDoc.Load(fileName);

                    // загрузка групп элементов
                    XmlNode elemGroupsNode = xmlDoc.DocumentElement.SelectSingleNode("ElemGroups");

                    if (elemGroupsNode != null)
                    {
                        int kpTagInd = 0;

                        foreach (XmlElement elemGroupElem in elemGroupsNode.ChildNodes)
                        {
                            TableTypes tableType = (TableTypes)(Enum.Parse(typeof(TableTypes), 
                                elemGroupElem.GetAttribute("tableType"), true));
                            ElemGroup elemGroup = new ElemGroup(tableType);
                            elemGroup.Address = ushort.Parse(elemGroupElem.GetAttribute("address"));
                            elemGroup.Name = elemGroupElem.GetAttribute("name");
                            elemGroup.StartKPTagInd = kpTagInd;
                            elemGroup.StartSignal = kpTagInd + 1;

                            XmlNodeList elemNodes = elemGroupElem.SelectNodes("Elem");
                            foreach (XmlElement elemElem in elemNodes)
                            {
                                Elem elem = new Elem();
                                elem.Name = elemElem.GetAttribute("name");
                                string elemTypeStr = elemElem.GetAttribute("type");
                                elem.ElemType = elemTypeStr == "" ? elemGroup.DefElemType : 
                                    (ElemTypes)(Enum.Parse(typeof(ElemTypes), elemTypeStr, true));
                                elem.InitByteOrder(elemElem.GetAttribute("byteOrder"));
                                elemGroup.Elems.Add(elem);
                            }

                            if (0 < elemGroup.Elems.Count && elemGroup.Elems.Count <= ElemGroup.GetMaxElemCnt(tableType))
                            {
                                ElemGroups.Add(elemGroup);
                                kpTagInd += elemGroup.Elems.Count;
                            }
                        }
                    }

                    // загрузка команд
                    XmlNode cmdsNode = xmlDoc.DocumentElement.SelectSingleNode("Cmds");

                    if (cmdsNode != null)
                    {
                        foreach (XmlElement cmdElem in cmdsNode.ChildNodes)
                        {
                            TableTypes tableType = (TableTypes)(Enum.Parse(typeof(TableTypes),
                                cmdElem.GetAttribute("tableType"), true));
                            string multiple = cmdElem.GetAttribute("multiple");
                            string elemCnt = cmdElem.GetAttribute("elemCnt");
                            Cmd cmd = multiple == "" || elemCnt == "" ? 
                                new Cmd(tableType) : 
                                new Cmd(tableType, bool.Parse(multiple), int.Parse(elemCnt));
                            cmd.Address = ushort.Parse(cmdElem.GetAttribute("address"));
                            cmd.Name = cmdElem.GetAttribute("name");
                            cmd.CmdNum = int.Parse(cmdElem.GetAttribute("cmdNum"));

                            if (0 < cmd.CmdNum && cmd.CmdNum <= ushort.MaxValue)
                                Cmds.Add(cmd);
                        }
                    }

                    errMsg = "";
                    return true;
                }
                catch (Exception ex)
                {
                    errMsg = Phrases.LoadTemplateError + ":" + Environment.NewLine + ex.Message;
                    return false;
                }
            }