ConfigService.cs 76 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705
  1. using Cognex.VisionPro;
  2. using Cognex.VisionPro.ToolBlock;
  3. using SqlSugar;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Collections.ObjectModel;
  7. using System.Globalization;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Threading;
  11. using System.Threading.Tasks;
  12. using TeamAAS_VP.Core;
  13. using TeamAAS_VP.Data; // for ISystemDatabaseService (if used)
  14. using TeamAAS_VP.Enums;
  15. using TeamAAS_VP.Interfaces;
  16. using TeamAAS_VP.Models;
  17. using TeamAAS_VP.Models.Calibration;
  18. using TeamAAS_VP.Models.Feeder;
  19. using TeamAAS_VP.Models.Lights;
  20. using TeamAAS_VP.Models.PLC;
  21. using TeamAAS_VP.Models.ScrewDriver;
  22. using TeamAAS_VP.Models.Torque;
  23. using TeamAAS_VP.Resources.Languages;
  24. using WPFLocalizeExtension.Engine;
  25. namespace TeamAAS_VP.Services
  26. {
  27. /// <summary>
  28. /// ���ò�������ʵ���ࡣ
  29. /// �̰߳�ȫ���ڲ�ʹ��˽�����ֶ� <see cref="_sync"/> ���������ڴ漯�ϵIJ������ʡ�
  30. /// �־û����Լ��ϵ��޸Ļ�д�ص���Ӧ�������ļ���·�����ڲ���̬�� <see cref="ConfigPaths"/> ���壩��
  31. /// </summary>
  32. public class ConfigService : IConfigService
  33. {
  34. private static class ConfigPaths
  35. {
  36. // ��·�����й����ڱ��࣬��ǰʹ������ FilePath ֵ�Ա��ּ���
  37. public static readonly string CamerasConfigurationPath = "..//Config//CameraConfiguration.cfg";
  38. public static readonly string RobotsConfigurationPath = "..//Config//RobotsConfiguration.cfg";
  39. public static readonly string FeedersConfigurationPath = "..//Config//FeedersConfiguration.cfg";
  40. public static readonly string PlcConfigurationPath = "..//Config//PlcConfiguration.cfg";
  41. public static readonly string BgTcpIpConfigurationPath = "..//Config//BgTcpIpConfiguration.cfg";
  42. public static readonly string BgModbusTcpConfigurationPath = "..//Config//BgModbusTcpConfiguration.cfg";
  43. public static readonly string SystemConfigurationPath = "..//Config//SystemConfiguration.cfg";
  44. public static readonly string DeviceInfoConfigurationPath = "..//Config//DeviceInfo.cfg";
  45. // Feeder������������·��
  46. public static readonly string FeederClearanceTasksConfigurationPath = "..//Config//FeederClearanceTasksConfiguration.cfg";
  47. // ��Դ����������·��
  48. public static readonly string LightControllersConfigurationPath = "..//Config//LightControllersConfiguration.cfg";
  49. // ��������·�������豸��
  50. public static readonly string ScrewDriverConfigurationPath = "..//Config//ScrewDriverConfiguration.cfg";
  51. // ��˿�����������ϣ�����·��
  52. public static readonly string ScrewFeedersConfigurationPath = "..//Config//ScrewFeedersConfiguration.cfg";
  53. // ˢ��������·��
  54. public static readonly string CardReaderConfigurationPath = "..//Config//CardReaderConfiguration.cfg";
  55. // ��������·��
  56. public static readonly string TorqueReaderConfigurationPath = "..//Config//TorqueReaderConfiguration.cfg";
  57. // ������������·��
  58. public static readonly string DataConfigurationPath = "..//Config//DataConfiguration.cfg";
  59. }
  60. private readonly object _sync = new object();
  61. private ObservableCollection<CameraInfo> Cameras { get; set; }
  62. private ObservableCollection<RobotInfo> Robots { get; set; }
  63. private ObservableCollection<FeederInfo> Feeders { get; set; }
  64. // ��˿�����������ϣ�����
  65. private ObservableCollection<ScrewFeederInfo> ScrewFeeders { get; set; }
  66. private ObservableCollection<PlcInfo> Plcs { get; set; }
  67. private BgTcpIP BgCommunicate { get; set; }
  68. private BgModbusTcp BgModbusCommunicate { get; set; }
  69. private ObservableCollection<FeederClearWork> FeederClearanceTasks { get; set; }
  70. // ��Դ����������
  71. private ObservableCollection<LightControllerConfig> LightControllers { get; set; }
  72. // Device info - 支持多设备
  73. private List<DeviceInfo> _deviceInfoList;
  74. public CTQ_Data CtqData { get; set; }
  75. private PlcAddressConfig PlcAddressConfig { get; set; }
  76. // ������������
  77. private TeamAAS_VP.Models.ScrewDriver.ScrewDriverConfig _screwDriverConfig;
  78. public TeamAAS_VP.Models.ScrewDriver.ScrewDriverConfig ScrewDriverConfig { get { lock (_sync) { return _screwDriverConfig; } } }
  79. private ISystemDatabaseService _systemDatabaseService;
  80. // ˢ��������
  81. private SerialPortConfig _cardReaderConfig;
  82. private TorqueSerialPortConfig _torqueReaderConfig;
  83. /// <summary>
  84. /// ע��ϵͳ���ݿ���񣨿�ѡ�������ڼ�¼��˿���α���ȼ�¼��
  85. /// </summary>
  86. /// <param name="svc"></param>
  87. public void SetSystemDatabaseService(ISystemDatabaseService svc)
  88. {
  89. lock (_sync)
  90. {
  91. _systemDatabaseService = svc;
  92. }
  93. }
  94. /// <summary>
  95. /// ��ʼ��һ���µ� <see cref="ConfigService"/> ʵ����
  96. /// ���캯�������Զ����������ļ��������ڹ����ڼ���� I/O ���������ɵ��� <see cref="LoadAll"/> �� <see cref="LoadAllAsync"/> ��ʽ���ء�
  97. /// </summary>
  98. public ConfigService()
  99. {
  100. //LoadAll();
  101. }
  102. /// <summary>
  103. /// ͬ���������������ļ����ڴ棨����Ӧ�ļ������ڣ�������Ĭ�Ͽռ���/����д���ļ�����
  104. /// �̰߳�ȫ�������ڲ��Թ�����Դʹ�� <see cref="_sync"/> ������
  105. /// </summary>
  106. public void LoadAll()
  107. {
  108. lock (_sync)
  109. {
  110. // ��ȡ�����ã�����ļ������ڣ��򱣳� DeviceConfig Ĭ��ֵ
  111. if (File.Exists(ConfigPaths.CamerasConfigurationPath))
  112. Cameras = FileHelper.ReadJsonFile<ObservableCollection<CameraInfo>>(ConfigPaths.CamerasConfigurationPath);
  113. else
  114. {
  115. Cameras = new ObservableCollection<CameraInfo>();
  116. FileHelper.WriteJsonFile(Cameras, ConfigPaths.CamerasConfigurationPath);
  117. }
  118. if (File.Exists(ConfigPaths.RobotsConfigurationPath))
  119. Robots = FileHelper.ReadJsonFile<ObservableCollection<RobotInfo>>(ConfigPaths.RobotsConfigurationPath);
  120. else
  121. {
  122. Robots = new ObservableCollection<RobotInfo>();
  123. FileHelper.WriteJsonFile(Robots, ConfigPaths.RobotsConfigurationPath);
  124. }
  125. if (File.Exists(ConfigPaths.FeedersConfigurationPath))
  126. Feeders = FileHelper.ReadJsonFile<ObservableCollection<FeederInfo>>(ConfigPaths.FeedersConfigurationPath);
  127. else
  128. {
  129. Feeders = new ObservableCollection<FeederInfo>();
  130. FileHelper.WriteJsonFile(Feeders, ConfigPaths.FeedersConfigurationPath);
  131. }
  132. // load screw feeders (material) configuration
  133. if (File.Exists(ConfigPaths.ScrewFeedersConfigurationPath))
  134. ScrewFeeders = FileHelper.ReadJsonFile<ObservableCollection<ScrewFeederInfo>>(ConfigPaths.ScrewFeedersConfigurationPath);
  135. else
  136. {
  137. ScrewFeeders = new ObservableCollection<ScrewFeederInfo>();
  138. FileHelper.WriteJsonFile(ScrewFeeders, ConfigPaths.ScrewFeedersConfigurationPath);
  139. }
  140. if (File.Exists(ConfigPaths.PlcConfigurationPath))
  141. Plcs = FileHelper.ReadJsonFile<ObservableCollection<PlcInfo>>(ConfigPaths.PlcConfigurationPath);
  142. else
  143. {
  144. Plcs = new ObservableCollection<PlcInfo>();
  145. FileHelper.WriteJsonFile(Plcs, ConfigPaths.PlcConfigurationPath);
  146. }
  147. if (File.Exists(ConfigPaths.BgTcpIpConfigurationPath))
  148. BgCommunicate = FileHelper.ReadJsonFile<BgTcpIP>(ConfigPaths.BgTcpIpConfigurationPath);
  149. else
  150. {
  151. BgCommunicate = new BgTcpIP();
  152. FileHelper.WriteJsonFile(BgCommunicate, ConfigPaths.BgTcpIpConfigurationPath);
  153. }
  154. if (File.Exists(ConfigPaths.BgModbusTcpConfigurationPath))
  155. BgModbusCommunicate = FileHelper.ReadJsonFile<BgModbusTcp>(ConfigPaths.BgModbusTcpConfigurationPath);
  156. else
  157. {
  158. BgModbusCommunicate = new BgModbusTcp();
  159. FileHelper.WriteJsonFile(BgModbusCommunicate, ConfigPaths.BgModbusTcpConfigurationPath);
  160. }
  161. if (!File.Exists(ConfigPaths.FeederClearanceTasksConfigurationPath))
  162. {
  163. FeederClearanceTasks = new ObservableCollection<FeederClearWork>();
  164. FileHelper.WriteJsonFile(FeederClearanceTasks, ConfigPaths.FeederClearanceTasksConfigurationPath);
  165. }
  166. else
  167. {
  168. // ��ȡ Feeder�������� ����
  169. FeederClearanceTasks = FileHelper.ReadJsonFile<ObservableCollection<FeederClearWork>>(ConfigPaths.FeederClearanceTasksConfigurationPath);
  170. }
  171. // ��ȡ��Դ����������
  172. if (!File.Exists(ConfigPaths.LightControllersConfigurationPath))
  173. {
  174. LightControllers = new ObservableCollection<LightControllerConfig>();
  175. FileHelper.WriteJsonFile(LightControllers, ConfigPaths.LightControllersConfigurationPath);
  176. }
  177. else
  178. {
  179. LightControllers = FileHelper.ReadJsonFile<ObservableCollection<LightControllerConfig>>(ConfigPaths.LightControllersConfigurationPath);
  180. }
  181. // load plc addresses
  182. var plcAddressPath = "..//Config//PlcAddressConfiguration.cfg";
  183. if (File.Exists(plcAddressPath))
  184. PlcAddressConfig = FileHelper.ReadJsonFile<PlcAddressConfig>(plcAddressPath);
  185. else
  186. {
  187. PlcAddressConfig = new PlcAddressConfig();
  188. PlcAddressConfig.SetDefaultValue();
  189. FileHelper.WriteJsonFile(PlcAddressConfig, plcAddressPath);
  190. }
  191. // load screw driver config (single device)
  192. if (File.Exists(ConfigPaths.ScrewDriverConfigurationPath))
  193. _screwDriverConfig = FileHelper.ReadJsonFile<TeamAAS_VP.Models.ScrewDriver.ScrewDriverConfig>(ConfigPaths.ScrewDriverConfigurationPath);
  194. else
  195. {
  196. _screwDriverConfig = new TeamAAS_VP.Models.ScrewDriver.ScrewDriverConfig();
  197. FileHelper.WriteJsonFile(_screwDriverConfig, ConfigPaths.ScrewDriverConfigurationPath);
  198. }
  199. // load device info list (支持多设备)
  200. if (File.Exists(ConfigPaths.DeviceInfoConfigurationPath))
  201. {
  202. try
  203. {
  204. // 尝试作为列表读取
  205. _deviceInfoList = FileHelper.ReadJsonFile<List<DeviceInfo>>(ConfigPaths.DeviceInfoConfigurationPath);
  206. }
  207. catch
  208. {
  209. // 兼容旧版单个 DeviceInfo,将其转换为列表
  210. var singleDevice = FileHelper.ReadJsonFile<DeviceInfo>(ConfigPaths.DeviceInfoConfigurationPath);
  211. if (singleDevice != null)
  212. {
  213. singleDevice.DeviceNo = 0;
  214. _deviceInfoList = new List<DeviceInfo> { singleDevice };
  215. }
  216. else
  217. {
  218. _deviceInfoList = new List<DeviceInfo> { new DeviceInfo { DeviceNo = 0 } };
  219. }
  220. FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
  221. }
  222. }
  223. else
  224. {
  225. _deviceInfoList = new List<DeviceInfo> { new DeviceInfo { DeviceNo = 0 } };
  226. FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
  227. }
  228. // load card reader configuration
  229. if (File.Exists(ConfigPaths.CardReaderConfigurationPath))
  230. _cardReaderConfig = FileHelper.ReadJsonFile<SerialPortConfig>(ConfigPaths.CardReaderConfigurationPath);
  231. else
  232. {
  233. _cardReaderConfig = new SerialPortConfig();
  234. FileHelper.WriteJsonFile(_cardReaderConfig, ConfigPaths.CardReaderConfigurationPath);
  235. }
  236. if (File.Exists(ConfigPaths.DataConfigurationPath))
  237. CtqData = FileHelper.ReadJsonFile<CTQ_Data>(ConfigPaths.DataConfigurationPath);
  238. else
  239. {
  240. CtqData = new CTQ_Data();
  241. FileHelper.WriteJsonFile(CtqData, ConfigPaths.DataConfigurationPath);
  242. }
  243. }
  244. }
  245. /// <summary>
  246. /// �첽ִ�� <see cref="LoadAll"/> ������
  247. /// </summary>
  248. /// <returns>��ʾ�첽���ز���������</returns>
  249. public Task LoadAllAsync()
  250. {
  251. return Task.Run(() => LoadAll());
  252. }
  253. /// <summary>
  254. /// ���ڴ��е���������д�ص���Ӧ�����ļ���
  255. /// �̰߳�ȫ�������ڲ���д�����ʹ�� <see cref="_sync"/> ������
  256. /// </summary>
  257. public void SaveAll()
  258. {
  259. lock (_sync)
  260. {
  261. FileHelper.WriteJsonFile(Cameras, ConfigPaths.CamerasConfigurationPath);
  262. FileHelper.WriteJsonFile(Robots, ConfigPaths.RobotsConfigurationPath);
  263. FileHelper.WriteJsonFile(Feeders, ConfigPaths.FeedersConfigurationPath);
  264. FileHelper.WriteJsonFile(Plcs, ConfigPaths.PlcConfigurationPath);
  265. FileHelper.WriteJsonFile(BgCommunicate, ConfigPaths.BgTcpIpConfigurationPath);
  266. FileHelper.WriteJsonFile(BgModbusCommunicate, ConfigPaths.BgModbusTcpConfigurationPath);
  267. FileHelper.WriteJsonFile(FeederClearanceTasks, ConfigPaths.FeederClearanceTasksConfigurationPath);
  268. FileHelper.WriteJsonFile(LightControllers, ConfigPaths.LightControllersConfigurationPath);
  269. // save screw driver config
  270. if (_screwDriverConfig != null)
  271. FileHelper.WriteJsonFile(_screwDriverConfig, ConfigPaths.ScrewDriverConfigurationPath);
  272. // save screw feeders
  273. if (ScrewFeeders != null)
  274. FileHelper.WriteJsonFile(ScrewFeeders, ConfigPaths.ScrewFeedersConfigurationPath);
  275. // save plc addresses
  276. //FileHelper.WriteJsonFile(PlcAddressConfig, "..//Config//PlcAddressConfiguration.cfg");
  277. // save device info list (支持多设备)
  278. if (_deviceInfoList != null)
  279. FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
  280. // save card reader config
  281. if (_cardReaderConfig != null)
  282. FileHelper.WriteJsonFile(_cardReaderConfig, ConfigPaths.CardReaderConfigurationPath);
  283. if (CtqData != null)
  284. FileHelper.WriteJsonFile(CtqData, ConfigPaths.DataConfigurationPath);
  285. }
  286. }
  287. /// <summary>
  288. /// �첽ִ�� <see cref="SaveAll"/> ������
  289. /// </summary>
  290. /// <returns>��ʾ�첽�������������</returns>
  291. public Task SaveAllAsync()
  292. {
  293. return Task.Run(() => SaveAll());
  294. }
  295. #region Cameras
  296. /// <summary>
  297. /// ��ȡ����������õ�ֻ�����ϡ�
  298. /// �̰߳�ȫ�����ڲ������Ա�֤������ȡ��һ���ԡ�
  299. /// </summary>
  300. /// <returns>������õ�ֻ�����ϡ�</returns>
  301. public IReadOnlyCollection<CameraInfo> GetAllCameras()
  302. {
  303. lock (_sync) { return Cameras.ToList().AsReadOnly(); }
  304. }
  305. /// <summary>
  306. /// ���ݱ�ʶ��ȡ�������������Ϣ��
  307. /// </summary>
  308. /// <param name="id">����� Guid ��ʶ��</param>
  309. /// <returns>�ҵ��򷵻ض�Ӧ�� <see cref="CameraInfo"/>�����򷵻� <c>null</c>��</returns>
  310. public CameraInfo GetCamera(Guid id)
  311. {
  312. lock (_sync) { return Cameras.FirstOrDefault(c => c.Id == id); }
  313. }
  314. /// <summary>
  315. /// ���������������á�
  316. /// - ������ <paramref name="camera"/> Ϊ <c>null</c> ���� <c>null</c>��
  317. /// - �� Id �Ѵ������滻������׷�Ӳ����������� CameraNo ��š�
  318. /// ����������Ὣ������ϳ־û��������ļ���
  319. /// </summary>
  320. /// <param name="camera">Ҫ���ӻ���µ�������á�</param>
  321. /// <returns>�����ӻ���µ� <see cref="CameraInfo"/>������Ϊ <c>null</c> ʱ���� <c>null</c>��</returns>
  322. public CameraInfo AddOrUpdateCamera(CameraInfo camera)
  323. {
  324. if (camera == null) return null;
  325. lock (_sync)
  326. {
  327. var exist = Cameras.FirstOrDefault(c => c.Id == camera.Id);
  328. if (exist != null)
  329. {
  330. var idx = Cameras.IndexOf(exist);
  331. Cameras[idx] = camera;
  332. }
  333. else
  334. {
  335. camera.CameraNo = Cameras.Count + 1;
  336. Cameras.Add(camera);
  337. }
  338. }
  339. FileHelper.WriteJsonFile(Cameras, ConfigPaths.CamerasConfigurationPath);
  340. return camera;
  341. }
  342. /// <summary>
  343. /// ���ݱ�ʶ�Ƴ�������ò����±��ʣ������� CameraNo��
  344. /// ����������Ὣ������ϳ־û��������ļ���
  345. /// </summary>
  346. /// <param name="id">Ҫ�Ƴ������ Guid��</param>
  347. /// <returns>���ҵ����ɹ��Ƴ����� <c>true</c>�����򷵻� <c>false</c>��</returns>
  348. public bool RemoveCamera(Guid id)
  349. {
  350. bool result = false;
  351. lock (_sync)
  352. {
  353. var exist = Cameras.FirstOrDefault(c => c.Id == id);
  354. if (exist != null) result = Cameras.Remove(exist);
  355. //���±��
  356. int no = 1;
  357. //�����������CameraNo����
  358. var sortedCameras = Cameras.OrderBy(c => c.CameraNo).ToList();
  359. foreach (var cam in sortedCameras)
  360. {
  361. cam.CameraNo = no;
  362. no++;
  363. }
  364. Cameras.Clear();
  365. foreach (var cam in sortedCameras)
  366. {
  367. Cameras.Add(cam);
  368. }
  369. }
  370. FileHelper.WriteJsonFile(Cameras, ConfigPaths.CamerasConfigurationPath);
  371. return result;
  372. }
  373. /// <summary>
  374. /// ����Ƿ����ָ�� Id ��������á�
  375. /// </summary>
  376. /// <param name="id">����� Guid��</param>
  377. /// <returns>���ڷ��� <c>true</c>�����򷵻� <c>false</c>��</returns>
  378. public bool ContainsCamera(Guid id) { lock (_sync) { return Cameras.Any(c => c.Id == id); } }
  379. #endregion
  380. #region DeviceInfo
  381. /// <summary>
  382. /// 获取所有设备信息配置列表
  383. /// </summary>
  384. /// <returns>设备信息列表的只读集合</returns>
  385. public IReadOnlyCollection<DeviceInfo> GetAllDeviceInfos()
  386. {
  387. lock (_sync)
  388. {
  389. if (_deviceInfoList == null)
  390. {
  391. if (File.Exists(ConfigPaths.DeviceInfoConfigurationPath))
  392. {
  393. try
  394. {
  395. _deviceInfoList = FileHelper.ReadJsonFile<List<DeviceInfo>>(ConfigPaths.DeviceInfoConfigurationPath);
  396. }
  397. catch
  398. {
  399. // 兼容旧版单个 DeviceInfo
  400. var singleDevice = FileHelper.ReadJsonFile<DeviceInfo>(ConfigPaths.DeviceInfoConfigurationPath);
  401. if (singleDevice != null)
  402. {
  403. singleDevice.DeviceNo = 0;
  404. _deviceInfoList = new List<DeviceInfo> { singleDevice };
  405. }
  406. else
  407. {
  408. _deviceInfoList = new List<DeviceInfo> { new DeviceInfo { DeviceNo = 0 } };
  409. }
  410. FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
  411. }
  412. }
  413. else
  414. {
  415. _deviceInfoList = new List<DeviceInfo> { new DeviceInfo { DeviceNo = 0 } };
  416. FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
  417. }
  418. }
  419. return _deviceInfoList.AsReadOnly();
  420. }
  421. }
  422. /// <summary>
  423. /// 根据设备编号获取设备信息(兼容旧API,返回第一个设备)
  424. /// </summary>
  425. /// <returns>设备信息,若不存在则创建默认设备</returns>
  426. public DeviceInfo GetDeviceInfo()
  427. {
  428. return GetDeviceInfo(0);
  429. }
  430. /// <summary>
  431. /// 根据设备编号获取设备信息
  432. /// </summary>
  433. /// <param name="deviceNo">设备编号</param>
  434. /// <returns>设备信息,若不存在则返回 null</returns>
  435. public DeviceInfo GetDeviceInfo(int deviceNo)
  436. {
  437. lock (_sync)
  438. {
  439. var allDevices = GetAllDeviceInfos();
  440. return allDevices.FirstOrDefault(d => d.DeviceNo == deviceNo);
  441. }
  442. }
  443. /// <summary>
  444. /// 添加或更新设备信息
  445. /// </summary>
  446. /// <param name="deviceInfo">设备信息对象</param>
  447. public void SaveDeviceInfo(DeviceInfo deviceInfo)
  448. {
  449. if (deviceInfo == null) return;
  450. lock (_sync)
  451. {
  452. // 确保列表已初始化
  453. if (_deviceInfoList == null)
  454. {
  455. _deviceInfoList = new List<DeviceInfo>();
  456. }
  457. // 查找是否已存在相同设备编号的设备
  458. var existing = _deviceInfoList.FirstOrDefault(d => d.DeviceNo == deviceInfo.DeviceNo);
  459. if (existing != null)
  460. {
  461. // 更新现有设备
  462. var index = _deviceInfoList.IndexOf(existing);
  463. _deviceInfoList[index] = deviceInfo;
  464. }
  465. else
  466. {
  467. // 添加新设备
  468. _deviceInfoList.Add(deviceInfo);
  469. }
  470. // 按设备编号排序
  471. _deviceInfoList = _deviceInfoList.OrderBy(d => d.DeviceNo).ToList();
  472. FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
  473. }
  474. }
  475. /// <summary>
  476. /// 保存所有设备信息列表
  477. /// </summary>
  478. /// <param name="deviceInfoList">设备信息列表</param>
  479. public void SaveAllDeviceInfos(IEnumerable<DeviceInfo> deviceInfoList)
  480. {
  481. if (deviceInfoList == null) return;
  482. lock (_sync)
  483. {
  484. _deviceInfoList = deviceInfoList.OrderBy(d => d.DeviceNo).ToList();
  485. FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
  486. }
  487. }
  488. /// <summary>
  489. /// 添加新设备
  490. /// </summary>
  491. /// <returns>新添加的设备</returns>
  492. public DeviceInfo AddDeviceInfo()
  493. {
  494. lock (_sync)
  495. {
  496. if (_deviceInfoList == null)
  497. {
  498. _deviceInfoList = new List<DeviceInfo>();
  499. }
  500. // 计算新设备编号
  501. int newDeviceNo = _deviceInfoList.Count > 0 ? _deviceInfoList.Max(d => d.DeviceNo) + 1 : 0;
  502. var newDevice = new DeviceInfo { DeviceNo = newDeviceNo };
  503. _deviceInfoList.Add(newDevice);
  504. FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
  505. return newDevice;
  506. }
  507. }
  508. /// <summary>
  509. /// 删除设备
  510. /// </summary>
  511. /// <param name="deviceNo">设备编号</param>
  512. /// <returns>是否删除成功</returns>
  513. public bool RemoveDeviceInfo(int deviceNo)
  514. {
  515. lock (_sync)
  516. {
  517. if (_deviceInfoList == null) return false;
  518. var device = _deviceInfoList.FirstOrDefault(d => d.DeviceNo == deviceNo);
  519. if (device != null)
  520. {
  521. _deviceInfoList.Remove(device);
  522. FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
  523. return true;
  524. }
  525. return false;
  526. }
  527. }
  528. #endregion
  529. #region CTQData
  530. /// <summary>
  531. /// ��ȡCTQ��Ϣ����
  532. /// </summary>
  533. public CTQ_Data GetCTQDataInfo()
  534. {
  535. lock (_sync)
  536. {
  537. if (CtqData == null)
  538. {
  539. if (File.Exists(ConfigPaths.DataConfigurationPath))
  540. CtqData = FileHelper.ReadJsonFile<CTQ_Data>(ConfigPaths.DataConfigurationPath);
  541. else
  542. {
  543. CtqData = new CTQ_Data();
  544. FileHelper.WriteJsonFile(CtqData, ConfigPaths.DataConfigurationPath);
  545. }
  546. }
  547. return CtqData;
  548. }
  549. }
  550. /// <summary>
  551. /// ����CTQ��Ϣ
  552. /// </summary>
  553. public void SaveCTQDataInfo(CTQ_Data cd)
  554. {
  555. if (cd == null) return;
  556. lock (_sync)
  557. {
  558. CtqData = cd;
  559. FileHelper.WriteJsonFile(CtqData, ConfigPaths.DataConfigurationPath);
  560. }
  561. }
  562. #endregion
  563. #region Robots
  564. /// <summary>
  565. /// ��ȡ���л��������õ�ֻ�����ϡ�
  566. /// </summary>
  567. /// <returns>���������õ�ֻ�����ϡ�</returns>
  568. public IReadOnlyCollection<RobotInfo> GetAllRobots() { lock (_sync) { return Robots.ToList().AsReadOnly(); } }
  569. /// <summary>
  570. /// ���ݱ�ʶ��ȡ�������������á�
  571. /// </summary>
  572. /// <param name="id">�����˵� Guid ��ʶ��</param>
  573. /// <returns>�ҵ��򷵻ض�Ӧ�� <see cref="RobotInfo"/>�����򷵻� <c>null</c>��</returns>
  574. public RobotInfo GetRobot(Guid id) { lock (_sync) { return Robots.FirstOrDefault(r => r.Id == id); } }
  575. /// <summary>
  576. /// ��������»��������ã�������־û��������ļ���
  577. /// ����ʱΪ�����˷��������� RobotNo ��š�
  578. /// </summary>
  579. /// <param name="robot">Ҫ���ӻ���µĻ��������á�</param>
  580. /// <returns>�����ӻ���µ� <see cref="RobotInfo"/>������Ϊ <c>null</c> ʱ���� <c>null</c>��</returns>
  581. public RobotInfo AddOrUpdateRobot(RobotInfo robot)
  582. {
  583. if (robot == null) return null;
  584. lock (_sync)
  585. {
  586. var exist = Robots.FirstOrDefault(r => r.Id == robot.Id);
  587. if (exist != null)
  588. {
  589. var idx = Robots.IndexOf(exist);
  590. Robots[idx] = robot;
  591. }
  592. else
  593. {
  594. robot.RobotNo = Robots.Count + 1;
  595. Robots.Add(robot);
  596. }
  597. }
  598. FileHelper.WriteJsonFile(Robots, ConfigPaths.RobotsConfigurationPath);
  599. return robot;
  600. }
  601. /// <summary>
  602. /// ���ݱ�ʶ�Ƴ����������ò����±��ʣ������ˡ�
  603. /// ������־û������ļ���
  604. /// </summary>
  605. /// <param name="id">Ҫ�Ƴ��Ļ����� Guid��</param>
  606. /// <returns>�Ƴ��ɹ����� <c>true</c>�����򷵻� <c>false</c>��</returns>
  607. public bool RemoveRobot(Guid id)
  608. {
  609. bool result = false;
  610. lock (_sync)
  611. {
  612. var e = Robots.FirstOrDefault(r => r.Id == id);
  613. if (e != null)
  614. result = Robots.Remove(e);
  615. //���±��
  616. int no = 1;
  617. //�����л����˰�RobotNo����
  618. var sortedRobots = Robots.OrderBy(r => r.RobotNo).ToList();
  619. foreach (var r in sortedRobots)
  620. {
  621. r.RobotNo = no;
  622. no++;
  623. }
  624. Robots.Clear();
  625. foreach (var r in sortedRobots)
  626. {
  627. Robots.Add(r);
  628. }
  629. }
  630. FileHelper.WriteJsonFile(Robots, ConfigPaths.RobotsConfigurationPath);
  631. return result;
  632. }
  633. /// <summary>
  634. /// �ж��Ƿ����ָ�� Id �Ļ��������á�
  635. /// </summary>
  636. /// <param name="id">�����˵� Guid��</param>
  637. /// <returns>���ڷ��� <c>true</c>�����򷵻� <c>false</c>��</returns>
  638. public bool ContainsRobot(Guid id) { lock (_sync) { return Robots.Any(r => r.Id == id); } }
  639. /// <summary>
  640. /// �޸�ָ�������� Id�IJ������벢�־û����������á�
  641. /// </summary>
  642. /// <param name="id">������Ψһ��ʶ����</param>
  643. /// <param name="stepDistance">�������롣</param>
  644. /// <returns>���³ɹ����� <c>true</c>���Ҳ��������˷��� <c>false</c>��</returns>
  645. public bool UpdateRobotStepDistance(Guid id, double stepDistance)
  646. {
  647. lock (_sync)
  648. {
  649. var robot = Robots.FirstOrDefault(r => r.Id == id);
  650. if (robot != null)
  651. {
  652. robot.StepDistance = stepDistance;
  653. FileHelper.WriteJsonFile(Robots, ConfigPaths.RobotsConfigurationPath);
  654. return true;
  655. }
  656. else
  657. {
  658. return false;
  659. }
  660. }
  661. }
  662. /// <summary>
  663. /// ��ȡָ�������� Id �IJ������롣
  664. /// </summary>
  665. /// <param name="id">������ Guid��</param>
  666. /// <returns>���ҵ��򷵻ض�Ӧ�IJ������룬���򷵻�Ĭ��ֵ 1.0��</returns>
  667. public double GetRobotStepDistance(Guid id)
  668. {
  669. lock (_sync)
  670. {
  671. var robot = Robots.FirstOrDefault(r => r.Id == id);
  672. if (robot != null)
  673. {
  674. return robot.StepDistance;
  675. }
  676. else
  677. {
  678. return 1.0;
  679. }
  680. }
  681. }
  682. #endregion
  683. #region Feeders
  684. /// <summary>
  685. /// ��ȡ���й��������õ�ֻ�����ϡ�
  686. /// </summary>
  687. /// <returns>���������õ�ֻ�����ϡ�</returns>
  688. public IReadOnlyCollection<FeederInfo> GetAllFeeders() { lock (_sync) { return Feeders.ToList().AsReadOnly(); } }
  689. /// <summary>
  690. /// ���ݱ�ʶ��ȡ�������������á�
  691. /// </summary>
  692. /// <param name="id">�������� Guid ��ʶ��</param>
  693. /// <returns>�ҵ��򷵻ض�Ӧ�� <see cref="FeederInfo"/>�����򷵻� <c>null</c>��</returns>
  694. public FeederInfo GetFeeder(Guid id) { lock (_sync) { return Feeders.FirstOrDefault(f => f.Id == id); } }
  695. /// <summary>
  696. /// ��������¹��������ã�������־û��������ļ���
  697. /// ����ʱΪ���������������� FeederNo ��š�
  698. /// </summary>
  699. /// <param name="feeder">Ҫ���ӻ���µĹ��������á�</param>
  700. /// <returns>�����ӻ���µ� <see cref="FeederInfo"/>������Ϊ <c>null</c> ʱ���� <c>null</c>��</returns>
  701. public FeederInfo AddOrUpdateFeeder(FeederInfo feeder)
  702. {
  703. if (feeder == null) return null;
  704. lock (_sync)
  705. {
  706. var exist = Feeders.FirstOrDefault(f => f.Id == feeder.Id);
  707. if (exist != null)
  708. {
  709. var idx = Feeders.IndexOf(exist);
  710. Feeders[idx] = feeder;
  711. }
  712. else
  713. {
  714. feeder.FeederNo = Feeders.Count + 1;
  715. Feeders.Add(feeder);
  716. }
  717. }
  718. FileHelper.WriteJsonFile(Feeders, ConfigPaths.FeedersConfigurationPath);
  719. return feeder;
  720. }
  721. /// <summary>
  722. /// ���ݱ�ʶ�Ƴ����������ò����±��ʣ�๩������
  723. /// ������־û������ļ���
  724. /// </summary>
  725. /// <param name="id">Ҫ�Ƴ��Ĺ����� Guid��</param>
  726. /// <returns>�Ƴ��ɹ����� <c>true</c>�����򷵻� <c>false</c>��</returns>
  727. public bool RemoveFeeder(Guid id)
  728. {
  729. bool result = false;
  730. lock (_sync)
  731. {
  732. var e = Feeders.FirstOrDefault(f => f.Id == id);
  733. if (e != null) result = Feeders.Remove(e);
  734. //���±��
  735. int no = 1;
  736. //�����������FeederNo����
  737. var sortedFeeders = Feeders.OrderBy(f => f.FeederNo).ToList();
  738. foreach (var f in sortedFeeders)
  739. {
  740. f.FeederNo = no;
  741. no++;
  742. }
  743. Feeders.Clear();
  744. foreach (var f in sortedFeeders)
  745. {
  746. Feeders.Add(f);
  747. }
  748. }
  749. FileHelper.WriteJsonFile(Feeders, ConfigPaths.FeedersConfigurationPath);
  750. return result;
  751. }
  752. /// <summary>
  753. /// �ж��Ƿ����ָ�� Id �Ĺ��������á�
  754. /// </summary>
  755. /// <param name="id">������ Guid��</param>
  756. /// <returns>���ڷ��� <c>true</c>�����򷵻� <c>false</c>��</returns>
  757. public bool ContainsFeeder(Guid id) { lock (_sync) { return Feeders.Any(f => f.Id == id); } }
  758. #endregion
  759. #region PLC
  760. /// <summary>
  761. /// ��ȡ���� PLC ���õ�ֻ�����ϡ�
  762. /// </summary>
  763. /// <returns>PLC ���õ�ֻ�����ϡ�</returns>
  764. public IReadOnlyCollection<PlcInfo> GetAllPlcs() { lock (_sync) { return Plcs.ToList().AsReadOnly(); } }
  765. /// <summary>
  766. /// ���ݱ�ʶ��ȡ���� PLC ���á�
  767. /// </summary>
  768. /// <param name="id">PLC �� Guid ��ʶ��</param>
  769. /// <returns>ƥ��� <see cref="PlcInfo"/> ʵ�����Ҳ������� <c>null</c>��</returns>
  770. public PlcInfo GetPlc(Guid id) { lock (_sync) { return Plcs.FirstOrDefault(p => p.Id == id); } }
  771. /// <summary>
  772. /// ��������� PLC ���ã�������־û��������ļ�������ʱ�������� PlcNo ��š�
  773. /// </summary>
  774. /// <param name="plc">Ҫ���ӻ���µ� PLC ���á�</param>
  775. /// <returns>�����ӻ���µ� <see cref="PlcInfo"/>������Ϊ <c>null</c> ʱ���� <c>null</c>��</returns>
  776. public PlcInfo AddOrUpdatePlc(PlcInfo plc)
  777. {
  778. if (plc == null) return null;
  779. lock (_sync)
  780. {
  781. var exist = Plcs.FirstOrDefault(p => p.Id == plc.Id);
  782. if (exist != null)
  783. {
  784. var idx = Plcs.IndexOf(exist);
  785. Plcs[idx] = plc;
  786. }
  787. else
  788. {
  789. plc.PlcNo = Plcs.Count + 1;
  790. Plcs.Add(plc);
  791. }
  792. }
  793. FileHelper.WriteJsonFile(Plcs, ConfigPaths.PlcConfigurationPath);
  794. return plc;
  795. }
  796. /// <summary>
  797. /// ���ݱ�ʶ�Ƴ� PLC ���ò����±��ʣ�� PLC��
  798. /// ������־û������ļ���
  799. /// </summary>
  800. /// <param name="id">Ҫ�Ƴ��� PLC Guid��</param>
  801. /// <returns>�Ƴ��ɹ����� <c>true</c>�����򷵻� <c>false</c>��</returns>
  802. public bool RemovePlc(Guid id)
  803. {
  804. bool result = false;
  805. lock (_sync)
  806. {
  807. var e = Plcs.FirstOrDefault(p => p.Id == id);
  808. if (e != null) result = Plcs.Remove(e);
  809. //���±��
  810. int no = 1;
  811. //������PLC��PlcNo����
  812. var sortedPlcs = Plcs.OrderBy(p => p.PlcNo).ToList();
  813. foreach (var p in sortedPlcs)
  814. {
  815. p.PlcNo = no;
  816. no++;
  817. }
  818. Plcs.Clear();
  819. foreach (var p in sortedPlcs)
  820. {
  821. Plcs.Add(p);
  822. }
  823. }
  824. FileHelper.WriteJsonFile(Plcs, ConfigPaths.PlcConfigurationPath);
  825. return result;
  826. }
  827. /// <summary>
  828. /// �ж��Ƿ����ָ�� Id �� PLC ���á�
  829. /// </summary>
  830. /// <param name="id">PLC �� Guid��</param>
  831. /// <returns>���ڷ��� <c>true</c>�����򷵻� <c>false</c>��</returns>
  832. public bool ContainsPlc(Guid id) { lock (_sync) { return Plcs.Any(p => p.Id == id); } }
  833. #endregion
  834. #region BgTcp
  835. /// <summary>
  836. /// ��ȡ BG TCP/IP ͨ�����ã��ڴ���󣬿���Ϊ null����
  837. /// </summary>
  838. /// <returns>��ǰ�� <see cref="BgTcpIP"/> ���ö���</returns>
  839. public BgTcpIP GetBgTcp() { lock (_sync) { return BgCommunicate; } }
  840. /// <summary>
  841. /// ���� BG TCP/IP ͨ�����ã��������ڴ���󣬲����Զ��־û�����
  842. /// ����־û������ <see cref="SaveBgTcp"/>��
  843. /// </summary>
  844. /// <param name="cfg">�µ� <see cref="BgTcpIP"/> ���ö���</param>
  845. public void SetBgTcp(BgTcpIP cfg) { lock (_sync) { BgCommunicate = cfg; } }
  846. /// <summary>
  847. /// ����ǰ�ڴ��е� BG TCP/IP ���ó־û��������ļ���
  848. /// </summary>
  849. public void SaveBgTcp() { lock (_sync) { FileHelper.WriteJsonFile(BgCommunicate, ConfigPaths.BgTcpIpConfigurationPath); } }
  850. #endregion
  851. #region BgModbus
  852. /// <summary>
  853. /// ��ȡ BG Modbus TCP ͨ�����ã��ڴ���󣩡�
  854. /// </summary>
  855. /// <returns>��ǰ�� <see cref="BgModbusTcp"/> ���ö���</returns>
  856. public BgModbusTcp GetBgModbusTcp() { lock (_sync) { return BgModbusCommunicate; } }
  857. /// <summary>
  858. /// ���� BG Modbus TCP ͨ�����ã��������ڴ���󣬲����Զ��־û�����
  859. /// </summary>
  860. /// <param name="cfg">�µ� <see cref="BgModbusTcp"/> ���ö���</param>
  861. public void SetBgModbusTcp(BgModbusTcp cfg) { lock (_sync) { BgModbusCommunicate = cfg; } }
  862. /// <summary>
  863. /// ����ǰ�ڴ��е� BG Modbus TCP ���ó־û��������ļ���
  864. /// </summary>
  865. public void SaveBgModbusTcp() { lock (_sync) { FileHelper.WriteJsonFile(BgModbusCommunicate, ConfigPaths.BgModbusTcpConfigurationPath); } }
  866. #endregion
  867. #region ϵͳ����
  868. /// <summary>
  869. /// ��ȡϵͳ���ã��������ļ���ȡ����
  870. /// �̰߳�ȫ�������ڲ������Ա�֤��ȡһ���ԡ�
  871. /// </summary>
  872. /// <returns>��ȡ���� <see cref="SystemConfiguration"/> �������ļ��������򷵻�Ĭ�ϵ���ʵ����</returns>
  873. public SystemConfiguration GetSystemConfiguration()
  874. {
  875. lock (_sync)
  876. {
  877. var config = new SystemConfiguration();
  878. if (File.Exists(ConfigPaths.SystemConfigurationPath))
  879. {
  880. config = FileHelper.ReadJsonFile<SystemConfiguration>(ConfigPaths.SystemConfigurationPath);
  881. }
  882. return config;
  883. }
  884. }
  885. /// <summary>
  886. /// ����ϵͳ���õ������ļ����Ḳ�������ļ�����
  887. /// </summary>
  888. /// <param name="systemConfiguration">Ҫ�����ϵͳ���ö���</param>
  889. public void SaveSystemConfiguration(SystemConfiguration systemConfiguration)
  890. {
  891. lock (_sync)
  892. {
  893. FileHelper.WriteJsonFile(systemConfiguration, ConfigPaths.SystemConfigurationPath);
  894. }
  895. }
  896. /// <summary>
  897. /// ��ȡ��ǰ����
  898. /// </summary>
  899. /// <returns></returns>
  900. public Language GetCurrentLanguage()
  901. {
  902. lock (_sync)
  903. {
  904. var config = GetSystemConfiguration();
  905. return config.CurrentLanguage;
  906. }
  907. }
  908. /// <summary>
  909. /// ���õ�ǰ����
  910. /// </summary>
  911. /// <param name="language"></param>
  912. public void SetCurrentLanguage(Language language)
  913. {
  914. lock (_sync)
  915. {
  916. var config = GetSystemConfiguration();
  917. config.CurrentLanguage = language;
  918. if (language == Enums.Language.ChineseSimplified)
  919. {
  920. var culture = new CultureInfo("zh-CN");
  921. App.Current.Dispatcher.Thread.CurrentCulture = culture;
  922. App.Current.Dispatcher.Thread.CurrentUICulture = culture;
  923. LocalizeDictionary.Instance.Culture = culture;
  924. Lang.Culture = culture;
  925. System.Windows.Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Microsoft YaHei");
  926. }
  927. else if (language == Enums.Language.ChineseTraditional)
  928. {
  929. var culture = new CultureInfo("zh-TW");
  930. App.Current.Dispatcher.Thread.CurrentCulture = culture;
  931. App.Current.Dispatcher.Thread.CurrentUICulture = culture;
  932. LocalizeDictionary.Instance.Culture = culture;
  933. Lang.Culture = culture;
  934. System.Windows.Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Microsoft YaHei");
  935. }
  936. else if (language == Enums.Language.English)
  937. {
  938. var culture = new CultureInfo("en");
  939. App.Current.Dispatcher.Thread.CurrentCulture = culture;
  940. App.Current.Dispatcher.Thread.CurrentUICulture = culture;
  941. LocalizeDictionary.Instance.Culture = culture;
  942. Lang.Culture = culture;
  943. System.Windows.Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Segoe UI");
  944. }
  945. else if (language == Enums.Language.Japanese)
  946. {
  947. var culture = new CultureInfo("ja-JP");
  948. App.Current.Dispatcher.Thread.CurrentCulture = culture;
  949. App.Current.Dispatcher.Thread.CurrentUICulture = culture;
  950. LocalizeDictionary.Instance.Culture = culture;
  951. Lang.Culture = culture;
  952. System.Windows.Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Segoe UI");
  953. }
  954. SaveSystemConfiguration(config);
  955. }
  956. }
  957. #endregion
  958. #region Feeder��������
  959. /// <summary>
  960. /// ��ȡ�������������ֻ�����ϡ�
  961. /// </summary>
  962. /// <returns>���������ֻ�����ϡ�</returns>
  963. public IReadOnlyCollection<FeederClearWork> GetAllClearanceTasks() { lock (_sync) { return FeederClearanceTasks.ToList().AsReadOnly(); } }
  964. /// <summary>
  965. /// ���������������������ʱΪ������������ TaskCode����ɺ�־û������ļ���
  966. /// </summary>
  967. /// <param name="task">Ҫ���ӻ���µ������������</param>
  968. /// <returns>�����ӻ���µ� <see cref="FeederClearWork"/>������Ϊ <c>null</c> ʱ���� <c>null</c>��</returns>
  969. public FeederClearWork AddOrUpdateClearanceTask(FeederClearWork task)
  970. {
  971. if (task == null) return null;
  972. lock (_sync)
  973. {
  974. var exist = FeederClearanceTasks.FirstOrDefault(t => t.Id == task.Id);
  975. if (exist != null)
  976. {
  977. var idx = FeederClearanceTasks.IndexOf(exist);
  978. FeederClearanceTasks[idx] = task;
  979. }
  980. else
  981. {
  982. // ����������Ϊ��ǰ����ż�1
  983. task.TaskCode = FeederClearanceTasks.Count > 0 ? FeederClearanceTasks.Max(t => t.TaskCode) + 1 : 1;
  984. FeederClearanceTasks.Add(task);
  985. }
  986. }
  987. FileHelper.WriteJsonFile(FeederClearanceTasks, ConfigPaths.FeederClearanceTasksConfigurationPath);
  988. return task;
  989. }
  990. /// <summary>
  991. /// ���ݱ�ʶ�Ƴ��������񲢳־û������ļ���
  992. /// </summary>
  993. /// <param name="id">Ҫ�Ƴ����������� Guid��</param>
  994. /// <returns>���ҵ����Ƴ����� <c>true</c>�����򷵻� <c>false</c>��</returns>
  995. public bool RemoveClearanceTask(Guid id)
  996. {
  997. lock (_sync)
  998. {
  999. var exist = FeederClearanceTasks.FirstOrDefault(t => t.Id == id);
  1000. if (exist != null)
  1001. {
  1002. FileHelper.WriteJsonFile(FeederClearanceTasks, ConfigPaths.FeederClearanceTasksConfigurationPath);
  1003. return FeederClearanceTasks.Remove(exist);
  1004. }
  1005. else
  1006. return false;
  1007. }
  1008. }
  1009. /// <summary>
  1010. /// ��������������񲢳־û��ռ��ϵ������ļ���
  1011. /// </summary>
  1012. public void ClearAllClearanceTasks()
  1013. {
  1014. lock (_sync)
  1015. {
  1016. FeederClearanceTasks.Clear();
  1017. }
  1018. FileHelper.WriteJsonFile(FeederClearanceTasks, ConfigPaths.FeederClearanceTasksConfigurationPath);
  1019. }
  1020. /// <summary>
  1021. /// �ж��Ƿ����ָ�� Id ����������
  1022. /// </summary>
  1023. /// <param name="id">�������� Guid��</param>
  1024. /// <returns>���ڷ��� <c>true</c>�����򷵻� <c>false</c>��</returns>
  1025. public bool ContainsClearanceTask(Guid id)
  1026. {
  1027. lock (_sync) { return FeederClearanceTasks.Any(t => t.Id == id); }
  1028. }
  1029. /// <summary>
  1030. /// ���ݱ�ʶ��ȡ��������������Ϣ��
  1031. /// </summary>
  1032. /// <param name="id">�������� Guid��</param>
  1033. /// <returns>ƥ��� <see cref="FeederClearWork"/>���Ҳ������� <c>null</c>��</returns>
  1034. public FeederClearWork GetClearanceTask(Guid id)
  1035. {
  1036. lock (_sync) { return FeederClearanceTasks.FirstOrDefault(t => t.Id == id); }
  1037. }
  1038. /// <summary>
  1039. /// �ж��Ƿ����ָ�������ŵ���������
  1040. /// </summary>
  1041. /// <param name="taskNumber">�����ţ�TaskCode����</param>
  1042. /// <returns>���ڷ��� <c>true</c>�����򷵻� <c>false</c>��</returns>
  1043. public bool ContainsClearanceTaskByNumber(int taskNumber)
  1044. {
  1045. lock (_sync) { return FeederClearanceTasks.Any(t => t.TaskCode == taskNumber); }
  1046. }
  1047. /// <summary>
  1048. /// ���������Ż�ȡ��������������Ϣ��
  1049. /// </summary>
  1050. /// <param name="taskNumber">�����ţ�TaskCode����</param>
  1051. /// <returns>ƥ��� <see cref="FeederClearWork"/>���Ҳ������� <c>null</c>��</returns>
  1052. public FeederClearWork GetClearanceTaskByNumber(int taskNumber)
  1053. {
  1054. lock (_sync) { return FeederClearanceTasks.FirstOrDefault(t => t.TaskCode == taskNumber); }
  1055. }
  1056. #endregion
  1057. #region Light controllers and channels
  1058. /// <summary>
  1059. /// ��ȡ���й�Դ���������õ�ֻ�����ϡ�
  1060. /// �̰߳�ȫ�����ڲ�ʹ�� <see cref="_sync"/> ���������Ա�֤�������ʰ�ȫ��
  1061. /// </summary>
  1062. /// <returns>����ǰ�ڴ��д洢˳�򷵻ص�ֻ�� <see cref="LightControllerConfig"/> ���ϡ�</returns>
  1063. public IReadOnlyCollection<LightControllerConfig> GetAllLightControllers()
  1064. {
  1065. lock (_sync) { return LightControllers.ToList().AsReadOnly(); }
  1066. }
  1067. /// <summary>
  1068. /// ���ݿ�������ʶ��ȡ������Դ���������á�
  1069. /// �̰߳�ȫ���÷������ڴ漯�Ͻ���ֻ�����ʲ����ڲ�������
  1070. /// </summary>
  1071. /// <param name="id">��������������ʶ��Id����</param>
  1072. /// <returns>ƥ��� <see cref="LightControllerConfig"/> ʵ�����Ҳ����򷵻� <c>null</c>��</returns>
  1073. public LightControllerConfig GetLightController(int id)
  1074. {
  1075. lock (_sync) { return LightControllers.FirstOrDefault(c => c.Id == id); }
  1076. }
  1077. /// <summary>
  1078. /// ��������¹�Դ���������á�
  1079. /// - �� <paramref name="controller"/> Ϊ <c>null</c> ���� <c>null</c>��
  1080. /// - ����ʱ�� Id ƥ��������滻��
  1081. /// - ����ʱ���������Ŀ����� Id����Ϊ�������ڵ�ÿ��ͨ������ȫ��ͨ����ţ�GlobalIndex����
  1082. /// �̰߳�ȫ�����ڲ�ʹ�� <see cref="_sync"/> �������ϡ�
  1083. /// </summary>
  1084. /// <param name="controller">Ҫ���ӻ���µ� <see cref="LightControllerConfig"/> ʵ����</param>
  1085. /// <returns>�����ӻ���µ� <see cref="LightControllerConfig"/> ʵ��������Ϊ <c>null</c> ʱ���� <c>null</c>��</returns>
  1086. /// <exception cref="ArgumentException">��Ҫ����/���µĿ��������������������������ظ�ʱ�׳���</exception>
  1087. public LightControllerConfig AddOrUpdateLightController(LightControllerConfig controller)
  1088. {
  1089. if (controller == null) return null;
  1090. lock (_sync)
  1091. {
  1092. // ���Ʋ����������������ظ���ͬ������ͬ Id ��������
  1093. if (LightControllers.Any(c => c.Name == controller.Name && c.Id != controller.Id))
  1094. throw new ArgumentException("Controller name must be unique");
  1095. var exist = LightControllers.FirstOrDefault(c => c.Id == controller.Id);
  1096. if (exist != null)
  1097. {
  1098. // �������п��������������滻��
  1099. var idx = LightControllers.IndexOf(exist);
  1100. LightControllers[idx] = controller;
  1101. }
  1102. else
  1103. {
  1104. // ����������
  1105. // ������������Ϊ��ǰ��� Id + 1��������Ϊ����Ϊ 1��
  1106. controller.Id = LightControllers.Count > 0 ? LightControllers.Max(c => c.Id) + 1 : 1;
  1107. // ������һ��ȫ��ͨ���������������Ѵ��ڿ�������ͨ�� GlobalIndex ��ȡ���ֵ����1
  1108. int nextGlobal = 0;
  1109. if (LightControllers.SelectMany(c => c.ChannelConfigs).Any())
  1110. {
  1111. nextGlobal = LightControllers.SelectMany(c => c.ChannelConfigs).Max(ch => ch.GlobalIndex) + 1;
  1112. }
  1113. // ����������������ͨ������ͨ���� GlobalIndex ��Ч��<0����������ͨ����ͻ�������·���
  1114. for (int i = 0; i < controller.ChannelConfigs.Count; i++)
  1115. {
  1116. var ch = controller.ChannelConfigs[i];
  1117. if (ch.GlobalIndex < 0 || LightControllers.SelectMany(c => c.ChannelConfigs).Any(existingCh => existingCh.GlobalIndex == ch.GlobalIndex))
  1118. {
  1119. ch.GlobalIndex = nextGlobal;
  1120. nextGlobal++;
  1121. }
  1122. }
  1123. LightControllers.Add(controller);
  1124. }
  1125. }
  1126. // �־û����º�Ĺ�Դ����������
  1127. FileHelper.WriteJsonFile(LightControllers, ConfigPaths.LightControllersConfigurationPath);
  1128. return controller;
  1129. }
  1130. /// <summary>
  1131. /// ���� Id �Ƴ���Դ���������ò���ʣ����������±�ţ��� 1 ��ʼ������ţ���
  1132. /// ������־û������ļ���
  1133. /// </summary>
  1134. /// <param name="id">Ҫ�Ƴ��Ŀ����� Id��</param>
  1135. /// <returns>����ɹ��Ƴ����� <c>true</c>�����򷵻� <c>false</c>������δ�ҵ��� Id����</returns>
  1136. public bool RemoveLightController(int id)
  1137. {
  1138. bool result = false;
  1139. lock (_sync)
  1140. {
  1141. var e = LightControllers.FirstOrDefault(c => c.Id == id);
  1142. if (e != null)
  1143. result = LightControllers.Remove(e);
  1144. // ���°� Id ���򲢴� 1 ��ʼ���±�ţ��Ա���������
  1145. int no = 1;
  1146. var sorted = LightControllers.OrderBy(c => c.Id).ToList();
  1147. foreach (var c in sorted)
  1148. {
  1149. c.Id = no;
  1150. no++;
  1151. }
  1152. LightControllers.Clear();
  1153. foreach (var c in sorted)
  1154. {
  1155. LightControllers.Add(c);
  1156. }
  1157. }
  1158. FileHelper.WriteJsonFile(LightControllers, ConfigPaths.LightControllersConfigurationPath);
  1159. return result;
  1160. }
  1161. /// <summary>
  1162. /// �ж��Ƿ����ָ�� Id �Ĺ�Դ��������
  1163. /// </summary>
  1164. /// <param name="id">������ Id��</param>
  1165. /// <returns>���ڷ��� <c>true</c>�����򷵻� <c>false</c>��</returns>
  1166. public bool ContainsLightController(int id) { lock (_sync) { return LightControllers.Any(c => c.Id == id); } }
  1167. /// <summary>
  1168. /// ��ȡ���й�Դͨ����ֻ�����ϣ��� GlobalIndex ���򷵻ء�
  1169. /// </summary>
  1170. /// <returns>�� GlobalIndex ����� <see cref="ChannelConfig"/> ֻ�����ϡ�</returns>
  1171. public IReadOnlyCollection<ChannelConfig> GetAllLightChannels()
  1172. {
  1173. lock (_sync) { return LightControllers.SelectMany(c => c.ChannelConfigs).OrderBy(ch => ch.GlobalIndex).ToList().AsReadOnly(); }
  1174. }
  1175. /// <summary>
  1176. /// ����ȫ��ͨ��������ȡ����ͨ�����á�
  1177. /// </summary>
  1178. /// <param name="globalIndex">ͨ����ȫ��������GlobalIndex����</param>
  1179. /// <returns>ƥ��� <see cref="ChannelConfig"/> ʵ�����Ҳ����򷵻� <c>null</c>��</returns>
  1180. public ChannelConfig GetLightChannelByGlobalIndex(int globalIndex)
  1181. {
  1182. lock (_sync) { return LightControllers.SelectMany(c => c.ChannelConfigs).FirstOrDefault(ch => ch.GlobalIndex == globalIndex); }
  1183. }
  1184. /// <summary>
  1185. /// �ж��Ƿ����ָ��ȫ��ͨ��������ͨ�����á�
  1186. /// </summary>
  1187. /// <param name="globalIndex">ȫ��ͨ��������</param>
  1188. /// <returns>���ڷ��� <c>true</c>�����򷵻� <c>false</c>��</returns>
  1189. public bool ContainsLightChannelByGlobalIndex(int globalIndex)
  1190. {
  1191. lock (_sync) { return LightControllers.SelectMany(c => c.ChannelConfigs).Any(ch => ch.GlobalIndex == globalIndex); }
  1192. }
  1193. /// <summary>
  1194. /// ����ָ��ȫ��ͨ����Ĭ�����ȣ�DefaultBrightness�������־û���Դ���������á�
  1195. /// </summary>
  1196. /// <param name="globalIndex">Ŀ��ͨ����ȫ��������GlobalIndex����</param>
  1197. /// <param name="brightness">Ҫ���õ�����ֵ��</param>
  1198. /// <returns>���³ɹ����� <c>true</c>���Ҳ�����Ӧͨ������ <c>false</c>��</returns>
  1199. public bool UpdateChannelDefaultBrightness(int globalIndex, int brightness)
  1200. {
  1201. lock (_sync)
  1202. {
  1203. var ch = LightControllers.SelectMany(c => c.ChannelConfigs).FirstOrDefault(x => x.GlobalIndex == globalIndex);
  1204. if (ch == null) return false;
  1205. ch.DefaultBrightness = brightness;
  1206. FileHelper.WriteJsonFile(LightControllers, ConfigPaths.LightControllersConfigurationPath);
  1207. return true;
  1208. }
  1209. }
  1210. #endregion
  1211. #region Plc Addresses
  1212. public PlcAddressConfig GetPlcAddresses() { lock (_sync) { return PlcAddressConfig; } }
  1213. #endregion
  1214. #region ScrewDriver config (single device)
  1215. /// <summary>
  1216. /// ��ȡ�������ã����豸����
  1217. /// </summary>
  1218. /// <returns>��ǰ�� <see cref="ScrewDriverConfig"/>����δ�����򷵻� null��</returns>
  1219. public ScrewDriverConfig GetScrewDriverConfig()
  1220. {
  1221. lock (_sync) { return _screwDriverConfig; }
  1222. }
  1223. /// <summary>
  1224. /// ���ò��־û��������ã����豸����
  1225. /// </summary>
  1226. /// <param name="cfg">�µ����ö��󣬲���Ϊ�ա�</param>
  1227. public void SetScrewDriverConfig(ScrewDriverConfig cfg)
  1228. {
  1229. if (cfg == null) throw new ArgumentNullException(nameof(cfg));
  1230. lock (_sync)
  1231. {
  1232. _screwDriverConfig = cfg;
  1233. FileHelper.WriteJsonFile(_screwDriverConfig, ConfigPaths.ScrewDriverConfigurationPath);
  1234. }
  1235. }
  1236. /// <summary>
  1237. /// ������ǰ�ڴ��еĵ������ñ��浽�ļ���
  1238. /// </summary>
  1239. public void SaveScrewDriverConfig()
  1240. {
  1241. lock (_sync)
  1242. {
  1243. if (_screwDriverConfig != null)
  1244. FileHelper.WriteJsonFile(_screwDriverConfig, ConfigPaths.ScrewDriverConfigurationPath);
  1245. }
  1246. }
  1247. #endregion
  1248. #region Screw Feeders (material)
  1249. /// <summary>
  1250. /// ��ȡ������˿���������õ�ֻ�����ϡ�
  1251. /// </summary>
  1252. public IReadOnlyCollection<ScrewFeederInfo> GetAllScrewFeeders() { lock (_sync) { return ScrewFeeders.ToList().AsReadOnly(); } }
  1253. /// <summary>
  1254. /// ���� Id ��ȡ������˿���������á�
  1255. /// </summary>
  1256. public ScrewFeederInfo GetScrewFeeder(Guid id) { lock (_sync) { return ScrewFeeders.FirstOrDefault(s => s.Id == id); } }
  1257. /// <summary>
  1258. /// �����������˿���������á�
  1259. /// ����ʱ��δָ�� FeederNumber �����Ϊ��ǰ����+1��
  1260. /// </summary>
  1261. public ScrewFeederInfo AddOrUpdateScrewFeeder(ScrewFeederInfo feeder)
  1262. {
  1263. if (feeder == null) return null;
  1264. lock (_sync)
  1265. {
  1266. var exist = ScrewFeeders.FirstOrDefault(f => f.Id == feeder.Id);
  1267. if (exist != null)
  1268. {
  1269. var idx = ScrewFeeders.IndexOf(exist);
  1270. ScrewFeeders[idx] = feeder;
  1271. }
  1272. else
  1273. {
  1274. if (feeder.FeederNumber <= 0) feeder.FeederNumber = ScrewFeeders.Count + 1;
  1275. ScrewFeeders.Add(feeder);
  1276. }
  1277. FileHelper.WriteJsonFile(ScrewFeeders, ConfigPaths.ScrewFeedersConfigurationPath);
  1278. }
  1279. return feeder;
  1280. }
  1281. /// <summary>
  1282. /// �Ƴ���˿���������á�
  1283. /// </summary>
  1284. public bool RemoveScrewFeeder(Guid id)
  1285. {
  1286. bool result = false;
  1287. lock (_sync)
  1288. {
  1289. var e = ScrewFeeders.FirstOrDefault(s => s.Id == id);
  1290. if (e != null) result = ScrewFeeders.Remove(e);
  1291. }
  1292. FileHelper.WriteJsonFile(ScrewFeeders, ConfigPaths.ScrewFeedersConfigurationPath);
  1293. return result;
  1294. }
  1295. public bool ContainsScrewFeeder(Guid id) { lock (_sync) { return ScrewFeeders.Any(s => s.Id == id); } }
  1296. // event for low level alarm
  1297. public event Action<ScrewFeederInfo> ScrewFeederLowLevelAlarmTriggered;
  1298. /// <summary>
  1299. /// ��ȡָ����������ŵ�ʣ����˿�������Ҳ������� -1��
  1300. /// </summary>
  1301. public int GetRemainingCountByFeederNumber(int feederNumber)
  1302. {
  1303. lock (_sync)
  1304. {
  1305. var f = ScrewFeeders.FirstOrDefault(s => s.FeederNumber == feederNumber);
  1306. if (f == null) return -1;
  1307. return f.RemainingCount;
  1308. }
  1309. }
  1310. /// <summary>
  1311. /// ��ȡָ����������ŵĵ�������״̬���Ҳ������� false��
  1312. /// </summary>
  1313. public bool GetLowLevelAlarmStatusByFeederNumber(int feederNumber)
  1314. {
  1315. lock (_sync)
  1316. {
  1317. var f = ScrewFeeders.FirstOrDefault(s => s.FeederNumber == feederNumber);
  1318. if (f == null) return false;
  1319. return f.IsLowLevelAlarmActive;
  1320. }
  1321. }
  1322. // helper: check and raise low level alarm when necessary
  1323. private void CheckAndTriggerLowLevelAlarm(ScrewFeederInfo f)
  1324. {
  1325. if (f == null) return;
  1326. if (f.LowLevelAlarmEnabled && f.RemainingCount <= f.LowLevelThreshold)
  1327. {
  1328. if (!f.IsLowLevelAlarmActive)
  1329. {
  1330. f.IsLowLevelAlarmActive = true;
  1331. try
  1332. {
  1333. ScrewFeederLowLevelAlarmTriggered?.Invoke(f.Clone());
  1334. }
  1335. catch { }
  1336. }
  1337. }
  1338. else
  1339. {
  1340. if (f.IsLowLevelAlarmActive)
  1341. {
  1342. f.IsLowLevelAlarmActive = false;
  1343. }
  1344. }
  1345. }
  1346. /// <summary>
  1347. /// Ϊָ����������ŵݼ�ָ�����������������㷵�� -1
  1348. /// </summary>
  1349. public int DecrementScrewCountByFeederNumber(int feederNumber, int decrement = 1)
  1350. {
  1351. lock (_sync)
  1352. {
  1353. var f = ScrewFeeders.FirstOrDefault(s => s.FeederNumber == feederNumber);
  1354. if (f == null) return -1;
  1355. if (decrement <= 0) decrement = 1;
  1356. if (f.RemainingCount < decrement) return -1;
  1357. f.RemainingCount -= decrement;
  1358. // check alarm
  1359. CheckAndTriggerLowLevelAlarm(f);
  1360. FileHelper.WriteJsonFile(ScrewFeeders, ConfigPaths.ScrewFeedersConfigurationPath);
  1361. return f.RemainingCount;
  1362. }
  1363. }
  1364. /// <summary>
  1365. /// ���ָ����������ŵ���˿��Ϣ�����κ��ÿգ�ʣ��������0��
  1366. /// </summary>
  1367. public void ClearScrewFeederByNumber(int feederNumber)
  1368. {
  1369. lock (_sync)
  1370. {
  1371. var f = ScrewFeeders.FirstOrDefault(s => s.FeederNumber == feederNumber);
  1372. if (f == null) return;
  1373. f.BatchNumber = string.Empty;
  1374. f.RemainingCount = 0;
  1375. // check alarm
  1376. CheckAndTriggerLowLevelAlarm(f);
  1377. FileHelper.WriteJsonFile(ScrewFeeders, ConfigPaths.ScrewFeedersConfigurationPath);
  1378. }
  1379. }
  1380. /// <summary>
  1381. /// Ϊָ������������������κţ�����ԭ��ʣ������������һ����PackSize��
  1382. /// </summary>
  1383. public void SetBatchForFeederNumber(int feederNumber, string batchNumber)
  1384. {
  1385. if (string.IsNullOrWhiteSpace(batchNumber)) return;
  1386. //��ȡ��ǰ�IJ���Ա�û���
  1387. string operatorName = _systemDatabaseService.GetCurrentUser()?.UserName;
  1388. // capture values under lock, then record to DB outside lock
  1389. ScrewFeederInfo target = null;
  1390. int remainingAfter = 0;
  1391. int packSize = 0;
  1392. string feederName = null;
  1393. int previousCount = 0;
  1394. lock (_sync)
  1395. {
  1396. var f = ScrewFeeders.FirstOrDefault(s => s.FeederNumber == feederNumber);
  1397. if (f == null) return;
  1398. f.BatchNumber = batchNumber;
  1399. previousCount = f.RemainingCount;
  1400. f.RemainingCount += Math.Max(0, f.PackSize);
  1401. // prepare capture values
  1402. target = f;
  1403. remainingAfter = f.RemainingCount;
  1404. packSize = f.PackSize;
  1405. feederName = f.Name;
  1406. // check alarm
  1407. CheckAndTriggerLowLevelAlarm(f);
  1408. FileHelper.WriteJsonFile(ScrewFeeders, ConfigPaths.ScrewFeedersConfigurationPath);
  1409. }
  1410. try
  1411. {
  1412. var record = new ScrewFeederBatchRecord
  1413. {
  1414. BatchNumber = batchNumber,
  1415. PackSize = packSize,
  1416. ChangeTime = DateTime.UtcNow,
  1417. RemainingCount = remainingAfter,
  1418. FeederNumber = feederNumber,
  1419. FeederName = feederName,
  1420. PreviousCount = previousCount,
  1421. OperatorName = operatorName,
  1422. };
  1423. // try get operator name from system database service if available
  1424. try
  1425. {
  1426. var user = _systemDatabaseService?.GetCurrentUser();
  1427. if (user != null)
  1428. record.OperatorName = user.UserName;
  1429. }
  1430. catch
  1431. {
  1432. // ignore getting user failure
  1433. }
  1434. try
  1435. {
  1436. if (_systemDatabaseService != null)
  1437. {
  1438. _ = _systemDatabaseService.RecordScrewFeederBatchAsync(record);
  1439. }
  1440. }
  1441. catch
  1442. {
  1443. // �������ݿ�д����󣬼�¼��������־
  1444. }
  1445. }
  1446. catch
  1447. {
  1448. // ignore any error creating/recording the batch record
  1449. }
  1450. }
  1451. /// <summary>
  1452. /// ���ʣ����˿�Ƿ񱨾�
  1453. /// </summary>
  1454. public bool CheckAlarm(int feederNumber)
  1455. {
  1456. lock (_sync)
  1457. {
  1458. var f = ScrewFeeders.FirstOrDefault(s => s.FeederNumber == feederNumber);
  1459. if (f == null) return false;
  1460. // check alarm
  1461. CheckAndTriggerLowLevelAlarm(f);
  1462. return f.IsLowLevelAlarmActive;
  1463. }
  1464. }
  1465. #endregion
  1466. #region �û���¼ˢ����
  1467. /// <summary>
  1468. /// ��ȡˢ��������
  1469. /// </summary>
  1470. /// <returns></returns>
  1471. public SerialPortConfig GetCardReaderConfig()
  1472. {
  1473. lock (_sync)
  1474. {
  1475. if (_cardReaderConfig != null)
  1476. return _cardReaderConfig;
  1477. if (File.Exists(ConfigPaths.CardReaderConfigurationPath))
  1478. {
  1479. try
  1480. {
  1481. _cardReaderConfig = FileHelper.ReadJsonFile<SerialPortConfig>(ConfigPaths.CardReaderConfigurationPath);
  1482. }
  1483. catch
  1484. {
  1485. // ����ȡʧ�ܣ�����Ĭ�����ò������ļ�������Ŀ���������ò���һ�£�
  1486. _cardReaderConfig = new SerialPortConfig();
  1487. try { FileHelper.WriteJsonFile(_cardReaderConfig, ConfigPaths.CardReaderConfigurationPath); } catch { }
  1488. }
  1489. }
  1490. else
  1491. {
  1492. _cardReaderConfig = new SerialPortConfig();
  1493. try { FileHelper.WriteJsonFile(_cardReaderConfig, ConfigPaths.CardReaderConfigurationPath); } catch { }
  1494. }
  1495. return _cardReaderConfig;
  1496. }
  1497. }
  1498. /// <summary>
  1499. /// ����ˢ��������
  1500. /// </summary>
  1501. /// <param name="config"></param>
  1502. public void SaveCardReaderConfig(SerialPortConfig config)
  1503. {
  1504. if (config == null) return;
  1505. lock (_sync)
  1506. {
  1507. _cardReaderConfig = config;
  1508. try
  1509. {
  1510. FileHelper.WriteJsonFile(_cardReaderConfig, ConfigPaths.CardReaderConfigurationPath);
  1511. }
  1512. catch
  1513. {
  1514. // ���Գ־û���������Ŀ���������淽��һ�£���������Ҫʱ������־��¼
  1515. }
  1516. }
  1517. }
  1518. #endregion
  1519. #region ��ȡ��������
  1520. public void SaveTorqueReaderConfig(TorqueSerialPortConfig config)
  1521. {
  1522. if (config == null) return;
  1523. lock (_sync)
  1524. {
  1525. _torqueReaderConfig = config;
  1526. try
  1527. {
  1528. FileHelper.WriteJsonFile(_torqueReaderConfig, ConfigPaths.TorqueReaderConfigurationPath);
  1529. }
  1530. catch
  1531. {
  1532. // ���Գ־û���������Ŀ���������淽��һ�£���������Ҫʱ������־��¼
  1533. }
  1534. }
  1535. }
  1536. public TorqueSerialPortConfig GetTorqueReaderConfig()
  1537. {
  1538. lock (_sync)
  1539. {
  1540. if (_torqueReaderConfig != null)
  1541. return _torqueReaderConfig;
  1542. if (File.Exists(ConfigPaths.TorqueReaderConfigurationPath))
  1543. {
  1544. try
  1545. {
  1546. _torqueReaderConfig = FileHelper.ReadJsonFile<TorqueSerialPortConfig>(ConfigPaths.TorqueReaderConfigurationPath);
  1547. }
  1548. catch
  1549. {
  1550. // ����ȡʧ�ܣ�����Ĭ�����ò������ļ�������Ŀ���������ò���һ�£�
  1551. _torqueReaderConfig = new TorqueSerialPortConfig();
  1552. try { FileHelper.WriteJsonFile(_torqueReaderConfig, ConfigPaths.TorqueReaderConfigurationPath); } catch { }
  1553. }
  1554. }
  1555. else
  1556. {
  1557. _torqueReaderConfig = new TorqueSerialPortConfig();
  1558. try { FileHelper.WriteJsonFile(_torqueReaderConfig, ConfigPaths.TorqueReaderConfigurationPath); } catch { }
  1559. }
  1560. return _torqueReaderConfig;
  1561. }
  1562. }
  1563. #endregion
  1564. /// <summary>
  1565. /// �ͷ���Դ�����浱ǰ�ڴ��е��������õ��ļ���
  1566. /// </summary>
  1567. public void Dispose()
  1568. {
  1569. SaveAll();
  1570. GC.SuppressFinalize(this);
  1571. }
  1572. }
  1573. }