/// <summary>Получает часовой набор значений указанного параметра за указанный период</summary> /// <param name="start_time">Начало интервала</param> /// <param name="parameter_index">Индекс параметра</param> /// <param name="station_parameter_name">Локальное название параметра архивной станции</param> /// <param name="table">Ссылка на таблицу в памяти для приёма истории значений параметра</param> /// <returns>Запрос успешен: параметр существует и получены данные с хорошим качеством</returns> internal bool get_hour_interval(DateTime start_time, ushort parameter_index, string station_parameter_name, ref MemoryTable table) { user_data_reference _user_data_ref = new user_data_reference(); // структура для передачи ссылки на дополнительные параметры через неуправляемый код UserData _user_data = new UserData(); // структура для транзита дополнительных параметров через неуправляемый код _user_data_ref.data = _user_data; // вставляем в структуру UserData ссылку на класс с дополнительными полями данных _user_data_ref.data.parameter_index = parameter_index; // индекс параметра _user_data_ref.data.count = 0; // счётчик принятых значений параметров с хорошим качеством _user_data_ref.data.table = table; // указательно на таблицу в памяти для приёма сырых значений IntPtr pointer = Marshal.AllocHGlobal(Marshal.SizeOf(_user_data_ref)); // распределяем память в куче для копирования туда индекса кэша Marshal.StructureToPtr(_user_data_ref, pointer, false); // копируем индекс кэша в кучу Services.QAQuery query = new Services.QAQuery(); // структура, описывающая запрос к АС query.LinkId = _link_id; // дескриптор подключения к архивной станции query.Callback = new Services.QACallback(_get_historical_data); // процедура для приёма данных от АС query.BeginTime = new Services.QATime(start_time); // начало запрашиваемого интервала query.EndTime = new Services.QATime(start_time.AddHours(1)); // конец запрашиваемого интервала query.Flags = Services.QF_BEGINOUTSIDE | Services.QF_FILTLAST; // флаги запроса query.Accuracy = 1; // шаг времени для просеивания query.UserData = pointer; // указатель на буфер в неуправляемой памяти с дополнительными параметрами запроса bool parameter_exist = load_parameter(station_parameter_name, out query.ParamId); // проверка наличия параметра на АС и получение его атрибутов if (parameter_exist) { Logger.Log(4, String.Format(" INFO4: [{0}] запрос значений параметра {1}", _station, station_parameter_name)); _execute_query(ref query); } Marshal.FreeHGlobal(pointer); // освобождаем выделенную в куче память return(_user_data_ref.data.count > 0); // признак успешности запроса }
/// <summary>Приёмник сообщений архивной станции</summary> /// <param name="Response">Единичный элемент данных архивной станции</param> /// <returns>Признак готовности к приёму следующего сообщения</returns> private int _get_historical_data(ref Services.QAResponse Response) { try { user_data_reference _user_data_ref = (user_data_reference)Marshal.PtrToStructure(Response.UserData, typeof(user_data_reference)); // копирует локальную копию индекса кэша в управляемую память if (Response.Status == Services.RS_OK) { _pipe_active = true; // приём любого ответа со статусом RS_OK означает рабочее состояние канала связи с архивной станцией if (Response.ParamId.CardId != 0 && Response.ParamId.ParamNo != 0) { if (Response.ParamId.Category == 7) { if (Response.ValueFormat == (int)Services.QAValueFormat.VF_QR8) { KvintArchive.VT_QR8 vt_f = (KvintArchive.VT_QR8)Marshal.PtrToStructure(Response.Value, typeof(KvintArchive.VT_QR8)); _user_data_ref.data.table.write_value(_user_data_ref.data.parameter_index, Response.Time.AsDateTime, vt_f.value, vt_f.quality < 64); if (vt_f.quality < 64) { _user_data_ref.data.count++; } } if (Response.ValueFormat == (int)Services.QAValueFormat.VF_QUI4) { KvintArchive.VT_QUI4 vt_i = (KvintArchive.VT_QUI4)Marshal.PtrToStructure(Response.Value, typeof(KvintArchive.VT_QUI4)); _user_data_ref.data.table.write_value(_user_data_ref.data.parameter_index, Response.Time.AsDateTime, (double)vt_i.value, vt_i.quality < 64); if (vt_i.quality < 64) { _user_data_ref.data.count++; } } if (Response.ValueFormat == (int)Services.QAValueFormat.VF_QUI2) { KvintArchive.VT_QUI2 vt_i = (KvintArchive.VT_QUI2)Marshal.PtrToStructure(Response.Value, typeof(KvintArchive.VT_QUI2)); _user_data_ref.data.table.write_value(_user_data_ref.data.parameter_index, Response.Time.AsDateTime, (double)vt_i.value, vt_i.quality < 64); if (vt_i.quality < 64) { _user_data_ref.data.count++; } } } } return(1); // продолжать приём данных } if (Response.Status == Services.RS_PIPEERROR) { _pipe_active = false; // ошибка программного канала - связь с АС потеряна } if (Response.Status == Services.RS_OPENPIPEFAILED) { _pipe_active = false; // ошибка открытия программного канала - связь с АС не установлена } if (_pipe_active == false) { return(0); // 0 - прекращает приём данных, завершая текущий запрос } } catch (Exception ex) { Logger.Log(0, String.Format(" ERROR: [{0}] ошибка при приёме данных: {1}", _station, ex.Message)); } return(0); // прекратить приём данных }