Beispiel #1
0
        /// <summary>
        /// Gets a user interface object for the device.
        /// </summary>
        private bool GetDeviceView(Settings.KP kp, bool common, out KPView kpView)
        {
            try
            {
                string dllPath      = Path.Combine(Environment.AppDirs.KPDir, kp.Dll);
                KPView commonKpView = Environment.GetKPView(dllPath);

                if (common)
                {
                    kpView = commonKpView;
                }
                else
                {
                    kpView         = KPFactory.GetKPView(commonKpView.GetType(), kp.Number);
                    kpView.KPProps = new KPView.KPProperties(CustomParams, kp.CmdLine);
                    kpView.AppDirs = Environment.AppDirs;
                }

                return(true);
            }
            catch (Exception ex)
            {
                ScadaUiUtils.ShowError(ex.Message);
                Environment.ErrLog.WriteException(ex);
                kpView = null;
                return(false);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Gets the user interface of the particular device.
        /// </summary>
        public KPView GetKPView(string dllPath, int kpNum, KPView.KPProperties kpProps)
        {
            KPView commonKpView = GetKPView(dllPath);
            KPView kpView       = KPFactory.GetKPView(commonKpView.GetType(), kpNum);

            kpView.KPProps = kpProps ?? throw new ArgumentNullException("kpProps");
            kpView.AppDirs = AppDirs;
            return(kpView);
        }
Beispiel #3
0
        /// <summary>
        /// Отобразить форму модально
        /// </summary>
        public static void ShowDialog(int kpNum, KPView.KPProperties kpProps, AppDirs appDirs)
        {
            if (kpProps == null)
                throw new ArgumentNullException("kpProps");
            if (appDirs == null)
                throw new ArgumentNullException("appDirs");

            FrmDevProps frmDevProps = new FrmDevProps();
            frmDevProps.kpNum = kpNum;
            frmDevProps.kpProps = kpProps;
            frmDevProps.appDirs = appDirs;
            frmDevProps.ShowDialog();
        }
Beispiel #4
0
        /// <summary>
        /// Initializes the driver item if needed.
        /// </summary>
        private void InitDriverItem(DriverItem driverItem)
        {
            if (!driverItem.IsInitialized)
            {
                driverItem.IsInitialized = true;

                try
                {
                    KPView kpView = environment.GetKPView(driverItem.FilePath);
                    driverItem.Descr  = kpView.KPDescr?.Replace("\n", Environment.NewLine);
                    driverItem.KPView = kpView;
                }
                catch (Exception ex)
                {
                    driverItem.Descr  = ex.Message;
                    driverItem.KPView = null;
                }
            }
        }
Beispiel #5
0
 /// <summary>
 /// Gets a user interface object for the device.
 /// </summary>
 public bool TryGetKPView(Settings.KP kp, bool common, SortedList <string, string> customParams,
                          out KPView kpView, out string errMsg)
 {
     try
     {
         string dllPath = Path.Combine(AppDirs.KPDir, kp.Dll);
         kpView = common ?
                  GetKPView(dllPath) :
                  GetKPView(dllPath, kp.Number, new KPView.KPProperties(customParams, kp.CmdLine));
         errMsg = null;
         return(true);
     }
     catch (Exception ex)
     {
         ErrLog.WriteException(ex);
         kpView = null;
         errMsg = ex.Message;
         return(false);
     }
 }
Beispiel #6
0
        /// <summary>
        /// Создать каналы
        /// </summary>
        private void CreateCnls()
        {
            writer = null;
            bool   logCreated  = false;
            string logFileName = AppData.ExeDir + "ScadaAdminCreateCnls.txt";

            try
            {
                // создание журанала создания каналов
                writer     = new StreamWriter(logFileName, false, Encoding.UTF8);
                logCreated = true;

                string title = DateTime.Now.ToString("G", Localization.Culture) + " " + AppPhrases.CreateCnlsTitle;
                writer.WriteLine(title);
                writer.WriteLine(new string('-', title.Length));
                writer.WriteLine();

                // определение используемых выбранными КП объектов пользовательского интерфейса КП
                List <KPView> usedKPViewList = new List <KPView>();
                foreach (KPParams kpParams in kpParamsList)
                {
                    if (kpParams.Selected)
                    {
                        KPView kpView = kpParams.KPView;
                        if (kpView != null && !usedKPViewList.Contains(kpView))
                        {
                            usedKPViewList.Add(kpView);
                        }
                    }
                }

                // формирование справочников используемых наименований
                SortedList <string, int> paramList  = new SortedList <string, int>();
                SortedList <string, int> unitList   = new SortedList <string, int>();
                SortedList <string, int> cmdValList = new SortedList <string, int>();

                foreach (KPView kpView in usedKPViewList)
                {
                    if (kpView.DefaultCnls != null)
                    {
                        foreach (KPView.InCnlProps inCnlProps in kpView.DefaultCnls)
                        {
                            string s = inCnlProps.ParamName;
                            if (s != "" && !paramList.ContainsKey(s))
                            {
                                paramList.Add(s, -1);
                            }

                            s = inCnlProps.UnitName;
                            if (s != "" && !unitList.ContainsKey(s))
                            {
                                unitList.Add(s, -1);
                            }

                            if (inCnlProps.CtrlCnlProps != null)
                            {
                                s = inCnlProps.CtrlCnlProps.CmdValName;
                                if (s != "" && !cmdValList.ContainsKey(s))
                                {
                                    cmdValList.Add(s, -1);
                                }
                            }
                        }
                    }
                }

                // определение идентификаторов в справочниках
                writer.WriteLine(AppPhrases.CheckDicts);
                bool paramError  = FindDictIDs(paramList, Tables.GetParamTable(), "ParamID", AppPhrases.ParamNotFound);
                bool unitError   = FindDictIDs(unitList, Tables.GetUnitTable(), "UnitID", AppPhrases.UnitNotFound);
                bool cmdValError = FindDictIDs(cmdValList, Tables.GetCmdValTable(), "CmdValID",
                                               AppPhrases.CmdValsNotFound);

                if (paramError || unitError || cmdValError)
                {
                    writer.WriteLine(AppPhrases.CreateCnlsImpossible);
                }
                else
                {
                    writer.WriteLine(AppPhrases.CreateCnlsStart);

                    // заполнение схем таблиц входных каналов и каналов управления
                    DataTable tblInCnl   = new DataTable("InCnl");
                    DataTable tblCtrlCnl = new DataTable("CtrlCnl");
                    Tables.FillTableSchema(tblInCnl);
                    Tables.FillTableSchema(tblCtrlCnl);

                    // получение таблицы форматов чисел
                    DataTable tblFormat = Tables.GetFormatTable();
                    tblFormat.DefaultView.Sort = "ShowNumber, DecDigits";

                    // создание каналов для КП
                    foreach (KPParams kpParams in kpParamsList)
                    {
                        if (kpParams.Selected)
                        {
                            int inCnlNum   = kpParams.FirstInCnlNum;
                            int ctrlCnlNum = kpParams.FirstCtrlCnlNum;

                            foreach (KPView.InCnlProps inCnlProps in kpParams.KPView.DefaultCnls)
                            {
                                KPView.CtrlCnlProps ctrlCnlProps = inCnlProps.CtrlCnlProps;
                                object lastCtrlCnlNum;
                                if (ctrlCnlProps == null)
                                {
                                    lastCtrlCnlNum = DBNull.Value;
                                }
                                else
                                {
                                    // создание канала управления
                                    DataRow newCtrlCnlRow = tblCtrlCnl.NewRow();
                                    newCtrlCnlRow["CtrlCnlNum"] = ctrlCnlNum;
                                    newCtrlCnlRow["Active"]     = true;
                                    newCtrlCnlRow["Name"]       = ctrlCnlProps.Name;
                                    newCtrlCnlRow["CmdTypeID"]  = (int)ctrlCnlProps.CmdType;
                                    newCtrlCnlRow["ObjNum"]     = kpParams.ObjNum;
                                    newCtrlCnlRow["KPNum"]      = kpParams.KPNum;
                                    newCtrlCnlRow["CmdNum"]     = ctrlCnlProps.CmdNum;
                                    newCtrlCnlRow["CmdValID"]   = ctrlCnlProps.CmdValName == "" ?
                                                                  DBNull.Value : (object)cmdValList[ctrlCnlProps.CmdValName];
                                    newCtrlCnlRow["FormulaUsed"] = ctrlCnlProps.FormulaUsed;
                                    newCtrlCnlRow["Formula"]     = ctrlCnlProps.Formula;
                                    newCtrlCnlRow["EvEnabled"]   = ctrlCnlProps.EvEnabled;
                                    newCtrlCnlRow["ModifiedDT"]  = DateTime.Now;

                                    tblCtrlCnl.Rows.Add(newCtrlCnlRow);
                                    lastCtrlCnlNum = ctrlCnlNum;
                                    ctrlCnlNum++;
                                }

                                // создание входного канала
                                DataRow newInCnlRow = tblInCnl.NewRow();
                                newInCnlRow["CnlNum"]      = inCnlNum;
                                newInCnlRow["Active"]      = true;
                                newInCnlRow["CnlNum"]      = inCnlNum;
                                newInCnlRow["Name"]        = inCnlProps.Name;
                                newInCnlRow["CnlTypeID"]   = (int)inCnlProps.CnlType;
                                newInCnlRow["ModifiedDT"]  = DateTime.Now;
                                newInCnlRow["ObjNum"]      = kpParams.ObjNum;
                                newInCnlRow["KPNum"]       = kpParams.KPNum;
                                newInCnlRow["Signal"]      = inCnlProps.Signal;
                                newInCnlRow["FormulaUsed"] = inCnlProps.FormulaUsed;
                                newInCnlRow["Formula"]     = inCnlProps.Formula;
                                newInCnlRow["Averaging"]   = inCnlProps.Averaging;
                                newInCnlRow["ParamID"]     = inCnlProps.ParamName == "" ?
                                                             DBNull.Value : (object)paramList[inCnlProps.ParamName];

                                newInCnlRow["FormatID"] = DBNull.Value;
                                if (inCnlProps.ShowNumber)
                                {
                                    int ind = tblFormat.DefaultView.Find(new object[] { true, inCnlProps.DecDigits });
                                    if (ind >= 0)
                                    {
                                        newInCnlRow["FormatID"] = tblFormat.DefaultView[ind]["FormatID"];
                                    }
                                    else
                                    {
                                        writer.WriteLine(string.Format(
                                                             AppPhrases.NumFormatNotFound, inCnlNum, inCnlProps.DecDigits));
                                    }
                                }
                                else
                                {
                                    int ind = tblFormat.DefaultView.Find(new object[] { false, DBNull.Value });
                                    if (ind >= 0)
                                    {
                                        newInCnlRow["FormatID"] = tblFormat.DefaultView[ind]["FormatID"];
                                    }
                                    else
                                    {
                                        writer.WriteLine(string.Format(AppPhrases.TextFormatNotFound, inCnlNum));
                                    }
                                }

                                newInCnlRow["UnitID"] = inCnlProps.UnitName == "" ?
                                                        DBNull.Value : (object)unitList[inCnlProps.UnitName];
                                newInCnlRow["CtrlCnlNum"]  = lastCtrlCnlNum;
                                newInCnlRow["EvEnabled"]   = inCnlProps.EvEnabled;
                                newInCnlRow["EvSound"]     = inCnlProps.EvSound;
                                newInCnlRow["EvOnChange"]  = inCnlProps.EvOnChange;
                                newInCnlRow["EvOnUndef"]   = inCnlProps.EvOnUndef;
                                newInCnlRow["LimLowCrash"] = double.IsNaN(inCnlProps.LimLowCrash) ?
                                                             DBNull.Value : (object)inCnlProps.LimLowCrash;
                                newInCnlRow["LimLow"] = double.IsNaN(inCnlProps.LimLow) ?
                                                        DBNull.Value : (object)inCnlProps.LimLow;
                                newInCnlRow["LimHigh"] = double.IsNaN(inCnlProps.LimHigh) ?
                                                         DBNull.Value : (object)inCnlProps.LimHigh;
                                newInCnlRow["LimHighCrash"] = double.IsNaN(inCnlProps.LimHighCrash) ?
                                                              DBNull.Value : (object)inCnlProps.LimHighCrash;

                                tblInCnl.Rows.Add(newInCnlRow);
                                inCnlNum++;
                            }
                        }
                    }

                    // сохранение каналов в БД
                    bool updateOk = UpdateCnls(tblCtrlCnl, AppPhrases.AddedCtrlCnlsCount);
                    updateOk = UpdateCnls(tblInCnl, AppPhrases.AddedInCnlsCount) && updateOk;
                    string msg = updateOk ? AppPhrases.CreateCnlsComplSucc : AppPhrases.CreateCnlsComplWithErr;
                    writer.WriteLine();
                    writer.WriteLine(msg);
                    if (updateOk)
                    {
                        ScadaUtils.ShowInfo(msg + AppPhrases.RefreshRequired);
                    }
                    else
                    {
                        AppData.ErrLog.WriteAction(msg, Log.ActTypes.Error);
                        ScadaUtils.ShowError(msg + AppPhrases.RefreshRequired);
                    }
                }
            }
            catch (Exception ex)
            {
                string errMsg = AppPhrases.CreateCnlsError + ":\r\n" + ex.Message;
                try { writer.WriteLine(errMsg); }
                catch { }
                AppUtils.ProcError(errMsg);
            }
            finally
            {
                try { writer.Close(); }
                catch { }
            }

            if (logCreated)
            {
                Process.Start(logFileName);
            }
        }
Beispiel #7
0
        /// <summary>
        /// Расчитать номера каналов и записать их в список информации о КП
        /// </summary>
        public static bool CalcCnlNums(Dictionary <string, Type> kpViewTypes, List <KPInfo> kpInfoList,
                                       Scada.Comm.AppDirs commDirs, List <int> inCnlNums, CnlNumParams inCnlNumParams,
                                       List <int> ctrlCnlNums, CnlNumParams ctrlCnlNumParams, out string errMsg)
        {
            if (kpViewTypes == null)
            {
                throw new ArgumentNullException("kpViewTypes");
            }
            if (kpInfoList == null)
            {
                throw new ArgumentNullException("kpInfoList");
            }
            if (inCnlNums == null)
            {
                throw new ArgumentNullException("inCnlNums");
            }
            if (inCnlNumParams == null)
            {
                throw new ArgumentNullException("inCnlNumParams");
            }
            if (ctrlCnlNums == null)
            {
                throw new ArgumentNullException("ctrlCnlNums");
            }
            if (ctrlCnlNumParams == null)
            {
                throw new ArgumentNullException("ctrlCnlNumParams");
            }

            bool hasChannels = false;
            bool hasErrors   = false;

            errMsg = "";

            try
            {
                // загрузка настроек SCADA-Коммуникатора
                Scada.Comm.Settings commSett = new Scada.Comm.Settings();
                if (!commSett.Load(commDirs.ConfigDir + Scada.Comm.Settings.DefFileName, out errMsg))
                {
                    throw new Exception(errMsg);
                }

                // заполнение справочника свойств КП
                Dictionary <int, KPView.KPProperties> kpPropsDict = new Dictionary <int, KPView.KPProperties>();
                foreach (Scada.Comm.Settings.CommLine commLine in commSett.CommLines)
                {
                    foreach (Scada.Comm.Settings.KP kp in commLine.ReqSequence)
                    {
                        if (!kpPropsDict.ContainsKey(kp.Number))
                        {
                            kpPropsDict.Add(kp.Number, new KPView.KPProperties(commLine.CustomParams, kp.CmdLine));
                        }
                    }
                }

                // определение стартового номера входного канала
                int inCnlsStart    = inCnlNumParams.Start;
                int inCnlsMultiple = inCnlNumParams.Multiple;
                int inCnlsSpace    = inCnlNumParams.Space;
                int remainder      = inCnlsStart % inCnlsMultiple;
                int curInCnlNum    = remainder > 0 ? inCnlsStart - remainder : inCnlsStart;
                curInCnlNum += inCnlNumParams.Shift;
                if (curInCnlNum < inCnlsStart)
                {
                    curInCnlNum += inCnlsMultiple;
                }

                // определение стартового номера канала управления
                int ctrlCnlsStart    = ctrlCnlNumParams.Start;
                int ctrlCnlsMultiple = ctrlCnlNumParams.Multiple;
                int ctrlCnlsSpace    = ctrlCnlNumParams.Space;
                remainder = ctrlCnlsStart % ctrlCnlNumParams.Multiple;
                int curCtrlCnlNum = remainder > 0 ? ctrlCnlsStart - remainder : ctrlCnlsStart;
                curCtrlCnlNum += ctrlCnlNumParams.Shift;
                if (curCtrlCnlNum < ctrlCnlNumParams.Start)
                {
                    curCtrlCnlNum += ctrlCnlNumParams.Multiple;
                }

                // расчёт номеров каналов КП
                int curInCnlInd    = 0;
                int inCnlNumsCnt   = inCnlNums.Count;
                int curCtrlCnlInd  = 0;
                int ctrlCnlNumsCnt = ctrlCnlNums.Count;

                foreach (KPInfo kpInfo in kpInfoList)
                {
                    if (kpInfo.Selected)
                    {
                        // получение типа интерфейса КП
                        Type kpViewType;
                        if (!kpViewTypes.TryGetValue(kpInfo.DllFileName, out kpViewType))
                        {
                            continue;
                        }

                        // создание экземпляра класса интерфейса КП
                        KPView kpView = null;
                        try
                        {
                            kpView = KPFactory.GetKPView(kpViewType, kpInfo.KPNum);
                            KPView.KPProperties kpProps;
                            if (kpPropsDict.TryGetValue(kpInfo.KPNum, out kpProps))
                            {
                                kpView.KPProps = kpProps;
                            }
                            kpView.AppDirs = commDirs;
                        }
                        catch
                        {
                            kpInfo.SetInCnlNums(true);
                            kpInfo.SetCtrlCnlNums(true);
                            continue;
                        }

                        // получение прототипов каналов КП по умолчанию
                        try
                        {
                            kpInfo.DefaultCnls = kpView.DefaultCnls;
                        }
                        catch
                        {
                            kpInfo.SetInCnlNums(true);
                            kpInfo.SetCtrlCnlNums(true);
                            continue;
                        }

                        // определение номеров входных каналов с учётом занятых существующими каналами номеров
                        if (kpInfo.DefaultCnls != null && kpInfo.DefaultCnls.InCnls.Count > 0)
                        {
                            hasChannels = true;

                            int firstInCnlNum; // номер первого входного канала КП
                            int lastInCnlNum;  // номер последнего входного канала КП
                            int newInCnlInd;   // новый индекс списка номеров входных каналов
                            CalcFirstAndLastNums(curInCnlNum, curInCnlInd, inCnlNums, inCnlNumsCnt,
                                                 kpInfo.DefaultCnls.InCnls.Count, inCnlsSpace, inCnlsMultiple,
                                                 out firstInCnlNum, out lastInCnlNum, out newInCnlInd);

                            if (lastInCnlNum > ushort.MaxValue)
                            {
                                hasErrors = true;
                                kpInfo.SetInCnlNums(true);
                            }
                            else
                            {
                                kpInfo.SetInCnlNums(false, firstInCnlNum, lastInCnlNum);

                                curInCnlInd = newInCnlInd;
                                curInCnlNum = firstInCnlNum;
                                do
                                {
                                    curInCnlNum += inCnlsMultiple;
                                }while (curInCnlNum - lastInCnlNum <= inCnlsSpace);
                            }
                        }
                        else
                        {
                            // номера каналов не назначаются, т.к. КП не поддерживает создание входных каналов
                            kpInfo.SetInCnlNums(false);
                        }

                        // определение номеров каналов управления с учётом занятых существующими каналами номеров
                        if (kpInfo.DefaultCnls != null && kpInfo.DefaultCnls.CtrlCnls.Count > 0)
                        {
                            hasChannels = true;

                            int firstCtrlCnlNum; // номер первого канала управления КП
                            int lastCtrlCnlNum;  // номер последнего канала управления КП
                            int newCtrlCnlInd;   // новый индекс списка номеров каналов управления
                            CalcFirstAndLastNums(curCtrlCnlNum, curCtrlCnlInd, ctrlCnlNums, ctrlCnlNumsCnt,
                                                 kpInfo.DefaultCnls.CtrlCnls.Count, ctrlCnlsSpace, ctrlCnlsMultiple,
                                                 out firstCtrlCnlNum, out lastCtrlCnlNum, out newCtrlCnlInd);

                            if (lastCtrlCnlNum > ushort.MaxValue)
                            {
                                hasErrors = true;
                                kpInfo.SetCtrlCnlNums(true);
                            }
                            else
                            {
                                kpInfo.SetCtrlCnlNums(false, firstCtrlCnlNum, lastCtrlCnlNum);

                                curCtrlCnlInd = newCtrlCnlInd;
                                curCtrlCnlNum = firstCtrlCnlNum;
                                do
                                {
                                    curCtrlCnlNum += ctrlCnlsMultiple;
                                }while (curCtrlCnlNum - lastCtrlCnlNum <= ctrlCnlsSpace);
                            }
                        }
                        else
                        {
                            // номера каналов не назначаются, т.к. КП не поддерживает создание каналов управления
                            kpInfo.SetCtrlCnlNums(false);
                        }
                    }
                    else
                    {
                        // номера каналов не назначаются, т.к. КП не выбран
                        kpInfo.SetInCnlNums(false, -1, -1);
                        kpInfo.SetCtrlCnlNums(false, -1, -1);
                    }
                }

                if (hasErrors)
                {
                    errMsg = AppPhrases.CalcCnlNumsErrors;
                }
                else if (!hasChannels)
                {
                    errMsg = AppPhrases.CreatedCnlsMissing;
                }
            }
            catch (Exception ex)
            {
                hasErrors = true;
                errMsg    = AppPhrases.CalcCnlNumsError + ":\r\n" + ex.Message;
            }

            return(hasChannels && !hasErrors);
        }
Beispiel #8
0
        /// <summary>
        /// Calculate the channel numbers and write them to the list of information on KP
        /// </summary>
        public static bool CalcCnlNums(Dictionary <string, Type> kpViewTypes, List <KPInfo> kpInfoList,
                                       Scada.Comm.AppDirs commDirs, List <int> inCnlNums, CnlNumParams inCnlNumParams,
                                       List <int> ctrlCnlNums, CnlNumParams ctrlCnlNumParams, out string errMsg)
        {
            if (kpViewTypes == null)
            {
                throw new ArgumentNullException(nameof(kpViewTypes));
            }
            if (kpInfoList == null)
            {
                throw new ArgumentNullException(nameof(kpInfoList));
            }
            if (inCnlNums == null)
            {
                throw new ArgumentNullException(nameof(inCnlNums));
            }
            if (inCnlNumParams == null)
            {
                throw new ArgumentNullException(nameof(inCnlNumParams));
            }
            if (ctrlCnlNums == null)
            {
                throw new ArgumentNullException(nameof(ctrlCnlNums));
            }
            if (ctrlCnlNumParams == null)
            {
                throw new ArgumentNullException(nameof(ctrlCnlNumParams));
            }

            var hasChannels = false;
            var hasErrors   = false;

            errMsg = "";

            try {
                // loading SCADA-Communicator settings
                Scada.Comm.Settings commSett = new Scada.Comm.Settings();
                if (!commSett.Load(commDirs.ConfigDir + Scada.Comm.Settings.DefFileName, out errMsg))
                {
                    throw new Exception(errMsg);
                }

                // filling the directory of KP properties
                Dictionary <int, KPView.KPProperties> kpPropsDict = new Dictionary <int, KPView.KPProperties>();
                foreach (Scada.Comm.Settings.CommLine commLine in commSett.CommLines)
                {
                    foreach (Scada.Comm.Settings.KP kp in commLine.ReqSequence)
                    {
                        if (!kpPropsDict.ContainsKey(kp.Number))
                        {
                            kpPropsDict.Add(kp.Number, new KPView.KPProperties(commLine.CustomParams, kp.CmdLine));
                        }
                    }
                }

                // determining the starting number of the input channel
                int inCnlsStart    = inCnlNumParams.Start;
                int inCnlsMultiple = inCnlNumParams.Multiple;
                int inCnlsSpace    = inCnlNumParams.Space;
                int remainder      = inCnlsStart % inCnlsMultiple;
                int curInCnlNum    = remainder > 0 ? inCnlsStart - remainder : inCnlsStart;
                curInCnlNum += inCnlNumParams.Shift;
                if (curInCnlNum < inCnlsStart)
                {
                    curInCnlNum += inCnlsMultiple;
                }

                // determination of the control channel start number
                int ctrlCnlsStart    = ctrlCnlNumParams.Start;
                int ctrlCnlsMultiple = ctrlCnlNumParams.Multiple;
                int ctrlCnlsSpace    = ctrlCnlNumParams.Space;
                remainder = ctrlCnlsStart % ctrlCnlNumParams.Multiple;
                int curCtrlCnlNum = remainder > 0 ? ctrlCnlsStart - remainder : ctrlCnlsStart;
                curCtrlCnlNum += ctrlCnlNumParams.Shift;
                if (curCtrlCnlNum < ctrlCnlNumParams.Start)
                {
                    curCtrlCnlNum += ctrlCnlNumParams.Multiple;
                }

                // calculation channel numbers KP
                var curInCnlInd    = 0;
                int inCnlNumsCnt   = inCnlNums.Count;
                var curCtrlCnlInd  = 0;
                int ctrlCnlNumsCnt = ctrlCnlNums.Count;

                foreach (var kpInfo in kpInfoList)
                {
                    if (kpInfo.Selected)
                    {
                        // getting interface type kp
                        if (!kpViewTypes.TryGetValue(kpInfo.DllFileName, out Type kpViewType))
                        {
                            continue;
                        }

                        // instantiating a KP interface class
                        KPView kpView = null;
                        try {
                            kpView = KPFactory.GetKPView(kpViewType, kpInfo.KPNum);
                            KPView.KPProperties kpProps;
                            if (kpPropsDict.TryGetValue(kpInfo.KPNum, out kpProps))
                            {
                                kpView.KPProps = kpProps;
                            }
                            kpView.AppDirs = commDirs;
                        } catch {
                            kpInfo.SetInCnlNums(true);
                            kpInfo.SetCtrlCnlNums(true);
                            continue;
                        }

                        // default prototype channel acquisition
                        try {
                            kpInfo.DefaultCnls = kpView.DefaultCnls;
                        } catch {
                            kpInfo.SetInCnlNums(true);
                            kpInfo.SetCtrlCnlNums(true);
                            continue;
                        }

                        // definition of numbers of input channels, taking into account the numbers occupied by existing channels
                        if (kpInfo.DefaultCnls != null && kpInfo.DefaultCnls.InCnls.Count > 0)
                        {
                            hasChannels = true;

                            int firstInCnlNum; // first input channel number
                            int lastInCnlNum;  // number of last input channel KP
                            int newInCnlInd;   // new index of the number of input channels
                            CalcFirstAndLastNums(curInCnlNum, curInCnlInd, inCnlNums, inCnlNumsCnt,
                                                 kpInfo.DefaultCnls.InCnls.Count, inCnlsSpace, inCnlsMultiple,
                                                 out firstInCnlNum, out lastInCnlNum, out newInCnlInd);

                            if (lastInCnlNum > ushort.MaxValue)
                            {
                                hasErrors = true;
                                kpInfo.SetInCnlNums(true);
                            }
                            else
                            {
                                kpInfo.SetInCnlNums(false, firstInCnlNum, lastInCnlNum);

                                curInCnlInd = newInCnlInd;
                                curInCnlNum = firstInCnlNum;
                                do
                                {
                                    curInCnlNum += inCnlsMultiple;
                                } while (curInCnlNum - lastInCnlNum <= inCnlsSpace);
                            }
                        }
                        else
                        {
                            // channel numbers are not assigned because KP does not support input channel creation
                            kpInfo.SetInCnlNums(false);
                        }

                        // identification of control channel numbers with regard to numbers occupied by existing channels
                        if (kpInfo.DefaultCnls != null && kpInfo.DefaultCnls.CtrlCnls.Count > 0)
                        {
                            hasChannels = true;

                            int firstCtrlCnlNum; // first control channel number
                            int lastCtrlCnlNum;  // control channel last control channel number
                            int newCtrlCnlInd;   // new index of the list of control channel numbers
                            CalcFirstAndLastNums(curCtrlCnlNum, curCtrlCnlInd, ctrlCnlNums, ctrlCnlNumsCnt,
                                                 kpInfo.DefaultCnls.CtrlCnls.Count, ctrlCnlsSpace, ctrlCnlsMultiple,
                                                 out firstCtrlCnlNum, out lastCtrlCnlNum, out newCtrlCnlInd);

                            if (lastCtrlCnlNum > ushort.MaxValue)
                            {
                                hasErrors = true;
                                kpInfo.SetCtrlCnlNums(true);
                            }
                            else
                            {
                                kpInfo.SetCtrlCnlNums(false, firstCtrlCnlNum, lastCtrlCnlNum);

                                curCtrlCnlInd = newCtrlCnlInd;
                                curCtrlCnlNum = firstCtrlCnlNum;
                                do
                                {
                                    curCtrlCnlNum += ctrlCnlsMultiple;
                                } while (curCtrlCnlNum - lastCtrlCnlNum <= ctrlCnlsSpace);
                            }
                        }
                        else
                        {
                            // channel numbers are not assigned because KP does not support the creation of control channels
                            kpInfo.SetCtrlCnlNums(false);
                        }
                    }
                    else
                    {
                        // channel numbers are not assigned because KP is not selected
                        kpInfo.SetInCnlNums(false, -1, -1);
                        kpInfo.SetCtrlCnlNums(false, -1, -1);
                    }
                }

                if (hasErrors)
                {
                    errMsg = AppPhrases.CalcCnlNumsErrors;
                }
                else if (!hasChannels)
                {
                    errMsg = AppPhrases.CreatedCnlsMissing;
                }
            } catch (Exception ex) {
                hasErrors = true;
                errMsg    = AppPhrases.CalcCnlNumsError + ":\r\n" + ex.Message;
            }

            return(hasChannels && !hasErrors);
        }