public void GetDataInCallback(int command, IReadOnlyList <byte> data, Action <Exception, IReadOnlyList <byte> > callback) { if (command == 6) { var result = data.ToList(); if (result[3] == 0) { Log.Log(Name + " > " + "Запрос текущих данных через шестерку"); var cmd = new PollCommand(); if (_lastCurrentDataRequestTime.HasValue && _lastCurrentDataResult != null && DateTime.Now - _lastCurrentDataRequestTime < _cacheTtl) { NamedLog("Данные взяты из кэша (время жизни кэша до: " + (_lastCurrentDataRequestTime.Value + _cacheTtl).ToString("yyyy.MM.dd-HH:mm:ss") + ") и сейчас будут отправлены: " + _lastCurrentDataResult.ToText()); callback(null, _lastCurrentDataResult); } else { NamedLog("Отправка запроса в менеджер обмена по сети БУМИЗ"); _bumiz.SendDataAsync( _bumizControllerInfo.Name, cmd, sendResult => { try { NamedLog("Менеджер обмена БУМИЗ вернул управление"); if (sendResult.ChannelException == null) { var cmdResult = cmd.GetResult(sendResult.Bytes); NamedLog("Результат обмена: " + cmdResult); var i1 = (float)cmdResult.PhaseAcurrent; var i2 = (float)cmdResult.PhaseBcurrent; var i3 = (float)cmdResult.PhaseCcurrent; var p1 = (float)cmdResult.PowerT1; var p2 = (float)cmdResult.PowerT2; var bits = (byte)( (cmdResult.IsInFault ? 0x01 : 0x00) + (cmdResult.IsTurnedOn ? 0x02 : 0x00) + (cmdResult.NoLinkWithCounter ? 0x00 : 0x04) + (cmdResult.CounterType == "СЕ102" ? 0x08 : 0x00) + (cmdResult.IsAutoTurnOffTimerStarted ? 0x10 : 0x00) + (cmdResult.NoFramOrCrcError ? 0x20 : 0x00) + (cmdResult.NoArchives ? 0x00 : 0x40)); NamedLog("Упаковка данных в байты ответа..."); result.AddRange(i1.ToBytes()); result.AddRange(i2.ToBytes()); result.AddRange(i3.ToBytes()); result.AddRange(p1.ToBytes()); result.AddRange(p2.ToBytes()); result.Add(bits); var channel = result[0]; var number = result[2]; result.Add(number); result.Add(0); result.Add(channel); result.Add(0); NamedLog("Упаковка текущих данных завершена"); _lastCurrentDataRequestTime = DateTime.Now; _lastCurrentDataResult = result.ToList(); File.AppendAllText( Path.Combine(Env.LogPath, _bumizControllerInfo.Name + ".read.txt"), DateTime.Now.ToString("yyyy.MM.dd-HH:mm:ss") + " > " + i1.ToString("f2") + " \t" + i2.ToString("f2") + " \t" + i3.ToString("f2") + " \t" + p1.ToString("f2") + " \t" + p2.ToString("f2") + " \t" + bits + Environment.NewLine); } else { NamedLog("Произошло внутреннее исключение при обмене: " + sendResult.ChannelException); } } catch (Exception ex) { NamedLog("После отправки команды, при обработке ответа возникло исключение: " + ex); } finally { NamedLog("В скаду через шлюз будет отправлен результат: " + result.ToText()); callback(null, result); } }, IoPriority.High); } } else if ((result[3] & 0x06) == 0x06) { try { NamedLog("Запрос получасовых данных для " + _bumizControllerInfo.Name); var minutes = result[3] == 0x06 ? 0 : 30; var hour = result[4]; var day = result[5]; var month = result[6]; var year = 2000 + result[7]; var certainTime = new DateTime(year, month, day, hour, minutes, 0); if (certainTime > DateTime.Now) { NamedLog("Запрос за время, которое в системе еще не достигнуто! " + certainTime.ToSimpleString()); } NamedLog("Запрос к хранилищу импульсов за время " + certainTime.ToSimpleString()); var storedImpulses = _pcStorageHolder.Storage.GetAtomicData(Name, certainTime); if (storedImpulses == null) { throw new Exception("Не удалось получить информацию по импульсам за время" + certainTime.ToSimpleString() + " для объекта " + Name); } var storedIntegral = _pcStorageHolder.Storage.GetIntegralData(Name, certainTime); if (storedIntegral == null) { throw new Exception("Не удалось получить суммарную информацию по импульсам до времени " + certainTime.ToSimpleString() + " для объекта " + Name); } NamedLog("Запрос к хранилищу выполнен"); NamedLog("Получены следующие суммарные данные из хранилища: " + storedIntegral); var exps = new List <Expression> { new Expression(_bumizControllerInfo.Pulse1Expression), new Expression(_bumizControllerInfo.Pulse2Expression), new Expression(_bumizControllerInfo.Pulse3Expression) }; foreach (var expression in exps) { expression.Parameters.Add("p1", storedIntegral.ImpulsesCount1); expression.Parameters.Add("p2", storedIntegral.ImpulsesCount2); expression.Parameters.Add("p3", storedIntegral.ImpulsesCount3); } var rp1 = (float)(double)exps[0].Evaluate(); var rp2 = (float)(double)exps[1].Evaluate(); var rp3 = (float)(double)exps[2].Evaluate(); result.AddRange(rp1.ToBytes()); result.AddRange(rp2.ToBytes()); result.AddRange(rp3.ToBytes()); NamedLog("В результате применения к импульсам расчетных формул получены значения расходов: (p1, p2, p3): " + rp1.ToString("f2") + " " + rp2.ToString("f2") + " " + rp3.ToString("f2")); result.AddRange(BitConverter.GetBytes(storedIntegral.RecordsCount)); result.AddRange(BitConverter.GetBytes(storedIntegral.CorrectRecordsCount)); result.AddRange(BitConverter.GetBytes(storedIntegral.IncorrectRecordsCount)); result.AddRange(BitConverter.GetBytes(storedIntegral.SupposedRecordsCount)); NamedLog("Всего записей в хранилище: " + storedIntegral.RecordsCount); result.Add((byte)storedImpulses.Value.PulseCount1); result.Add((byte)storedImpulses.Value.PulseCount2); result.Add((byte)storedImpulses.Value.PulseCount3); result.Add((byte)storedImpulses.Value.Status); result.Add((byte)((storedImpulses.Value.StatusX & 0xF0) >> 8)); result.Add((byte)(storedImpulses.Value.StatusX & 0x0F)); result.Add((byte)(storedImpulses.Value.IsRecordCorrect ? 0x01 : 0x00)); var channel = result[0]; var number = result[2]; result.Add(number); result.Add(0); result.Add(channel); result.Add(0); NamedLog("Упаковка получасовых данных завершена"); } catch (Exception ex) { NamedLog("Будет отправлена пустая посылка, т.к. произошло исключение во время составления ответа на получас: " + ex); } finally { callback(null, result); } } else { NamedLog("Такая шестерка не поддерживается, будет отправлена пустая посылка"); callback(null, result); } } else { throw new Exception("Такая команда не поддерживается объектом БУМИЗ"); } }
private void AsyncRecurseArchiveReadMethod(string objName, WaitableCounter sharedTasksCounter) { Log.Log("Рекурсивное чтение архивов для " + objName); var nowTime = DateTime.Now; DateTime?timeToGet = _storage.GetFirstMissedTimeUpToTime(objName, nowTime); if (timeToGet.HasValue) { var time = timeToGet.Value; var cmd = new ReadArchiveRecordServiceCommand(time); Log.Log("Есть архивы, которые нужно вычитать. Имя объекта=" + objName + " Команда=<" + cmd.Comment + "> Время=" + cmd.RequestedTime.ToSimpleString() + " Арх.№=" + cmd.RecordNumber); sharedTasksCounter.IncrementCount(); _bumizIoManager.SendDataAsync(objName, cmd, result => { try { Log.Log("Асинхронный запрос к сети БУМИЗ выполнен для объекта " + objName); if (result != null) { if (result.ChannelException == null) { Log.Log(result.Bytes.ToText() + " <= для времени = " + time.ToSimpleString() + " Арх.№=" + cmd.RecordNumber); try { var ctResult = cmd.GetResult(result.Bytes); Log.Log(ctResult.ToString()); if (ctResult.RecordTime.Date == time.Date) { Log.Log("Даты совпадают, сохраняем данные в хранилище"); _storage.SaveData(objName, time, true, ctResult.Count1, ctResult.Count2, ctResult.Count3, ctResult.Status, ctResult.Xstatus); } else { throw new Exception("Дата внутри архива не совпадает с датой запроса"); } } catch (Exception ex) { Log.Log("Ошибка обработки ответа БУМИЗ, в хранилище будет записана информация о плохой записи архива"); Log.Log("Причина - исключение: " + ex.ToString()); _storage.SaveData(objName, time, false, 0, 0, 0, 0, 0); } finally { AsyncRecurseArchiveReadMethod(objName, sharedTasksCounter); } } else { Log.Log("Ошибка канала передачи данных: " + result.ChannelException.ToString()); Log.Log("Объект " + objName + " больше не будет опрашиваться в этой итерации (пока все остальные не закончат свои обмены)"); // Получается, что при ошибке передачи данных следующий запрос не будет осуществлен, и объект выпадает из цикла опроса, пока другие объекты не закончат свои работы } } else { Log.Log("Результат выполнения операции не существует, странно :О"); } } catch (Exception ex) { Log.Log("Произошла ошибка при разборе ответа от объекта " + objName); Log.Log(ex.ToString()); // TODO: что делать при ошибке чтения данных (нет связи с FRAM)? } finally { Log.Log("Декремент счетчика задач сети БУМИЗ для объекта " + objName); sharedTasksCounter.DecrementCount(); } }, IoPriority.Low); } else { Log.Log("Либо ошибка хранилища, либо для объекта " + objName + " все данные вычитаны"); } }
private void SyncTimeFunc() { var getTimeCmd = new GetCounterTimeCommand(); var wrappedGetTimeCmd = new WrappedCounterCommand(getTimeCmd); var setTimeCmd = new SetCounterTimeToCurrentCommand(TimeSpan.FromSeconds(5.0)); var wrappedSetTimeCmd = new WrappedCounterCommand(setTimeCmd); while (true) { var waiter = new AutoResetEvent(false); // TODO: данный алгоритм не поддерживает возможности параллельной работы по нескольким каналам одновременно (все объекты синхронизируются последовательно) // TODO: чтобы включить таковую поддержку, нужно создать threadWorker для отправки команд // TODO: но тогда теряется выполнение в реальном времени (то есть, грубо говоря, время будет устанавливаться не точно, если в очереди с высоким приоритетом 100500 команд) // TODO: т.к. DateTime для установки задается во время добавления команды в очередь, а не во время извлечения // TODO: решение: можно написать команду, которая будет подставлять то текущее время на момент распаковки! SetCounterTimeCurrentCommand - написал SetCounterTimeToCurrentCommand foreach (var bumizName in _bumizNames) { var objectName = bumizName; //var obj = info.Item1; //var channel = info.Item2; bool canSyncTime = false; _bumizIoManager.SendDataAsync(objectName, //channel.SendInteleconCommandAsync( wrappedGetTimeCmd, result => { try { if (result.ChannelException == null) { var counterReply = result.Bytes.GetDataBytesFromCounterReply(); Log.Log("Получены байты:" + counterReply.ToText()); var curControllerTime = getTimeCmd.GetResult(counterReply); var currentTime = DateTime.Now; canSyncTime = CanSafeAndReallyNeedTimeSync(curControllerTime, currentTime); Log.Log("Время контроллера " + objectName + ": " + curControllerTime.ToString("yyyy.MM.dd-HH:mm:ss") + (canSyncTime ? " будет произведена синхронизация" : " синхронизация не требуется или невозможна в автоматическом режиме")); } else { throw result.ChannelException; } } catch (Exception ex) { Log.Log("Ошибка при обработке ответа команды получения времени контроллера: " + ex); } finally { waiter.Set(); // в любом случае нужно продолжить алгоритм } }, IoPriority.Lowest); // тут высокий приоритет не нужен, главное, чтобы команда установки времени выполнилась быстро (чтобы успеть во временное окно) Log.Log("Ждем результатов чтения времени объекта " + objectName + " ..."); waiter.WaitOne(); if (canSyncTime) { _bumizIoManager.SendDataAsync(objectName, //channel.SendInteleconCommandAsync( wrappedSetTimeCmd, result => { try { if (result.ChannelException == null) { Log.Log("Синхронизация прошла успешно для объекта " + objectName); } else { throw result.ChannelException; } } catch (Exception ex) { Log.Log("Ошибка при обработке ответа команды установки времени контроллера: " + ex); } finally { waiter.Set(); // finally waited ok } }, IoPriority.Highest); waiter.WaitOne(); } Thread.Sleep(300000); } Thread.Sleep(10000); } }