public override void SendCmd(Command cmd) { base.SendCmd(cmd); lastCommSucc = false; bool WriteOk = false; // Идентификатор успешной записи mask_ch_wr = 0; // переменная для параметра MASK_CH записи данных каналов (Регистратор импульсов) mask_chv_wr = 0; // Переменная для параметра MASK_CH записи Веса импульсов (Регистратор импульсов) byte cmdCode = 0x00; // переменная для байта запроса CmdCode - параметр F протокола (номера для записи) byte[] byteData = new byte[1]; // Буфер для значения переменной double cmdVal = cmd.CmdVal; int cmdNum = cmd.CmdNum; int cmdCnl = ActiveCmd[cmdNum]; // Чтение индекса команды по ключу из Словаря if (cmd.CmdTypeID == BaseValues.CmdTypes.Standard) { byte[] cmdcode = ScadaUtils.HexToBytes(devTemplate.CmdGroups[cmdCnl].CmdCode, true); // Чтение строки HEX из параметра CmdCode cmdCode = cmdcode[0]; string cmdtype = devTemplate.CmdGroups[cmdCnl].CmdType; // Чтение строки Типа переменной команды // Определив диапазон проверяем к какому из них относятся Текущие параметры и Веса импульса для составления маски if ((cmdNum >= startCnl && cmdNum <= maxch) || (cmdNum >= startCnlv && cmdNum <= maxchv)) { if ((cmdNum >= startCnl && cmdNum <= maxch) && !(cmdNum >= startCnlv && cmdNum <= maxchv)) { mask_ch_wr = BitFunc.SetBit(mask_ch_wr, cmdNum - startCnl, true); // Если каналы относятся к Текущим данным, то формируем маску для записи маски текущих данных } else { mask_chv_wr = BitFunc.SetBit(mask_chv_wr, cmdNum - startCnlv, true); // Иначе для записи маски Весов импульсов } } if (cmdtype == "uint16") { Array.Resize(ref byteData, 2); byteData = BitConverter.GetBytes(Convert.ToUInt16(cmdVal)); } else if (cmdtype == "float") { Array.Resize(ref byteData, 4); byteData = BitConverter.GetBytes(Convert.ToSingle(cmdVal)); } else if (cmdtype == "double") { Array.Resize(ref byteData, 8); byteData = BitConverter.GetBytes(cmdVal); } else if (cmdtype == "DateTime") { Array.Resize(ref byteData, 6); DateTime dateTime = DateTime.FromOADate(cmdVal); byteData[0] = Convert.ToByte(dateTime.Year - 2000); byteData[1] = Convert.ToByte(dateTime.Month); byteData[2] = Convert.ToByte(dateTime.Day); byteData[3] = Convert.ToByte(dateTime.Hour); byteData[4] = Convert.ToByte(dateTime.Minute); byteData[5] = Convert.ToByte(dateTime.Second); } if (cmdCode == 0x0B) { Array.Resize(ref byteData, 8); // Увеличить размер буфера до 8 байт записываемого параметра F=0x0B PARAM_VAL_NEW } Buf_Out(cmdCnl, cmdCode, byteData, false); // отправить в функцию Номер индекса команды управления и Байт запроса Connection.Write(buf_out, 0, buf_out.Length, CommUtils.ProtocolLogFormats.Hex, out logText); //послать запрос в порт ExecWriteToLog(logText); // вывести запрос в Журнал линии связи readcnt = Connection.Read(buf_in, 0, buf_in.Length, ReqParams.Timeout, CommUtils.ProtocolLogFormats.Hex, out logText); //считать значение из порта ExecWriteToLog(logText); // вывести запрос в Журнал линии связи // Проверка выполнения команды прибором - определяется по ответу прибора на запись команды if (readcnt == buf_in.Length || readcnt == 11) { crc = CrcFunc.CalcCRC16(buf_in, readcnt); // Рассчет CRC16 полученного ответа, при совпадении должно вернуть 0 при расчете CRC16(Modbus) и полного буфера вместе с CRC byte fCode = buf_in[4]; // Чтение кода команды F Array.Copy(buf_in, readcnt - 4, byteIDres, 0, 2); if (!(crc == 0 & fCode != 0 & byteID.SequenceEqual(byteIDres))) // Проверка CRC, параметра F и ID запроса { if (crc != 0) { ExecWriteToLog(CommPhrases.ResponseCrcError); } else if (fCode == 0) { string err = Error_code(buf_in[6]); ExecWriteToLog(CommPhrases.IncorrectCmdData + " - " + err); // При некорректном запросе F будет равен 0x00 } else if (!byteID.SequenceEqual(byteIDres)) { ExecWriteToLog("ID ответа не совпадает с ID запроса"); // При несовпадении ID } FinishRequest(); } else { if (fCode == 0x03 || fCode == 0x08) { byte[] maskchRes = new byte[4]; Array.Copy(buf_in, 6, maskchRes, 0, 4); if (maskch.SequenceEqual(maskchRes)) { WriteOk = true; } } if (fCode == 0x05) { if (buf_in[6] != 0) { WriteOk = true; } } if (fCode == 0x0B) { UInt16 Result_WR = BitConverter.ToUInt16(buf_in, 6); if (Result_WR == 0) { WriteOk = true; } } if (WriteOk) { lastCommSucc = true; string nameCnl = ActiveCnl.Find(c => c.Cnl == cmdNum).Name; ExecWriteToLog($"Запись команды {nameCnl} - " + CommPhrases.ResponseOK); } else { ExecWriteToLog(CommPhrases.WriteDataError); } FinishRequest(); } } else { if (readcnt == 0) { ExecWriteToLog(CommPhrases.ResponseError); // Нет ответа по Timeout - Ошибка связи! } else { ExecWriteToLog(CommPhrases.IncorrectResponseLength); // Некорректная длина ответа } FinishRequest(); } } else { WriteToLog(CommPhrases.IllegalCommand); } CalcCmdStats(); }
public override void OnAddedToCommLine() // Выполняем действия при добавлении Линии связи - Чтение шаблона, создание списка Тегов { base.OnAddedToCommLine(); devTemplate = null; fileName = ReqParams.CmdLine == null ? "" : ReqParams.CmdLine.Trim(); string filePath = AppDirs.ConfigDir + fileName; if (fileName == "") { WriteToLog(string.Format(Localization.UseRussian ? "{0} Ошибка: Не задан шаблон устройства для {1}" : "{0} Error: Template is undefined for the {1}", CommUtils.GetNowDT(), Caption)); } else { try { devTemplate = FileFunc.LoadXml(typeof(DevTemplate), filePath) as DevTemplate; fileyes = true; } catch (Exception err) { WriteToLog(string.Format(Localization.UseRussian ? "Ошибка: " + err.Message : "Error: " + err.Message, CommUtils.GetNowDT(), Caption)); } } // Проверка на наличие конфигурации XML if (devTemplate != null) { // Определить Номера активных запросов, посылку команд проводить согласно списку активных запросов. if (devTemplate.SndGroups.Count != 0) // Определить активные запросы и записать в массив номера запросов для создания тегов по номерам телеграмм // Можно упростить до определения индекса { for (int snd = 0; snd < devTemplate.SndGroups.Count; snd++) { if (devTemplate.SndGroups[snd].SndActive) // Если запрос активен, заносим его номер Cnt в Словарь { if (!ActiveSnd.ContainsKey(devTemplate.SndGroups[snd].SndCnt)) // Ключ = SndCnt - Значение = Индекс Активного запроса SndCnt { ActiveSnd.Add(devTemplate.SndGroups[snd].SndCnt, devTemplate.SndGroups.FindIndex(x => x.SndCnt == devTemplate.SndGroups[snd].SndCnt)); } byte[] sndcode = ScadaUtils.HexToBytes(devTemplate.SndGroups[snd].SndCode, true); // Чтение строки HEX из параметра SndCode sndcode_ = sndcode[0]; if (sndcode_ == 0x01) // Проверяем какой номер запроса у параметра SndCode - F=0x01 Текущие параметры { xValCnt01 = devTemplate.SndGroups[snd].SndCnt; // Сохраняем номер запроса (SndCnt) if (devTemplate.SndGroups[snd].SndData != "") { startCnl = Convert.ToInt32(ScadaUtils.StrToDouble(devTemplate.SndGroups[snd].SndData.Trim())); // Сохранить начальный номер сигнала Текущих параметров } } else if (sndcode_ == 0x07) // Или F=0x07 (Вес импульса для Регистратора импульсов) { xValCnt07 = devTemplate.SndGroups[snd].SndCnt; // Сохраняем номер запроса (SndCnt) if (devTemplate.SndGroups[snd].SndData != "") { startCnlv = Convert.ToInt32(ScadaUtils.StrToDouble(devTemplate.SndGroups[snd].SndData.Trim())); // Сохранить начальный номер сигнала Весов импульсов (Регистратор импульсов) } } activeuse = true; // Есть активные запросы } } } if (devTemplate.CmdGroups.Count != 0) // Определяем наличие активных команд и заносим в словарь Индексов команд { for (int cmd = 0; cmd < devTemplate.CmdGroups.Count; cmd++) { if (devTemplate.CmdGroups[cmd].CmdActive) { if (!ActiveCmd.ContainsKey(devTemplate.CmdGroups[cmd].CmdCnl)) // Ключ = номер команды CmdCnl - Значение = Индекс Активной команды CmdCnl { ActiveCmd.Add(devTemplate.CmdGroups[cmd].CmdCnl, devTemplate.CmdGroups.FindIndex(x => x.CmdCnl == devTemplate.CmdGroups[cmd].CmdCnl)); } } } } if (devTemplate.Values.Count != 0) // Проверка наличия записей переменных в конфигурации { if (activeuse) { // ------------------- Сформировать Список параметров по меню ------------------ for (int ac = 0; ac < ActiveSnd.Count; ac++) { var valCnt_ = devTemplate.Values.FindIndex(x => x.ValCnt == ActiveSnd.ElementAt(ac).Key); for (int val = 0; val < devTemplate.Values[valCnt_].Vals.Count; val++) // МЕНЯЕМ valCnt_ на уже проиндексированный Словарь { if (devTemplate.Values[valCnt_].Vals[val].SigActive) // Проверяем переменную на активность { sigN = devTemplate.Values[valCnt_].Vals[val].SigCnl; // читаем номер сигнала переменной ActiveCnl.Add(new ActiveCnlList() { Cnl = sigN, // Номер текущего активного сигнала Name = devTemplate.Values[valCnt_].Vals[val].SigName, // Имя текущего активного сигнала Format = devTemplate.Values[valCnt_].Vals[val].SigType, // Тип переменной активного сигнала IdxValue = valCnt_, // Индекс группы ответа (ValCnt), в которой находится сигнал MenuName = devTemplate.Values[valCnt_].ValMenu }); // Проверяем номер запроса с параметром SndCode = F=0x01 и создаем маску запросов if (devTemplate.Values[valCnt_].ValCnt == xValCnt01) { // Заносим в маску номер сигнала - startCnl (1 по умолчанию) бит по расположению. mask_ch = BitFunc.SetBit(mask_ch, devTemplate.Values[valCnt_].Vals[val].SigCnl - startCnl, devTemplate.Values[valCnt_].Vals[val].SigActive); //maxch = ActiveCnl.FindLast(s => s.IdxValue == ActiveCnl.Find(d => d.Cnl == sigN).IdxValue).Cnl; // Поиск Максимального номер канала для Текущих параметров } // SigCnl - startCnl (1 по умолчанию) определяет какой бит 32-х разрядного числа выставить в 1 (единицу) if (devTemplate.Values[valCnt_].ValCnt == xValCnt07) { // Заносим в маску номер сигнала - startCnlv (41 по умолчанию) бит по расположению. // Номера сигналов для запроса F=0x07, Вес импульса Регистратора импульсов должны начинаться с 41-ого если не задан в SndData mask_chv = BitFunc.SetBit(mask_chv, devTemplate.Values[valCnt_].Vals[val].SigCnl - startCnlv, devTemplate.Values[valCnt_].Vals[val].SigActive); } // SigCnl - startCnlv (41 по умолчанию) определяет какой бит 32-х разрядного числа выставить в 1 (единицу) } } } // ------------ Создание тегов на основе созданного Списка Активных переменных ------------ List <TagGroup> tagGroups = new List <TagGroup>(); TagGroup tagGroup; var categoryCounts = // Считаем количество Меню и количество переменных в Меню в шаблоне from p in ActiveCnl group p by p.MenuName into g select new { NameMenu = g.Key, counts = g.Count() }; int cnt = 0; foreach (var menu in categoryCounts) { tagGroup = new TagGroup(menu.NameMenu); // Создание меню Тегов var actcnl = ActiveCnl.FindAll(s => s.MenuName == menu.NameMenu).OrderBy(d => d.Cnl); // Сортировка активных каналов по каждому меню foreach (var tags in actcnl) { sigN = ActiveCnl.Find(f => f.Cnl == tags.Cnl).Cnl; tagGroup.KPTags.Add(new KPTag(sigN, ActiveCnl.Find(f => f.Cnl == tags.Cnl).Name)); // Заносим в тег Коммуникатора ActiveCnl.Find(s => s.Cnl == sigN).IdxTag = cnt; // Заносим номер тега Коммуникатора в Список cnt++; // Увеличиваем счетчик тегов } tagGroups.Add(tagGroup); // Добавляем группу тегов } InitKPTags(tagGroups); // Инициализация всех тегов // Определяем диапазон каналов в группах Текущие параметры и Вес импульса if (xValCnt01 != 0) // Если запрос с кодом 0x01 активен, переменная xValCnt01 содержит номер запроса { int idx = devTemplate.SndGroups.FindIndex(f => f.SndCnt == xValCnt01); maxch = ActiveCnl.FindLast(d => d.IdxValue == idx).Cnl; // Максимальный номер канала для Текущих параметров res_ch = BitFunc.CountBit32(mask_ch); // Определяем количество бит = 1 в маске текущих параметров string format = ActiveCnl.Find(d => d.IdxValue == idx).Format; if (format == "float" || format == "uint32") { col = 4; } if (format == "double") { col = 8; } } if (xValCnt07 != 0) // Если запрос с кодом 0x07 активен, переменная xValCnt07 содержит номер запроса { int idx = devTemplate.SndGroups.FindIndex(f => f.SndCnt == xValCnt07); maxchv = ActiveCnl.FindLast(d => d.IdxValue == idx).Cnl; // Максимальный номер канала для Веса импульсов res_chv = BitFunc.CountBit32(mask_chv); // Определяем количество бит = 1 в маске Веса импульсов } } } } }