/// <summary> /// Wait new tasks and and create instance from DC if not created yet. /// </summary> void Run() { //Read tasks that was prosessed when app was closed. //This is used to start example monitoring again. GXClaimedTask executedTask = LoadExecutedTask(this.Guid); if (executedTask != null) { if (executedTask.Task.TaskType == TaskType.StartMonitor) { TaskModified.Set(); } } else { GXAmiTask[] pendingTasks = DC.GetTasks(TaskState.Pending, false); if (pendingTasks.Length != 0) { DC_OnTasksAdded(DC, pendingTasks); } } //Save device threads so we can wait whem on close. while (true) { List<EventWaitHandle> events = new List<EventWaitHandle>(); events.Add(Closing); events.Add(TaskModified); foreach (GXClaimedInfo it in ClaimedTasks.Values.ToArray()) { events.Add(it.TaskExecuted); } int ret = EventWaitHandle.WaitAny(events.ToArray()); //If closing. if (ret == 0) { break; } //If new task added. if (ret == 1) { System.Diagnostics.Debug.WriteLine("DC task added: " + Guid.ToString()); //Get new task GXClaimedTask taskinfo = executedTask; executedTask = null; lock (UnclaimedTasks) { for (int pos = 0; pos != UnclaimedTasks.Count; ++pos) { GXAmiTask task = UnclaimedTasks[pos]; //New task added. if (task.State == TaskState.Pending) { lock (UnclaimedTasks) { bool idle = true; //If task is sent to the device if (task.TargetDeviceID != null) { idle = !ClaimedTasks.ContainsKey(task.TargetDeviceID.Value) || ClaimedTasks[task.TargetDeviceID.Value].ClaimedTasks.Count == 0; } else //If task is sent to the DC. { idle = !ClaimedTasks.ContainsKey(task.DataCollectorGuid) || ClaimedTasks[task.DataCollectorGuid].ClaimedTasks.Count == 0; } //If collector is reading do not claim task before collector is finished reading. if (idle) { try { taskinfo = DC.ClaimTask(task); //If other DC is claimed the task. if (taskinfo == null || task.Id != taskinfo.Task.Id) { //Remove task that was asked, but failed. UnclaimedTasks.Remove(task); //Remove executed task. if (taskinfo != null && task.Id != taskinfo.Task.Id) { UnclaimedTasks.Remove(taskinfo.Task); if (taskinfo.Task.State == TaskState.Processing) { System.Diagnostics.Debug.Assert(false); } task = taskinfo.Task; } } else //DC claimed task. { task = taskinfo.Task; UnclaimedTasks.Remove(task); } if (taskinfo != null) { //This should be newer happend. if (task.State == TaskState.Processing) { System.Diagnostics.Debug.Assert(false); } System.Diagnostics.Debug.WriteLine("DC Start to process task: " + Guid.ToString() + " " + task.Id.ToString() + " " + task.TargetDeviceID.ToString()); if (m_TasksClaimed != null) { m_TasksClaimed(this, new GXAmiTask[] { task }); } } else { System.Diagnostics.Debug.WriteLine("DC Failed to get task: " + Guid.ToString() + " " + task.Id.ToString()); } break; } catch (Exception ex) { if (m_Error != null) { m_Error(this, ex); } } } else//If task is processed. Wait until task is executed and read again... { System.Diagnostics.Debug.WriteLine("DC is already processing task: " + Guid.ToString()); if (task.TargetDeviceID != null) { ClaimedTasks[task.TargetDeviceID].TaskExecuted.WaitOne(50000); } else { ClaimedTasks[task.DataCollectorGuid].TaskExecuted.WaitOne(50000); } break; } } } } } //If new task is claimed. if (taskinfo != null) { if (taskinfo.Task.TargetDeviceID != null) { SaveExecutedTask(this.Guid, taskinfo); GXClaimedInfo dcinfo = null; //If task is sent to existing device. if (ClaimedTasks.ContainsKey(taskinfo.Task.TargetDeviceID.Value)) { dcinfo = ClaimedTasks[taskinfo.Task.TargetDeviceID.Value]; lock (dcinfo.ClaimedTasks) { dcinfo.ClaimedTasks.Add(taskinfo); dcinfo.NewTask.Set(); } } else//If task is sent to new device. { dcinfo = new GXClaimedInfo(); dcinfo.ClaimedTasks.Add(taskinfo); ClaimedTasks.Add(taskinfo.Task.TargetDeviceID.Value, dcinfo); Thread thread = new Thread(new ParameterizedThreadStart(DeviceCollector)); thread.Start(dcinfo); dcinfo.WorkThread = thread; } } //Task is send to Media else if (taskinfo.Task.TargetType == TargetType.Media) { GXClaimedInfo dcinfo = null; if (ClaimedTasks.ContainsKey(taskinfo.Task.DataCollectorGuid)) { dcinfo = ClaimedTasks[taskinfo.Task.DataCollectorGuid]; lock (dcinfo.ClaimedTasks) { dcinfo.ClaimedTasks.Add(taskinfo); dcinfo.NewTask.Set(); } } else { dcinfo = new GXClaimedInfo(); dcinfo.ClaimedTasks.Add(taskinfo); ClaimedTasks.Add(taskinfo.Task.DataCollectorGuid, dcinfo); Thread thread = new Thread(new ParameterizedThreadStart(DeviceCollector)); thread.Start(dcinfo); dcinfo.WorkThread = thread; } } } } else { ret -= 2; GXClaimedInfo c = ClaimedTasks[ClaimedTasks.Keys.ElementAt(ret)]; c.TaskExecuted.Reset(); System.Diagnostics.Debug.WriteLine("Task handled: " + c.ClaimedTasks[0].Task.Id.ToString()); foreach (GXClaimedTask it2 in c.ClaimedTasks) { GXAmiTask task = it2.Task; //This should be newer happend. if (task.State == TaskState.Processing) { System.Diagnostics.Debug.Assert(false); } //Remove task after successful reading. if (task.State == TaskState.Succeeded) { lock (c.ClaimedTasks) { c.ClaimedTasks.Remove(it2); } try { DC.RemoveTask(task); //Close thread if device task is executed and connection is not leave open. if ( task.TaskType != TaskType.StartMonitor) { if (task.TargetDeviceID != null) { c.Closing.Set(); ClaimedTasks.Remove(task.TargetDeviceID.Value); } else if (task.TaskType == TaskType.MediaClose)//if DC task is executed. { c.Closing.Set(); ClaimedTasks.Remove(task.DataCollectorGuid); } } } catch (Exception ex) { if (m_Error != null) { m_Error(this, ex); } } lock (UnclaimedTasks) { //Search next unclaimed task and execute it. foreach (GXAmiTask ut in UnclaimedTasks) { if (ut.State == TaskState.Pending) { TaskModified.Set(); break; } } } //System.Diagnostics.Debug.WriteLine("Wait next task."); break; //Break here because task is removed. } else if (task.State == TaskState.Timeout) { try { lock (c.ClaimedTasks) { c.ClaimedTasks.Remove(it2); } DC.AddDeviceError(task, new TimeoutException(), 1); //Remove failed task. DC.RemoveTask(task); } catch (Exception ex) { if (m_Error != null) { m_Error(this, ex); } } break; //Break here because task is removed. } else if (task.State == TaskState.Failed) { try { lock (c.ClaimedTasks) { c.ClaimedTasks.Remove(it2); } foreach (var it in c.Exceptions) { DC.AddDeviceError(it.Key.Task, it.Value, 1); /* //If device is caused the error. if (it.Key.Task.TargetDeviceID.HasValue) { DC.AddDeviceError(it.Key.Task, it.Value, 1); } //If DC is caused the error. else if (it.Key.Task.DataCollectorID != 0) { DC.AddDeviceError(it.Key.Task, it.Value, 1); } else { throw new Exception("Unknown target."); } * */ } c.Exceptions.Clear(); //Remove failed task. DC.RemoveTask(task); } catch (Exception ex) { if (m_Error != null) { m_Error(this, ex); } } break; //Break here because task is removed. } } } } //Tell all collector threads to close. List<Thread> threads = new List<Thread>(); foreach(GXClaimedInfo it in ClaimedTasks.Values) { it.Closing.Set(); threads.Add(it.WorkThread); } //Wait until threads are closed. foreach (Thread it in threads) { it.Join(); } }
private void HandleDevice(GXClaimedInfo info, GXProxyClass pc, ref string path, ref bool leaveConnectionOpen, GXClaimedTask taskinfo) { try { //If device template is not loaded yet. if (path == null) { path = Path.Combine(Gurux.Common.GXCommon.ApplicationDataPath, "Gurux"); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); Gurux.Common.GXFileSystemSecurity.UpdateDirectorySecurity(path); } path = Path.Combine(path, "Gurux.DeviceSuite"); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); Gurux.Common.GXFileSystemSecurity.UpdateDirectorySecurity(path); } path = Path.Combine(path, "DeviceProfiles"); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); Gurux.Common.GXFileSystemSecurity.UpdateDirectorySecurity(path); } path = Path.Combine(path, taskinfo.DeviceProfile.ToString()); //Load Device template if not loaded yet. if (!Directory.Exists(path)) { Directory.CreateDirectory(path); Gurux.Common.GXFileSystemSecurity.UpdateDirectorySecurity(path); byte[] data = DC.GetDeviceProfilesData(taskinfo.DeviceProfile); GXDeviceProfile type = pc.Import(data, path); if (!(type is GXPublishedDeviceProfile)) { File.Copy(type.Path, Path.Combine(path, taskinfo.DeviceProfile.ToString() + ".gxp"), true); } } } } catch (Exception ex) { path = null; if (Directory.Exists(path)) { Directory.Delete(path, true); } lock (info.Exceptions) { info.Exceptions.Add(taskinfo, ex); taskinfo.Task.State = TaskState.Failed; } } try { //Save executed task. This is used if error occures. pc.Connect(path, taskinfo); //Read or write device. if (taskinfo.Task.TaskType == TaskType.Read || taskinfo.Task.TaskType == TaskType.Write) { System.Diagnostics.Debug.WriteLine("DC start to read target: " + taskinfo.Task.Id.ToString() + " " + taskinfo.Task.TargetDeviceID.ToString()); pc.ExecuteTransaction(taskinfo); taskinfo.Task.State = TaskState.Succeeded; System.Diagnostics.Debug.WriteLine("DC end reading target: " + taskinfo.Task.Id.ToString() + " " + Guid.ToString()); } else if (taskinfo.Task.TaskType == TaskType.StartMonitor) { leaveConnectionOpen = true; pc.StartMonitoring(); taskinfo.Task.State = TaskState.Succeeded; } else if (taskinfo.Task.TaskType == TaskType.StopMonitor) { leaveConnectionOpen = false; pc.StopMonitoring(); taskinfo.Task.State = TaskState.Succeeded; } else { throw new Exception("Invalid task type."); } } catch (Exception ex) { lock (info.Exceptions) { info.Exceptions.Add(taskinfo, ex); taskinfo.Task.State = TaskState.Failed; } if (m_Error != null) { m_Error(this, ex); } } }