Management.cs 177 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596
  1. using Cognex.VisionPro;
  2. using CSScripting;
  3. using NPOI.Util;
  4. //using ICSharpCode.SharpZipLib.Zip;
  5. using Prism.Events;
  6. using Prism.Ioc;
  7. using Prism.Mvvm;
  8. using Prism.Regions;
  9. using System;
  10. using System.Collections.Generic;
  11. using System.Collections.ObjectModel;
  12. using System.Drawing;
  13. using System.IO;
  14. using System.IO.Compression;
  15. using System.Linq;
  16. using System.Text;
  17. using System.Threading;
  18. using System.Threading.Tasks;
  19. using System.Windows.Media;
  20. using Team.FFFeederService.Interfaces;
  21. using TeamAAS_VP.Core.PLCs;
  22. using TeamAAS_VP.Core.ScrewDriver;
  23. using TeamAAS_VP.Enums;
  24. using TeamAAS_VP.Events;
  25. using TeamAAS_VP.Interfaces;
  26. using TeamAAS_VP.Models;
  27. using TeamAAS_VP.Resources.Languages;
  28. using TeamAAS_VP.ViewModels;
  29. using TeamAAS_VP.ViewModels.Home;
  30. using TouchSocket.Core;
  31. using TouchSocket.SerialPorts;
  32. using TouchSocket.Sockets;
  33. namespace TeamAAS_VP.Core
  34. {
  35. public class Management : BindableBase
  36. {
  37. #region 字段
  38. IRegionManager _regionManager;
  39. IEventAggregator _eventAggregator;
  40. IContainerProvider _container;
  41. IConfigService _configService;
  42. IRobotService _robotService;
  43. IScannerService _scannerService;
  44. ICameraService _cameraService;
  45. IFeederService _feederService;
  46. IPlcService _plcService;
  47. ILightManagerService _lightManagerService;
  48. IProductService _productService;
  49. ICalibrationService _calibrationService;
  50. IRemoteCommandService _remoteCommandService;
  51. ISystemDatabaseService _systemDatabaseService;
  52. IMesService _mesService;
  53. Timer yieldtimer;
  54. private DateTime StartTime = DateTime.Now;
  55. /// <summary>
  56. /// 产品主sn
  57. /// </summary>
  58. string ProductMainSN = "";
  59. /// <summary>
  60. /// 工单信息
  61. /// </summary>
  62. string wo = "";
  63. string model_num = "";//产品model_num
  64. string color = "";//产品color
  65. string ppid = "";//产品ppid
  66. string revision = "";//产品revision
  67. string stage = "";//产品revision
  68. /// <summary>
  69. /// 上次执行上传csv的日期
  70. /// </summary>
  71. private DateTime _lastCompressDate = DateTime.MinValue;
  72. /// <summary>
  73. /// 当天是否上传过csv
  74. /// </summary>
  75. private bool _hasCompressedToday = false;
  76. #endregion
  77. #region 属性
  78. private Guid _defaultScannerId = Guid.Empty;
  79. private volatile TaskCompletionSource<string> _scanTcs; // 最简单:只支持单通道“当前一次扫
  80. public string[] CsvData = new string[50];
  81. public int[] ResultData = new int[200];
  82. public string code = "";
  83. List<LockResult> lockResultsAll = new List<LockResult>();//一个产品的总结果
  84. private ObservableCollection<ShowRender> _Renders;
  85. private double _CTtime;
  86. public int ResultDataCount;
  87. // 扫码结果
  88. private string ScanValue = "";
  89. // 扫码完成事件
  90. private readonly ManualResetEventSlim _scanDoneEvent = new ManualResetEventSlim(false);
  91. private SerialPortClient _Scan_Client;
  92. public SerialPortClient Scan_Client
  93. {
  94. get { return _Scan_Client; }
  95. set { _Scan_Client = value; }
  96. }
  97. private bool _ShowMes_Query;
  98. /// <summary>
  99. /// 显示查询结果
  100. /// </summary>
  101. public bool ShowMes_Query
  102. {
  103. get { return _ShowMes_Query; }
  104. set { SetProperty(ref _ShowMes_Query, value); }
  105. }
  106. private bool _ShowMes_Result;
  107. /// <summary>
  108. /// 显示上传结果
  109. /// </summary>
  110. public bool ShowMes_Result
  111. {
  112. get { return _ShowMes_Result; }
  113. set { SetProperty(ref _ShowMes_Result, value); }
  114. }
  115. /// <summary>
  116. /// ct
  117. /// </summary>
  118. public double CTtime
  119. {
  120. get { return _CTtime; }
  121. set { SetProperty(ref _CTtime, value); }
  122. }
  123. /// <summary>
  124. /// 显示界面
  125. /// </summary>
  126. public ObservableCollection<ShowRender> Renders
  127. {
  128. get { return _Renders; }
  129. set { SetProperty(ref _Renders, value); }
  130. }
  131. private ProductModel _CurrentProduct;
  132. /// <summary>
  133. /// 当前产品
  134. /// </summary>
  135. public ProductModel CurrentProduct
  136. {
  137. get { return _CurrentProduct; }
  138. set { SetProperty(ref _CurrentProduct, value); }
  139. }
  140. public BgCommunicate BgCommunicate { get; private set; }
  141. public BgModbusTcpCommunicate BgModbusTcpCommunicate { get; private set; }
  142. private ObservableCollection<StatusInfo> _Status = new ObservableCollection<StatusInfo>();
  143. /// <summary>
  144. /// 状态栏集合
  145. /// </summary>
  146. public ObservableCollection<StatusInfo> Status
  147. {
  148. get { return _Status; }
  149. set { SetProperty(ref _Status, value); }
  150. }
  151. private Int64 _TotalQuantity;
  152. /// <summary>
  153. /// 总产量
  154. /// </summary>
  155. public Int64 TotalQuantity
  156. {
  157. get { return _TotalQuantity; }
  158. set { SetProperty(ref _TotalQuantity, value); }
  159. }
  160. private Int64 _TotalQuantityToday;
  161. /// <summary>
  162. /// 当天的总产量
  163. /// </summary>
  164. public Int64 TotalQuantityToday
  165. {
  166. get { return _TotalQuantityToday; }
  167. set { SetProperty(ref _TotalQuantityToday, value); }
  168. }
  169. private Int64 _CurrentUPH;
  170. /// <summary>
  171. /// 当前的UPH
  172. /// </summary>
  173. public Int64 CurrentUPH
  174. {
  175. get { return _CurrentUPH; }
  176. set { SetProperty(ref _CurrentUPH, value); }
  177. }
  178. private Int64 _NgNumber;
  179. /// <summary>
  180. /// 当前的NG数量
  181. /// </summary>
  182. public Int64 NgNumber
  183. {
  184. get { return _NgNumber; }
  185. set { SetProperty(ref _NgNumber, value); }
  186. }
  187. private double _Yield;
  188. /// <summary>
  189. /// 当前的NG数量
  190. /// </summary>
  191. public double Yield
  192. {
  193. get { return _Yield; }
  194. set { SetProperty(ref _Yield, value); }
  195. }
  196. private XYD_ScrewDriver _ScrewDriver;
  197. public XYD_ScrewDriver ScrewDriver
  198. {
  199. get { return _ScrewDriver; }
  200. set { SetProperty(ref _ScrewDriver, value); }
  201. }
  202. public Dictionary<string, object> BackupObject { get; set; } = new Dictionary<string, object>();
  203. private ObservableCollection<ProductModel> _ProductList;
  204. public ObservableCollection<ProductModel> ProductList
  205. {
  206. get { return _ProductList; }
  207. set { SetProperty(ref _ProductList, value); }
  208. }
  209. #endregion
  210. #region 命令
  211. #endregion
  212. #region 事件
  213. #endregion
  214. public Management(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container, IConfigService configService,
  215. IRobotService robotService, ICameraService cameraService, IFeederService feederService, IPlcService plcService, IProductService productService,
  216. ICalibrationService calibrationService, IRemoteCommandService remoteCommandService, ISystemDatabaseService systemDatabaseService, ILightManagerService lightManagerService, IMesService mesService, IScannerService scannerService)
  217. {
  218. _regionManager = regionManager;
  219. _eventAggregator = ea;
  220. _container = container;
  221. _configService = configService;
  222. _robotService = robotService;
  223. _scannerService = scannerService;
  224. _cameraService = cameraService;
  225. _feederService = feederService;
  226. _plcService = plcService;
  227. _calibrationService = calibrationService;
  228. yieldtimer = new Timer(DoYieldTime, null, 10000, 1000);
  229. Renders = new ObservableCollection<ShowRender>();
  230. _configService = configService;
  231. _productService = productService;
  232. _remoteCommandService = remoteCommandService;
  233. _systemDatabaseService = systemDatabaseService;
  234. _lightManagerService = lightManagerService;
  235. _mesService = mesService;
  236. }
  237. #region 初始化硬件模块
  238. /// <summary>
  239. /// 初始化Feeder
  240. /// </summary>
  241. /// <returns></returns>
  242. public async Task<(bool IsSucceed, string Msg)> InitFeeders()
  243. {
  244. var feeders = _configService.GetAllFeeders();
  245. StringBuilder sb = new StringBuilder();
  246. foreach (var item in feeders)
  247. {
  248. _feederService.CreateFeeder(item.Id, item.FeederNo, item.FeederName, item.IP, item.Port, item.FeederBrand);
  249. var feeder = _feederService.GetFeeder(item.Id);
  250. Status.Add(new StatusInfo(item.Id, item.FeederName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
  251. try
  252. {
  253. feeder.FeederConnectionStatusChanged += Management_FeederConnectionStatusChanged;
  254. await feeder.ConnectAsync(); //连接Feeder
  255. //SendTaskMessage($"{item.FeederName}已连接!", MessageLevel.Debug);
  256. }
  257. catch (Exception ex)
  258. {
  259. sb.AppendLine($"{item.FeederName}:{Lang.断开连接}![{ex.Message}]");
  260. SendTaskMessage($"{item.FeederName}{Lang.断开连接}!", MessageLevel.Alarm);
  261. }
  262. }
  263. if (sb.Length == 0)
  264. {
  265. return (true, "");
  266. }
  267. else
  268. {
  269. return (false, sb.ToString());
  270. }
  271. }
  272. /// <summary>
  273. /// 初始化机器人
  274. /// </summary>
  275. /// <returns></returns>
  276. public async Task<(bool IsSucceed, string Msg)> InitRobots()
  277. {
  278. var robots = _configService.GetAllRobots();
  279. StringBuilder sb = new StringBuilder();
  280. foreach (var item in robots)
  281. {
  282. _robotService.CreateRobot(item.Id, item);
  283. try
  284. {
  285. Status.Add(new StatusInfo(item.Id, item.RobotName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
  286. var robot = _robotService.GetRobot(item.Id);
  287. robot.ReceivedEvent += Management_ReceivedEvent;
  288. robot.SendEvent += Management_SendEvent;
  289. robot.ConnectedEvent += Management_ConnectedEvent;
  290. robot.DisconnectedEvent += Management_DisconnectedEvent;
  291. await robot.ConnectAsync(); //连接Robot
  292. SendTaskMessage($"{item.RobotName}{Lang.已连接}!", MessageLevel.Debug);
  293. }
  294. catch (Exception ex)
  295. {
  296. sb.AppendLine($"{item.RobotName}:{Lang.断开连接}![{ex.Message}]");
  297. SendTaskMessage($"{item.RobotName}{Lang.断开连接}!", MessageLevel.Alarm);
  298. }
  299. }
  300. if (sb.Length == 0)
  301. {
  302. return (true, "");
  303. }
  304. else
  305. {
  306. return (false, sb.ToString());
  307. }
  308. }
  309. /// <summary>
  310. /// 初始化扫码枪
  311. /// </summary>
  312. /// <returns></returns>
  313. public async Task<(bool IsSucceed, string Msg)> InitScanners()
  314. {
  315. var scanners = _configService.GetAllScanners();
  316. StringBuilder sb = new StringBuilder();
  317. foreach (var item in scanners)
  318. {
  319. _scannerService.CreateScanner(item.Id, item);
  320. try
  321. {
  322. Status.Add(new StatusInfo(item.Id, item.ScannerName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
  323. var scanner = _scannerService.GetScanner(item.Id);
  324. scanner.ReceivedEvent += Management_ScannerReceivedEvent;
  325. scanner.SendEvent += Management_ScannerSendEvent;
  326. scanner.ConnectedEvent += Management_ScannerConnectedEvent;
  327. scanner.DisconnectedEvent += Management_ScannerDisconnectedEvent;
  328. await scanner.ConnectAsync(); //连接Scanner
  329. SendTaskMessage($"{item.ScannerName}{Lang.已连接}!", MessageLevel.Debug);
  330. }
  331. catch (Exception ex)
  332. {
  333. sb.AppendLine($"{item.ScannerName}:{Lang.断开连接}![{ex.Message}]");
  334. SendTaskMessage($"{item.ScannerName}{Lang.断开连接}!", MessageLevel.Alarm);
  335. }
  336. }
  337. if (sb.Length == 0)
  338. {
  339. return (true, "");
  340. }
  341. else
  342. {
  343. return (false, sb.ToString());
  344. }
  345. }
  346. /// <summary>
  347. /// 初始化PLC
  348. /// </summary>
  349. /// <returns></returns>
  350. public async Task<(bool IsSucceed, string Msg)> InitPlc()
  351. {
  352. var plcs = _configService.GetAllPlcs();
  353. StringBuilder sb = new StringBuilder();
  354. foreach (var item in plcs)
  355. {
  356. try
  357. {
  358. _plcService.CreatePlc(item.Id, item);
  359. var plc = _plcService.GetPlc(item.Id);
  360. Status.Add(new StatusInfo(item.Id, item.Name + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
  361. plc.ConnectChangedEvent += Management_PlcConnectChangedEvent;
  362. await plc.ConnectAsync(); //连接PLC
  363. //SendTaskMessage($"{item.Name}{Lang.已连接}!", MessageLevel.Debug);
  364. }
  365. catch (Exception ex)
  366. {
  367. sb.AppendLine($"{item.Name}:{Lang.断开连接}![{ex.Message}]");
  368. SendTaskMessage($"{item.Name}{Lang.断开连接}!", MessageLevel.Alarm);
  369. }
  370. }
  371. try
  372. {
  373. await WriteSystemParameterToPlcAsync(_configService.GetSystemConfiguration());
  374. RegisterPlcMonitorAddress();
  375. }
  376. catch (Exception ex)
  377. {
  378. LogHelper.WriteLogError("为PLC写入系统参数和订阅变量时出错", ex);
  379. }
  380. if (sb.Length == 0)
  381. {
  382. return (true, "");
  383. }
  384. else
  385. {
  386. return (false, sb.ToString());
  387. }
  388. }
  389. /// <summary>
  390. /// 初始化相机
  391. /// </summary>
  392. /// <returns></returns>
  393. public async Task<(bool IsSucceed, string Msg)> InitCameras()
  394. {
  395. var cameras = _configService.GetAllCameras();
  396. StringBuilder sb = new StringBuilder();
  397. foreach (var item in cameras)
  398. {
  399. if (item.DisplatConfigs != null)
  400. {
  401. foreach (var item1 in item.DisplatConfigs)
  402. {
  403. Renders.Add(new ShowRender() { Id = item1.Id, DisplayName = item1.DisplayName });
  404. }
  405. }
  406. _cameraService.CreateCamera(item.Id, item);
  407. try
  408. {
  409. var camera = _cameraService.GetCamera(item.Id);
  410. Status.Add(new StatusInfo(item.Id, item.CameraName + $"{Lang.未连接}", new SolidColorBrush(Colors.Red)));
  411. camera.CameraConnectChangedEvent += Management_CameraConnectChangedEvent;
  412. camera.ImageCallbackEvent += Camera_ImageCallbackEvent;
  413. try
  414. {
  415. if (await camera.OpenDeviceAsync())
  416. {
  417. SendTaskMessage($"{item.CameraName}{Lang.已连接}!", MessageLevel.Debug);
  418. }
  419. else
  420. {
  421. SendTaskMessage($"{item.CameraName}{Lang.连接失败}!", MessageLevel.Alarm);
  422. sb.AppendLine($"{item.CameraName}:{Lang.连接失败}!");
  423. }
  424. }
  425. catch (Exception ex)
  426. {
  427. SendTaskMessage($"{item.CameraName}{ex.Message}!", MessageLevel.Alarm);
  428. sb.AppendLine($"{item.CameraName}:{ex.Message}!");
  429. }
  430. }
  431. catch (Exception ex)
  432. {
  433. SendTaskMessage($"{item.CameraName}{Lang.连接失败}!", MessageLevel.Alarm);
  434. sb.AppendLine($"{item.CameraName}:{Lang.连接失败}!:{ex.Message}");
  435. }
  436. }
  437. _container.Resolve<ShowVisionRenderViewModel>().Renders = Renders;
  438. if (sb.Length == 0)
  439. {
  440. return (true, "");
  441. }
  442. else
  443. {
  444. return (false, sb.ToString());
  445. }
  446. }
  447. private void Camera_ImageCallbackEvent(ICogImage arg1, TimeSpan arg2, string arg3, Guid cameraId)
  448. {
  449. var camera = _configService.GetCamera(cameraId);
  450. SendTaskMessage($"相机[{camera.CameraName}]图像接收完成!", MessageLevel.Info);
  451. //if (camera.CameraNo == 1)
  452. //{
  453. // ImageData[1] = 1;
  454. //}
  455. //else if (camera.CameraNo == 2)
  456. //{
  457. // ImageData[2] = 1;
  458. //}
  459. //else if (camera.CameraNo == 3)
  460. //{
  461. // ImageData[3] = 1;
  462. // ImageData[4] = 1;
  463. //}
  464. //_eventAggregator.GetEvent<RenderUpdateNotification>().Publish(new ShowRender()
  465. //{
  466. // CameraName = camera.CameraName,
  467. // Id = cameraId,
  468. // Image = arg1,
  469. // Graphic = null,
  470. // Record = null,
  471. // Result = false,
  472. // IsShow = true,
  473. //});
  474. // 通知等待方:该相机新图到达
  475. //SignalImageArrived(cameraId, arg1);
  476. }
  477. /// <summary>
  478. /// 初始化光源控制器
  479. /// </summary>
  480. /// <returns></returns>
  481. public async Task<(bool IsSucceed, string Msg)> InitLightControllers()
  482. {
  483. var lightcontrollers = _configService.GetAllLightControllers();
  484. StringBuilder sb = new StringBuilder();
  485. foreach (var item in lightcontrollers)
  486. {
  487. try
  488. {
  489. var lishtCtr = await _lightManagerService.RegisterControllerAsync(item.Id, item);
  490. //var lightcontroller = _cameraService.GetLightController(item.Id);
  491. //await lightcontroller.ConnectAsync(); //连接光源控制器
  492. //SendTaskMessage($"{item.LightControllerName}{Lang.已连接}!", MessageLevel.Debug);
  493. }
  494. catch (Exception ex)
  495. {
  496. //sb.AppendLine($"{item.LightControllerName}:{Lang.断开连接}![{ex.Message}]");
  497. //SendTaskMessage($"{item.LightControllerName}{Lang.断开连接}!", MessageLevel.Alarm);
  498. }
  499. }
  500. if (lightcontrollers.Count > 0)
  501. {
  502. var result = await _lightManagerService.ConnectAllAsync();
  503. if (result)
  504. {
  505. return (true, "");
  506. }
  507. else
  508. {
  509. return (false, "Light Controller Connect Failed!");
  510. }
  511. }
  512. return (true, "");
  513. //if (sb.Length == 0)
  514. //{
  515. // return (true, "");
  516. //}
  517. //else
  518. //{
  519. // return (false, sb.ToString());
  520. //}
  521. }
  522. /// <summary>
  523. /// 初始化后台TCP服务器通讯
  524. /// </summary>
  525. public void InitBgTcp()
  526. {
  527. var config = _configService.GetBgTcp();
  528. try
  529. {
  530. BgCommunicate = new BgCommunicate(config);
  531. BgCommunicate.ConnectedEvent += BgCommunicate_ConnectedEvent;
  532. BgCommunicate.DisconnectedEvent += BgCommunicate_DisconnectedEvent;
  533. BgCommunicate.ReceivedEvent += BgCommunicate_ReceivedEvent;
  534. BgCommunicate.SendEvent += BgCommunicate_SendEvent;
  535. BgCommunicate.StartListening();
  536. SendTaskMessage($"{Lang.已开启监听端口}:{config.Port}", MessageLevel.Debug);
  537. }
  538. catch (Exception ex)
  539. {
  540. SendTaskMessage($"{Lang.未开启监听端口}:{config.Port}", MessageLevel.Error);
  541. LogHelper.WriteLogError("开启后台服务器通讯时出错!", ex);
  542. }
  543. }
  544. /// <summary>
  545. /// 初始化后台ModbusTCP从站
  546. /// </summary>
  547. public void InitModbusTcp()
  548. {
  549. try
  550. {
  551. var config = _configService.GetBgModbusTcp();
  552. BgModbusTcpCommunicate = new BgModbusTcpCommunicate(config);
  553. if (config.IsEnabled)
  554. {
  555. BgModbusTcpCommunicate.Listen();
  556. SendTaskMessage($"Start Modbus Tcp Slave:{BgModbusTcpCommunicate.IP}:{BgModbusTcpCommunicate.Port}:{BgModbusTcpCommunicate.SlaveID}", MessageLevel.Debug);
  557. }
  558. }
  559. catch (Exception ex)
  560. {
  561. SendTaskMessage($"No Start Modbus Tcp Slave:{ex.Message}", MessageLevel.Alarm);
  562. LogHelper.WriteLogError("开启后台Modbus TCP通讯时出错!", ex);
  563. }
  564. }
  565. /// <summary>
  566. /// 初始化后台脚本
  567. /// </summary>
  568. public void InitBackgroundcript()
  569. {
  570. try
  571. {
  572. if (!Directory.Exists(FilePath.BackgroundScriptPath))
  573. {
  574. Directory.CreateDirectory(FilePath.BackgroundScriptPath);
  575. }
  576. try
  577. {
  578. string[] files = Directory.GetFiles(FilePath.BackgroundScriptPath);
  579. List<string> ScriptFilesCollection = new List<string>();
  580. foreach (string file in files)
  581. {
  582. string fileName = Path.GetFileName(file);
  583. string fileExtension = Path.GetExtension(file);
  584. if (fileExtension == ".cs")
  585. {
  586. ScriptFilesCollection.Add(file);
  587. }
  588. }
  589. foreach (var item in ScriptFilesCollection)
  590. {
  591. try
  592. {
  593. string script = FileHelper.ReadFile(item);
  594. SendTaskMessage($"{Lang.执行脚本}:{item}", MessageLevel.Info);
  595. Task.Factory.StartNew(() =>
  596. {
  597. ScriptHelper.ExecuteScriptingAsync(script, _regionManager, _eventAggregator, _container, rst =>
  598. {
  599. if (!rst.Item1)
  600. {
  601. foreach (var err in rst.Item2)
  602. {
  603. SendTaskMessage($"{Lang.后台脚本出错}:{err}", MessageLevel.Error);
  604. }
  605. }
  606. });
  607. });
  608. }
  609. catch (Exception ex)
  610. {
  611. LogHelper.WriteLogError($"开启脚本时出错:{item}", ex);
  612. }
  613. }
  614. }
  615. catch (Exception ex)
  616. {
  617. LogHelper.WriteLogError("读取本地脚本文件列表时出错", ex);
  618. }
  619. }
  620. catch (Exception ex)
  621. {
  622. LogHelper.WriteLogError("开启后台脚本时出错!", ex);
  623. }
  624. }
  625. /// <summary>
  626. /// 初始化电批
  627. /// </summary>
  628. /// <returns></returns>
  629. public async Task InitScrewDriver()
  630. {
  631. try
  632. {
  633. var screwDriverConfig = _configService.GetScrewDriverConfig();
  634. ScrewDriver = new XYD_ScrewDriver(screwDriverConfig.IPAdress, screwDriverConfig.Port);
  635. Status.Add(new StatusInfo(ScrewDriver.Id, "电批未连接", new SolidColorBrush(Colors.Red)));
  636. ScrewDriver.ConnectStateChangedEvent += ScrewDriver_ConnectStateChangedEvent;
  637. ScrewDriver.SendTimeout = screwDriverConfig.SendTimeout;
  638. screwDriverConfig.ReceiveTimeout = screwDriverConfig.ReceiveTimeout;
  639. var isConnected = await ScrewDriver.ConnectAsync();
  640. if (isConnected)
  641. {
  642. SendTaskMessage($"电批已连接", MessageLevel.Debug);
  643. }
  644. else
  645. {
  646. SendTaskMessage($"电批连接失败", MessageLevel.Error);
  647. }
  648. }
  649. catch (Exception ex)
  650. {
  651. SendTaskMessage($"电批连接失败:{ex.Message}", MessageLevel.Alarm);
  652. LogHelper.WriteLogError("连接电批时出错!", ex);
  653. }
  654. }
  655. public async Task InitScan()
  656. {
  657. if (!File.Exists(FilePath.ScanRS232ConfigPath))
  658. {
  659. var scan = new ScanRs232ConfigModel();
  660. FileHelper.WriteJsonFile(scan, FilePath.ScanRS232ConfigPath);
  661. }
  662. try
  663. {
  664. var res = FileHelper.ReadJsonFile<ScanRs232ConfigModel>(FilePath.ScanRS232ConfigPath);
  665. if (res != null)
  666. {
  667. Scan_Client = new SerialPortClient();
  668. Scan_Client.Connecting = (client1, e) => { return EasyTask.CompletedTask; };//即将连接到端口
  669. Scan_Client.Connected = (client1, e) => { return EasyTask.CompletedTask; };//成功连接到端口
  670. Scan_Client.Closing = (client1, e) => { return EasyTask.CompletedTask; };//即将从端口断开连接。此处仅主动断开才有效。
  671. Scan_Client.Closed = (client1, e) => { return EasyTask.CompletedTask; };//从端口断开连接,当连接不成功时不会触发。
  672. Scan_Client.Received = async (c, e) =>
  673. {
  674. //await Console.Out.WriteLineAsync(Encoding.UTF8.GetString(e.ByteBlock.Buffer));
  675. await Console.Out.WriteLineAsync(e.ByteBlock.Span.ToString(Encoding.ASCII));
  676. };
  677. Scan_Client.Received = Scan_DataReceived;
  678. await Scan_Client.SetupAsync(new TouchSocketConfig()
  679. .SetSerialPortOption(new SerialPortOption()
  680. {
  681. BaudRate = res.BaudRate,//波特率
  682. DataBits = res.DataBits,//数据位
  683. Parity = res.Parity,//校验位
  684. PortName = res.PortName,//COM
  685. StopBits = res.StopBits//停止位
  686. })
  687. .SetSerialDataHandlingAdapter(() => new PeriodPackageAdapter() { CacheTimeout = TimeSpan.FromMilliseconds(100) })
  688. );
  689. await Scan_Client.ConnectAsync();
  690. if (Scan_Client.Online)
  691. {
  692. SendTaskMessage(Lang.扫码机已连接, MessageLevel.Debug);
  693. }
  694. else
  695. {
  696. SendTaskMessage(Lang.扫码机未连接, MessageLevel.Debug);
  697. }
  698. }
  699. else
  700. {
  701. SendTaskMessage(Lang.请设置扫码机串口, MessageLevel.Error);
  702. }
  703. }
  704. catch (Exception ex)
  705. {
  706. LogHelper.WriteLogError("初始化扫码枪时出错!", ex);
  707. SendTaskMessage(Lang.初始化扫码枪时出错 + ex.Message, MessageLevel.Error);
  708. }
  709. }
  710. #endregion
  711. #region 机器人指令执行
  712. public Dictionary<Guid, CancellationTokenSource> RobotTCPCollection = new Dictionary<Guid, CancellationTokenSource>();
  713. public Dictionary<Guid, CancellationTokenSource> ScannerTCPCollection = new Dictionary<Guid, CancellationTokenSource>();
  714. /// <summary>
  715. /// 机器人TCP接收
  716. /// </summary>
  717. /// <param name="arg1"></param>
  718. /// <param name="arg2"></param>
  719. /// <param name="arg3"></param>
  720. private async void Management_ReceivedEvent(Guid robotid, object arg2, TouchSocket.Sockets.ReceivedDataEventArgs e)
  721. {
  722. try
  723. {
  724. if (!RobotTCPCollection.ContainsKey(robotid))
  725. RobotTCPCollection.Add(robotid, new CancellationTokenSource());
  726. else
  727. {
  728. if (RobotTCPCollection[robotid].IsCancellationRequested)
  729. {
  730. RobotTCPCollection[robotid] = new CancellationTokenSource();
  731. }
  732. }
  733. var robot = await _robotService.GetRobotAsync(robotid);
  734. //从服务器收到信息。但是一般byteBlock和requestInfo会根据适配器呈现不同的值。
  735. var buffer = e.ByteBlock.Span.ToString(robot.GetEncoding());
  736. SendTaskMessage($"{robot.Name}Received:{buffer}", MessageLevel.Info);
  737. var _ = _remoteCommandService.ExecuteAsync(buffer, RobotTCPCollection[robotid].Token, async msg =>
  738. {
  739. try
  740. {
  741. if (robot.ConnectType == TCPConnectType.Client)
  742. {
  743. if (robot.IsConnected)
  744. {
  745. await robot.SendAsync($"{msg}");
  746. }
  747. }
  748. else
  749. {
  750. var cient = (ITcpSessionClient)arg2;
  751. if (cient.Online)
  752. {
  753. await robot.SendAsync(cient, $"{msg}");
  754. }
  755. }
  756. }
  757. catch (Exception ex)
  758. {
  759. LogHelper.WriteLogError("TCP发送数据时出错!", ex);
  760. SendTaskMessage(ex.Message, MessageLevel.Alarm);
  761. }
  762. });
  763. }
  764. catch (Exception ex)
  765. {
  766. LogHelper.WriteLogError("处理机器人接收的命令时出错!", ex);
  767. SendTaskMessage(ex.Message, MessageLevel.Alarm);
  768. }
  769. }
  770. /// <summary>
  771. /// 扫码枪TCP接收
  772. /// </summary>
  773. /// <param name="arg1"></param>
  774. /// <param name="arg2"></param>
  775. /// <param name="arg3"></param>
  776. private async void Management_ScannerReceivedEvent(Guid scannerid, object arg2, TouchSocket.Sockets.ReceivedDataEventArgs e)
  777. {
  778. try
  779. {
  780. if (!ScannerTCPCollection.ContainsKey(scannerid))
  781. ScannerTCPCollection.Add(scannerid, new CancellationTokenSource());
  782. else
  783. {
  784. if (ScannerTCPCollection[scannerid].IsCancellationRequested)
  785. {
  786. ScannerTCPCollection[scannerid] = new CancellationTokenSource();
  787. }
  788. }
  789. var scanner = await _scannerService.GetScannerAsync(scannerid);
  790. //从服务器收到信息。但是一般byteBlock和requestInfo会根据适配器呈现不同的值。
  791. var buffer = e.ByteBlock.Span.ToString(scanner.GetEncoding());
  792. var reply = (buffer ?? string.Empty).Trim();
  793. SendTaskMessage($"{scanner.Name}Received:{reply}", MessageLevel.Info);
  794. // 只要有人在等扫码结果,就先完成等待(避免被下面 ExecuteAsync 干扰)
  795. var tcs = _scanTcs;
  796. if (tcs != null && !string.IsNullOrWhiteSpace(reply))
  797. {
  798. // 只完成一次
  799. tcs.TrySetResult(reply);
  800. }
  801. var _ = _remoteCommandService.ExecuteAsync(buffer, ScannerTCPCollection[scannerid].Token, async msg =>
  802. {
  803. try
  804. {
  805. if (scanner.ConnectType == TCPConnectType.Client)
  806. {
  807. if (scanner.IsConnected)
  808. {
  809. await scanner.SendAsync($"{msg}");
  810. }
  811. }
  812. else
  813. {
  814. var cient = (ITcpSessionClient)arg2;
  815. if (cient.Online)
  816. {
  817. await scanner.SendAsync(cient, $"{msg}");
  818. }
  819. }
  820. }
  821. catch (Exception ex)
  822. {
  823. LogHelper.WriteLogError("TCP发送数据时出错!", ex);
  824. SendTaskMessage(ex.Message, MessageLevel.Alarm);
  825. }
  826. });
  827. }
  828. catch (Exception ex)
  829. {
  830. LogHelper.WriteLogError("处理扫码枪接收的命令时出错!", ex);
  831. SendTaskMessage(ex.Message, MessageLevel.Alarm);
  832. }
  833. }
  834. #endregion
  835. #region 机器人&Feeder&相机连接状态事件
  836. /// <summary>
  837. /// 机器人发送事件
  838. /// </summary>
  839. /// <param name="arg1"></param>
  840. /// <param name="arg2"></param>
  841. /// <param name="arg3"></param>
  842. /// <exception cref="NotImplementedException"></exception>
  843. private void Management_SendEvent(Guid robotid, object arg2, string arg3)
  844. {
  845. var r = _robotService.GetRobot(robotid);
  846. SendTaskMessage($"{r.Name}Send:{arg3}", MessageLevel.Info);
  847. }
  848. /// <summary>
  849. /// 扫码枪发送事件
  850. /// </summary>
  851. /// <param name="arg1"></param>
  852. /// <param name="arg2"></param>
  853. /// <param name="arg3"></param>
  854. /// <exception cref="NotImplementedException"></exception>
  855. private void Management_ScannerSendEvent(Guid scannerid, object arg2, string arg3)
  856. {
  857. var r = _scannerService.GetScanner(scannerid);
  858. SendTaskMessage($"{r.Name}Send:{arg3}", MessageLevel.Info);
  859. }
  860. /// <summary>
  861. /// 机器人断开连接时
  862. /// </summary>
  863. /// <param name="arg1"></param>
  864. /// <param name="arg2"></param>
  865. /// <param name="arg3"></param>
  866. /// <exception cref="NotImplementedException"></exception>
  867. private void Management_DisconnectedEvent(Guid robotid, object arg2, ClosedEventArgs arg3)
  868. {
  869. if (RobotTCPCollection.ContainsKey(robotid))
  870. {
  871. RobotTCPCollection[robotid].Cancel();
  872. }
  873. var r = _configService.GetRobot(robotid);
  874. if (r.ConnectType == TCPConnectType.Server)
  875. {
  876. ITcpSessionClient socketClient = arg2 as ITcpSessionClient;
  877. SendTaskMessage($"{r.RobotName}[{socketClient.Id}:{socketClient.IP}]{Lang.断开连接}!", MessageLevel.Error);
  878. var robot = _robotService.GetRobot(robotid);
  879. if (robot.TcpService.Count < 1)
  880. {
  881. var sta = Status.FirstOrDefault(s => s.ID == robotid);
  882. App.Current.Dispatcher.Invoke(new
  883. Action(() =>
  884. {
  885. sta.Message = $"{r.RobotName}{Lang.未连接}";
  886. sta.Background = new SolidColorBrush(Colors.Red);
  887. }));
  888. }
  889. }
  890. else
  891. {
  892. SendTaskMessage($"{r.RobotName}{Lang.断开连接}!", MessageLevel.Error);
  893. var sta = Status.FirstOrDefault(s => s.ID == robotid);
  894. App.Current.Dispatcher.Invoke(new
  895. Action(() =>
  896. {
  897. sta.Message = $"{r.RobotName}{Lang.断开连接}";
  898. sta.Background = new SolidColorBrush(Colors.Red);
  899. }));
  900. }
  901. }
  902. /// <summary>
  903. /// 扫码枪断开连接时
  904. /// </summary>
  905. /// <param name="arg1"></param>
  906. /// <param name="arg2"></param>
  907. /// <param name="arg3"></param>
  908. /// <exception cref="NotImplementedException"></exception>
  909. private void Management_ScannerDisconnectedEvent(Guid scannerid, object arg2, ClosedEventArgs arg3)
  910. {
  911. if (ScannerTCPCollection.ContainsKey(scannerid))
  912. {
  913. ScannerTCPCollection[scannerid].Cancel();
  914. }
  915. var r = _configService.GetScanner(scannerid);
  916. if (r.ConnectType == TCPConnectType.Server)
  917. {
  918. ITcpSessionClient socketClient = arg2 as ITcpSessionClient;
  919. SendTaskMessage($"{r.ScannerName}[{socketClient.Id}:{socketClient.IP}]{Lang.断开连接}!", MessageLevel.Error);
  920. var scanner = _scannerService.GetScanner(scannerid);
  921. if (scanner.TcpService.Count < 1)
  922. {
  923. var sta = Status.FirstOrDefault(s => s.ID == scannerid);
  924. App.Current.Dispatcher.Invoke(new
  925. Action(() =>
  926. {
  927. sta.Message = $"{r.ScannerName}{Lang.未连接}";
  928. sta.Background = new SolidColorBrush(Colors.Red);
  929. }));
  930. }
  931. }
  932. else
  933. {
  934. SendTaskMessage($"{r.ScannerName}{Lang.断开连接}!", MessageLevel.Error);
  935. var sta = Status.FirstOrDefault(s => s.ID == scannerid);
  936. App.Current.Dispatcher.Invoke(new
  937. Action(() =>
  938. {
  939. sta.Message = $"{r.ScannerName}{Lang.断开连接}";
  940. sta.Background = new SolidColorBrush(Colors.Red);
  941. }));
  942. }
  943. }
  944. /// <summary>
  945. /// 机器人连接成功时
  946. /// </summary>
  947. /// <param name="arg1"></param>
  948. /// <param name="arg2"></param>
  949. /// <param name="arg3"></param>
  950. /// <exception cref="NotImplementedException"></exception>
  951. private void Management_ConnectedEvent(Guid robotid, object arg2, ConnectedEventArgs arg3)
  952. {
  953. var r = _configService.GetRobot(robotid);
  954. if (r.ConnectType == TCPConnectType.Server)
  955. {
  956. ITcpSessionClient socketClient = arg2 as ITcpSessionClient;
  957. SendTaskMessage($"{r.RobotName}[{socketClient.Id}:{socketClient.IP}]{Lang.已连接}!", MessageLevel.Debug);
  958. var robot = _robotService.GetRobot(robotid);
  959. if (robot.TcpService.Count > 0)
  960. {
  961. var sta = Status.FirstOrDefault(s => s.ID == robotid);
  962. App.Current.Dispatcher.Invoke(new
  963. Action(() =>
  964. {
  965. sta.Message = $"{r.RobotName}{Lang.已连接}";
  966. sta.Background = new SolidColorBrush(Colors.Green);
  967. }));
  968. }
  969. }
  970. else
  971. {
  972. SendTaskMessage($"{r.RobotName}{Lang.已连接}!", MessageLevel.Debug);
  973. var sta = Status.FirstOrDefault(s => s.ID == robotid);
  974. App.Current.Dispatcher.Invoke(new
  975. Action(() =>
  976. {
  977. sta.Message = $"{r.RobotName}{Lang.已连接}";
  978. sta.Background = new SolidColorBrush(Colors.Green);
  979. }));
  980. }
  981. }
  982. /// <summary>
  983. /// 扫码枪连接成功时
  984. /// </summary>
  985. /// <param name="arg1"></param>
  986. /// <param name="arg2"></param>
  987. /// <param name="arg3"></param>
  988. /// <exception cref="NotImplementedException"></exception>
  989. private void Management_ScannerConnectedEvent(Guid scannerid, object arg2, ConnectedEventArgs arg3)
  990. {
  991. var r = _configService.GetScanner(scannerid);
  992. if (r.ConnectType == TCPConnectType.Server)
  993. {
  994. ITcpSessionClient socketClient = arg2 as ITcpSessionClient;
  995. SendTaskMessage($"{r.ScannerName}[{socketClient.Id}:{socketClient.IP}]{Lang.已连接}!", MessageLevel.Debug);
  996. var scanner = _scannerService.GetScanner(scannerid);
  997. if (scanner.TcpService.Count > 0)
  998. {
  999. var sta = Status.FirstOrDefault(s => s.ID == scannerid);
  1000. App.Current.Dispatcher.Invoke(new
  1001. Action(() =>
  1002. {
  1003. sta.Message = $"{r.ScannerName}{Lang.已连接}";
  1004. sta.Background = new SolidColorBrush(Colors.Green);
  1005. }));
  1006. }
  1007. }
  1008. else
  1009. {
  1010. SendTaskMessage($"{r.ScannerName}{Lang.已连接}!", MessageLevel.Debug);
  1011. var sta = Status.FirstOrDefault(s => s.ID == scannerid);
  1012. App.Current.Dispatcher.Invoke(new
  1013. Action(() =>
  1014. {
  1015. sta.Message = $"{r.ScannerName}{Lang.已连接}";
  1016. sta.Background = new SolidColorBrush(Colors.Green);
  1017. }));
  1018. }
  1019. }
  1020. /// <summary>
  1021. /// Feeder连接状态改变时
  1022. /// </summary>
  1023. /// <param name="sender"></param>
  1024. /// <param name="state"></param>
  1025. private void Management_FeederConnectionStatusChanged(object sender, bool state)
  1026. {
  1027. IFeeder feeder = sender as IFeeder;
  1028. var sta = Status.FirstOrDefault(s => s.ID == feeder.Id);
  1029. if (state)
  1030. {
  1031. App.Current.Dispatcher.Invoke(new
  1032. Action(() =>
  1033. {
  1034. sta.Message = $"{feeder.Name}{Lang.已连接}";
  1035. sta.Background = new SolidColorBrush(Colors.Green);
  1036. }));
  1037. SendTaskMessage($"{feeder.Name}{Lang.已连接}!", MessageLevel.Debug);
  1038. }
  1039. else
  1040. {
  1041. App.Current.Dispatcher.Invoke(new
  1042. Action(() =>
  1043. {
  1044. sta.Message = $"{feeder.Name}{Lang.未连接}";
  1045. sta.Background = new SolidColorBrush(Colors.Red);
  1046. }));
  1047. SendTaskMessage($"{feeder.Name}{Lang.断开连接}!", MessageLevel.Error);
  1048. }
  1049. }
  1050. /// <summary>
  1051. /// 相机连接或者断开时
  1052. /// </summary>
  1053. /// <param name="id"></param>
  1054. /// <param name="state"></param>
  1055. private void Management_CameraConnectChangedEvent(Guid id, bool state)
  1056. {
  1057. var sta = Status.FirstOrDefault(s => s.ID == id);
  1058. var camera = _configService.GetCamera(id);
  1059. if (sta != null && camera != null)
  1060. {
  1061. if (state)
  1062. {
  1063. App.Current.Dispatcher.Invoke(new Action(() =>
  1064. {
  1065. sta.Message = $"{camera.CameraName}{Lang.已连接}";
  1066. sta.Background = new SolidColorBrush(Colors.Green);
  1067. }));
  1068. }
  1069. else
  1070. {
  1071. App.Current.Dispatcher.Invoke(new Action(() =>
  1072. {
  1073. sta.Message = $"{camera.CameraName}{Lang.断开连接}";
  1074. sta.Background = new SolidColorBrush(Colors.Red);
  1075. }));
  1076. }
  1077. }
  1078. }
  1079. /// <summary>
  1080. /// PLC连接状态改变事件
  1081. /// </summary>
  1082. /// <param name="plc"></param>
  1083. /// <param name="isconnected"></param>
  1084. private void Management_PlcConnectChangedEvent(object sender, bool isconnected)
  1085. {
  1086. IPlc plc = sender as IPlc;
  1087. var sta = Status.FirstOrDefault(s => s.ID == plc.Id);
  1088. if (plc.IsConnected)
  1089. {
  1090. SendTaskMessage($"{plc.Name}{Lang.已连接}!", MessageLevel.Debug);
  1091. if (sta == null) return;
  1092. App.Current.Dispatcher.Invoke(new
  1093. Action(() =>
  1094. {
  1095. sta.Message = $"{plc.Name}{Lang.已连接}";
  1096. sta.Background = new SolidColorBrush(Colors.Green);
  1097. }));
  1098. }
  1099. else
  1100. {
  1101. SendTaskMessage($"{plc.Name}{Lang.断开连接}!", MessageLevel.Error);
  1102. if (sta == null) return;
  1103. App.Current.Dispatcher.Invoke(new
  1104. Action(() =>
  1105. {
  1106. sta.Message = $"{plc.Name}{Lang.未连接}";
  1107. sta.Background = new SolidColorBrush(Colors.Red);
  1108. }));
  1109. }
  1110. }
  1111. /// <summary>
  1112. /// 电批连接状态改变时
  1113. /// </summary>
  1114. /// <param name="screwDevice"></param>
  1115. /// <param name="state"></param>
  1116. private void ScrewDriver_ConnectStateChangedEvent(object screwDevice, bool state)
  1117. {
  1118. try
  1119. {
  1120. XYD_ScrewDriver screwDriver = screwDevice as XYD_ScrewDriver;
  1121. if (state)
  1122. {
  1123. SendTaskMessage($"电批{Lang.已连接}!", MessageLevel.Debug);
  1124. var sta = Status.FirstOrDefault(s => s.ID == screwDriver.Id);
  1125. App.Current.Dispatcher.Invoke(new
  1126. Action(() =>
  1127. {
  1128. sta.Message = $"电批{Lang.已连接}";
  1129. sta.Background = new SolidColorBrush(Colors.Green);
  1130. }));
  1131. }
  1132. else
  1133. {
  1134. SendTaskMessage($"电批{Lang.未连接}!", MessageLevel.Error);
  1135. var sta = Status.FirstOrDefault(s => s.ID == screwDriver.Id);
  1136. App.Current.Dispatcher.Invoke(new
  1137. Action(() =>
  1138. {
  1139. sta.Message = $"电批{Lang.未连接}";
  1140. sta.Background = new SolidColorBrush(Colors.Red);
  1141. }));
  1142. }
  1143. }
  1144. catch (Exception ex)
  1145. {
  1146. LogHelper.WriteLogError("电批连接状态改变时出错了", ex);
  1147. }
  1148. }
  1149. #endregion
  1150. #region 后台服务器通讯事件
  1151. private void BgCommunicate_SendEvent(ITcpSessionClient client, string msg)
  1152. {
  1153. SendTaskMessage($"{Lang.服务器}[{client.ServicePort}] Send To {Lang.客户端}[{client.Id}:{client.IP}]:{msg}", MessageLevel.Info);
  1154. }
  1155. public Dictionary<string, CancellationTokenSource> BgCommunicateollection = new Dictionary<string, CancellationTokenSource>();
  1156. private async void BgCommunicate_ReceivedEvent(ITcpSessionClient client, string msg)
  1157. {
  1158. try
  1159. {
  1160. if (!BgCommunicateollection.ContainsKey(client.Id))
  1161. {
  1162. BgCommunicateollection.Add(client.Id, new CancellationTokenSource());
  1163. }
  1164. SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]ReceiveFor{Lang.客户端}[{client.Id}:{client.IP}]:{msg}", MessageLevel.Info);
  1165. var _ = _remoteCommandService.ExecuteAsync(msg, BgCommunicateollection[client.Id].Token, async response =>
  1166. {
  1167. try
  1168. {
  1169. if (!client.Online)
  1170. {
  1171. return;
  1172. }
  1173. await BgCommunicate.SendAsync(client, $"{response}");
  1174. }
  1175. catch (Exception ex)
  1176. {
  1177. LogHelper.WriteLogError("后台TCP发送数据时出错!", ex);
  1178. SendTaskMessage(ex.Message, MessageLevel.Alarm);
  1179. }
  1180. });
  1181. }
  1182. catch (Exception ex)
  1183. {
  1184. LogHelper.WriteLogError("处理后台服务器接收的命令时出错!", ex);
  1185. SendTaskMessage(ex.Message, MessageLevel.Alarm);
  1186. }
  1187. }
  1188. private void BgCommunicate_DisconnectedEvent(ITcpSessionClient client, ClosedEventArgs e)
  1189. {
  1190. SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]{Lang.客户端}[{client.Id}:{client.IP}]{Lang.断开连接}!", MessageLevel.Alarm);
  1191. if (BgCommunicateollection.ContainsKey(client.Id))
  1192. {
  1193. BgCommunicateollection[client.Id].Cancel();
  1194. }
  1195. }
  1196. private void BgCommunicate_ConnectedEvent(ITcpSessionClient client, ConnectedEventArgs e)
  1197. {
  1198. SendTaskMessage($"{Lang.服务器}[{client.ServicePort}]{Lang.客户端}[{client.Id}:{client.IP}]{Lang.连接成功}!", MessageLevel.Debug);
  1199. }
  1200. #endregion
  1201. #region PLC
  1202. /// <summary>
  1203. /// 将系统参数写入PLC
  1204. /// </summary>
  1205. /// <param name="systemConfiguration"></param>
  1206. /// <returns></returns>
  1207. public async Task WriteSystemParameterToPlcAsync(SystemConfiguration systemConfiguration)
  1208. {
  1209. var addressConfig = _configService.GetPlcAddresses();
  1210. var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
  1211. if (plc == null || !plc.IsConnected) return;
  1212. Dictionary<string, object> nodeValues = new Dictionary<string, object>();
  1213. nodeValues.Add(addressConfig.Out_WorkMode.Address, (Int16)systemConfiguration.WorkMode);
  1214. nodeValues.Add(addressConfig.Out_PickPointNum.Address, (Int16)systemConfiguration.PickPointNum);
  1215. nodeValues.Add(addressConfig.Out_DowmCameraNum.Address, (Int16)systemConfiguration.DowmCameraNum);
  1216. nodeValues.Add(addressConfig.Out_UpCameraPickNum.Address, (Int16)systemConfiguration.UpCameraPickNum);
  1217. nodeValues.Add(addressConfig.Out_UpCameraPutNum.Address, (Int16)systemConfiguration.UpCameraPutNum);
  1218. nodeValues.Add(addressConfig.Out_UPCameracheckNum.Address, (Int16)systemConfiguration.UPCameracheckNum);
  1219. nodeValues.Add(addressConfig.Out_FixedCameraPickNum.Address, (Int16)systemConfiguration.FixedCameraPickNum);
  1220. nodeValues.Add(addressConfig.Out_FixedCameraPutNum.Address, (Int16)systemConfiguration.FixedCameraPutNum);
  1221. nodeValues.Add(addressConfig.Out_FixedCameracheckNum.Address, (Int16)systemConfiguration.FixedCameracheckNum);
  1222. var res = await plc.WriteNodesAsync(nodeValues);
  1223. }
  1224. /// <summary>
  1225. /// 注册需要监控的PLC地址
  1226. /// </summary>
  1227. public void RegisterPlcMonitorAddress()
  1228. {
  1229. var addressConfig = _configService.GetPlcAddresses();
  1230. var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
  1231. if (plc == null || !plc.IsConnected) return;
  1232. //PLC地址数组
  1233. List<string> monitorNodeIds = new List<string>()
  1234. {
  1235. addressConfig.In_DowmCameraExe.Address,
  1236. addressConfig.In_UpCameraPickExe.Address,
  1237. addressConfig.In_UpCameraPutExe.Address,
  1238. addressConfig.In_UPCameracheckExe.Address,
  1239. addressConfig.In_FixedCameraPickExe.Address,
  1240. addressConfig.In_FixedCameraPutExe.Address,
  1241. addressConfig.In_FixedCameracheckExe.Address,
  1242. addressConfig.In_WorkStart.Address,
  1243. addressConfig.In_WorkDone.Address,
  1244. addressConfig.In_MesCheck.Address,
  1245. addressConfig.In_RequestPosition.Address,
  1246. };
  1247. for (int i = 0; i < 10; i++)
  1248. {
  1249. monitorNodeIds.Add(string.Format(addressConfig.In_MesCheck.Address, i));
  1250. }
  1251. //订阅PLC地址变化
  1252. plc.SubscribeNodes("AutoSensor", monitorNodeIds, PlcCommandTrigger);
  1253. }
  1254. /// <summary>
  1255. /// 写入点位信息给PLC
  1256. /// </summary>
  1257. /// <returns></returns>
  1258. public async Task WritePositionToPlcAsync()
  1259. {
  1260. var addressConfig = _configService.GetPlcAddresses();
  1261. var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
  1262. if (plc == null || !plc.IsConnected) return;
  1263. var current = _productService.GetCurrentProduct();
  1264. if (current == null) return;
  1265. if (current.PickCameraPoints != null && current.PickCameraPoints.Count > 0)
  1266. {
  1267. foreach (var item in current.PickCameraPoints)
  1268. {
  1269. await item.WriteToPlcAddress(addressConfig.Out_PickCamera, plc);
  1270. }
  1271. }
  1272. if (current.PickPoints != null && current.PickPoints.Count > 0)
  1273. {
  1274. foreach (var item in current.PickPoints)
  1275. {
  1276. await item.WriteToPlcAddress(addressConfig.Out_Pick, plc);
  1277. }
  1278. }
  1279. if (current.SecPosCameraPoints != null && current.SecPosCameraPoints.Count > 0)
  1280. {
  1281. foreach (var item in current.SecPosCameraPoints)
  1282. {
  1283. await item.WriteToPlcAddress(addressConfig.Out_SecPosCamera, plc);
  1284. }
  1285. }
  1286. if (current.ScrewCameraPoints != null && current.ScrewCameraPoints.Count > 0)
  1287. {
  1288. foreach (var item in current.ScrewCameraPoints)
  1289. {
  1290. await item.WriteToPlcAddress(addressConfig.Out_ScrewCamera, plc);
  1291. }
  1292. }
  1293. //if (current.ScrewPoints != null && current.ScrewPoints.Count > 0)
  1294. //{
  1295. // foreach (var item in current.ScrewPoints)
  1296. // {
  1297. // await item.WriteToPlcAddress(addressConfig.Out_Screw, plc);
  1298. // }
  1299. // await plc.WriteNodeAsync(addressConfig.Out_WorkNum.Address, (Int16)current.ScrewPoints.Count);
  1300. //}
  1301. if (current.CheckCameraPoints != null && current.CheckCameraPoints.Count > 0)
  1302. {
  1303. foreach (var item in current.CheckCameraPoints)
  1304. {
  1305. await item.WriteToPlcAddress(addressConfig.Out_CheckCamera, plc);
  1306. }
  1307. }
  1308. if (current.AoiPoints != null && current.AoiPoints.Count > 0)
  1309. {
  1310. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickNum.Address, (Int16)current.AoiPoints.Count);
  1311. foreach (var item in current.AoiPoints)
  1312. {
  1313. await item.WriteToPlcAddress(addressConfig.Out_AoiCamera, plc);
  1314. }
  1315. }
  1316. else
  1317. {
  1318. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickNum.Address, 0);
  1319. }
  1320. }
  1321. PointF[] DowmCameraResults = new PointF[10];
  1322. PointF[] UpCameraPutResults = new PointF[10];
  1323. bool _LastDowmCameraExe = false;
  1324. bool _LastScrewTeachExe = false;
  1325. bool _LastUpCameraPickExe = false;
  1326. bool _LastUpCameraPutExe = false;
  1327. bool _LastUPCameracheckExe = false;
  1328. bool _LastFixedCameraPickExe = false;
  1329. bool _LastFixedCameraPutExe = false;
  1330. bool _LastFixedCameracheckExe = false;
  1331. Int16 _LastWorkStart = 0;
  1332. Int16 _LastWorkDone = 0;
  1333. Int16 _LastRequestPosition = 0;
  1334. Int16[] _LastMesCheck = new Int16[10];
  1335. Int16 _LastPickINC = 0;
  1336. DateTime[] _LastMesCheckTime = new DateTime[10];
  1337. List<Task<(bool IsSucceed, bool[] Result, string Message)>> _PrcTaskList = new List<Task<(bool IsSucceed, bool[] Result, string Message)>>();
  1338. List<Task<(bool IsSucceed, ICogImage[] Images, string Message, int cameraIndex, Guid procedureId)>> _ImageTaskList = new List<Task<(bool IsSucceed, ICogImage[] Images, string Message, int cameraIndex, Guid procedureId)>>();
  1339. private readonly object _stateLock = new object();
  1340. /// <summary>
  1341. /// PLC命令触发时
  1342. /// </summary>
  1343. /// <param name="tuple"></param>
  1344. private async void PlcCommandTrigger((string key, string nodeId, object value) tuple)
  1345. {
  1346. try
  1347. {
  1348. if (tuple.key != "AutoSensor")
  1349. {
  1350. return;
  1351. }
  1352. var addressConfig = _configService.GetPlcAddresses();
  1353. var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
  1354. if (plc == null || !plc.IsConnected) return;
  1355. // 获取当前产品
  1356. var currentProduct = _productService.GetCurrentProduct();
  1357. if (currentProduct == null)
  1358. {
  1359. return;
  1360. }
  1361. ////获取产品编码
  1362. //_productService.CurrentProductCode = currentProduct.Name;
  1363. //string productCode = plc.ReadNode<string>(addressConfig.In_Code.Address);
  1364. ////如果产品编码为空,则以当前的时间戳作为编码
  1365. //if (string.IsNullOrEmpty(productCode))
  1366. //{
  1367. // productCode = DateTime.Now.ToString("yyyyMMddHHmmssfff");
  1368. //}
  1369. // 写入3D相机长度
  1370. if (addressConfig.In_UPCameracheckExe.Address.Contains(tuple.nodeId))
  1371. {
  1372. if (tuple.value is bool state)
  1373. {
  1374. if (_LastUPCameracheckExe != state)
  1375. {
  1376. _LastUPCameracheckExe = state;
  1377. }
  1378. else
  1379. {
  1380. return;
  1381. }
  1382. if (state)
  1383. {
  1384. SendTaskMessage($"写入3D相机长度...", MessageLevel.Debug);
  1385. //相机的编号
  1386. //Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameracheckNum.Address);
  1387. // 读取相机编号
  1388. Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameracheckNum.Address);
  1389. SendTaskMessage($"编号:{cameraIndex}", MessageLevel.Info);
  1390. // 找到对应编号的 PlcPoint
  1391. var targetPoint = currentProduct.AoiPoints?.FirstOrDefault(p => p.Number == cameraIndex);
  1392. if (targetPoint == null)
  1393. {
  1394. SendTaskMessage($"未找到 AOI 点位,编号:{cameraIndex}", MessageLevel.Alarm);
  1395. await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)2);
  1396. return;
  1397. }
  1398. SetBatchPoints(new int[] { targetPoint.Camera_Data1, targetPoint.Camera_Data2, targetPoint.Camera_Data3, targetPoint.Camera_Data4 });
  1399. await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)1);
  1400. }
  1401. else
  1402. {
  1403. SendTaskMessage($"写入3D相机长度信号已关闭", MessageLevel.Alarm);
  1404. await plc.WriteNodeAsync(addressConfig.Out_UPCameracheckStatus.Address, (Int16)0);
  1405. }
  1406. }
  1407. }
  1408. // 发送点位个数
  1409. else if (addressConfig.In_RequestPosition.Address.Contains(tuple.nodeId))
  1410. {
  1411. if (tuple.value is Int16 state)
  1412. {
  1413. if (_LastRequestPosition != state)
  1414. {
  1415. _LastRequestPosition = state;
  1416. }
  1417. else
  1418. {
  1419. return;
  1420. }
  1421. if (state == 1)
  1422. {
  1423. var current = _productService.GetCurrentProduct();
  1424. if (current == null) return;
  1425. await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)1);
  1426. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickNum.Address, (Int16)current.AoiPoints.Count);
  1427. }
  1428. else
  1429. {
  1430. SendTaskMessage($"多相机坐标合并请求已结束或被取消,state={state}", MessageLevel.Alarm);
  1431. await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)0);
  1432. }
  1433. }
  1434. }
  1435. // 固定相机检测拍照
  1436. else if (addressConfig.In_FixedCameracheckExe.Address.Contains(tuple.nodeId))
  1437. {
  1438. if (tuple.value is bool state)
  1439. {
  1440. if (_LastFixedCameracheckExe != state)
  1441. {
  1442. _LastFixedCameracheckExe = state;
  1443. }
  1444. else
  1445. {
  1446. return;
  1447. }
  1448. if (state)
  1449. {
  1450. LockResult lockResult = new LockResult();
  1451. lockResult.TimeStart = DateTime.Now;
  1452. SendTaskMessage($"触发固定相机检测拍照...", MessageLevel.Debug);
  1453. // 读取相机编号
  1454. Int16 cameraIndex = plc.ReadNode<Int16>(addressConfig.In_FixedCameracheckNum.Address);
  1455. SendTaskMessage($"编号:{cameraIndex}", MessageLevel.Info);
  1456. // 找到对应编号的 PlcPoint
  1457. var targetPoint = currentProduct.AoiPoints?.FirstOrDefault(p => p.Number == cameraIndex);
  1458. if (targetPoint == null)
  1459. {
  1460. SendTaskMessage($"未找到 AOI 点位,编号:{cameraIndex}", MessageLevel.Alarm);
  1461. await plc.WriteNodeAsync(addressConfig.Out_FixedCameracheckStatus.Address, (Int16)2);
  1462. return;
  1463. }
  1464. // 收集要执行的流程 id(仅添加大于0的)
  1465. var procIds = new List<Guid>();
  1466. try
  1467. {
  1468. if (targetPoint.CameraProcedureId1 != Guid.Empty && !procIds.Contains(targetPoint.CameraProcedureId1)) procIds.Add(targetPoint.CameraProcedureId1);
  1469. }
  1470. catch { }
  1471. try
  1472. {
  1473. if (targetPoint.CameraProcedureId2 != Guid.Empty && !procIds.Contains(targetPoint.CameraProcedureId2)) procIds.Add(targetPoint.CameraProcedureId2);
  1474. }
  1475. catch { }
  1476. try
  1477. {
  1478. if (targetPoint.CameraProcedureId3 != Guid.Empty && !procIds.Contains(targetPoint.CameraProcedureId3)) procIds.Add(targetPoint.CameraProcedureId3);
  1479. }
  1480. catch { }
  1481. try
  1482. {
  1483. if (targetPoint.CameraProcedureId4 != Guid.Empty && !procIds.Contains(targetPoint.CameraProcedureId4)) procIds.Add(targetPoint.CameraProcedureId4);
  1484. }
  1485. catch { }
  1486. try
  1487. {
  1488. if (targetPoint.CameraProcedureId5 != Guid.Empty && !procIds.Contains(targetPoint.CameraProcedureId5)) procIds.Add(targetPoint.CameraProcedureId5);
  1489. }
  1490. catch { }
  1491. try
  1492. {
  1493. if (targetPoint.CameraProcedureId6 != Guid.Empty && !procIds.Contains(targetPoint.CameraProcedureId6)) procIds.Add(targetPoint.CameraProcedureId6);
  1494. }
  1495. catch { }
  1496. try
  1497. {
  1498. if (targetPoint.CameraProcedureId7 != Guid.Empty && !procIds.Contains(targetPoint.CameraProcedureId7)) procIds.Add(targetPoint.CameraProcedureId7);
  1499. }
  1500. catch { }
  1501. try
  1502. {
  1503. if (targetPoint.CameraProcedureId8 != Guid.Empty && !procIds.Contains(targetPoint.CameraProcedureId8)) procIds.Add(targetPoint.CameraProcedureId8);
  1504. }
  1505. catch { }
  1506. var sysConfig = _configService.GetSystemConfiguration();
  1507. if (sysConfig.ScannerUse == true && cameraIndex == 1 && sysConfig.CodeUse2 == true)
  1508. {
  1509. ScanValue = "";
  1510. _scanDoneEvent.Reset(); // 重要:先关门
  1511. await Scan_Client.SendAsync("T\r\n");
  1512. // 等待扫码结果,最多 3 秒
  1513. bool scanOk = await Task.Run(() => _scanDoneEvent.Wait(3000));
  1514. if (!scanOk || ScanValue.IsNullOrWhiteSpace())
  1515. {
  1516. SendTaskMessage("二维码拍照失败或超时", MessageLevel.Alarm);
  1517. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (short)3);
  1518. return;
  1519. }
  1520. code = ScanValue;
  1521. SendTaskMessage($"扫码成功,SN:{code}", MessageLevel.Info);
  1522. //这里缺少从MES获取产品配方的内容,需要补充
  1523. _LastMesCheckTime[0] = (await _mesService.GetServerTimeAsync(code, 2)).Now;
  1524. //_LastMesCheckTime[1] = DateTime.Now;
  1525. LogHelper.WriteLogMes($"【mes开始QUERY】");
  1526. SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
  1527. (bool isSuccess, string response) = await _mesService.StationGetAsync(code, "", 2);//询问mes
  1528. if (isSuccess)
  1529. {
  1530. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  1531. LogHelper.WriteLogMes($"询问mes成功");
  1532. SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
  1533. if (response != "MES功能未启用!")
  1534. {
  1535. string[] items = response.Split('\n');
  1536. string snItem = items.FirstOrDefault(f => f.Contains("sn="));
  1537. if (snItem != null)
  1538. {
  1539. ProductMainSN = snItem.Replace("sn=", "").Trim();
  1540. _productService.CurrentProductCode = ProductMainSN;
  1541. SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info);
  1542. }
  1543. string woItem = items.FirstOrDefault(f => f.Contains("wo="));
  1544. if (woItem != null)
  1545. {
  1546. wo = woItem.Replace("wo=", "").Trim();
  1547. SendTaskMessage($"产品wo:{wo}", MessageLevel.Info);
  1548. }
  1549. string modelItem = items.FirstOrDefault(f => f.Contains("model_num="));
  1550. if (modelItem != null)
  1551. {
  1552. model_num = modelItem.Replace("model_num=", "").Trim();
  1553. SendTaskMessage($"model_num:{model_num}", MessageLevel.Info);
  1554. }
  1555. string colorItem = items.FirstOrDefault(f => f.Contains("color="));
  1556. if (colorItem != null)
  1557. {
  1558. color = colorItem.Replace("color=", "").Trim();
  1559. SendTaskMessage($"color:{color}", MessageLevel.Info);
  1560. }
  1561. string ppidItem = items.FirstOrDefault(f => f.Contains("ppid="));
  1562. if (ppidItem != null)
  1563. {
  1564. ppid = ppidItem.Replace("ppid=", "").Trim();
  1565. SendTaskMessage($"ppid:{ppid}", MessageLevel.Info);
  1566. }
  1567. string stageItem = items.FirstOrDefault(f => f.Contains("stage="));
  1568. if (stageItem != null)
  1569. {
  1570. stage = stageItem.Replace("stage=", "").Trim();
  1571. SendTaskMessage($"stage:{revision}", MessageLevel.Info);
  1572. }
  1573. }
  1574. LogHelper.WriteLogMes($"【mes结束QUERY】");
  1575. SendTaskMessage($"mes结束QUERY", MessageLevel.Info);
  1576. var q = await _systemDatabaseService.QueryProductFromMesAsync(model_num, color);
  1577. if (!string.IsNullOrEmpty(q))
  1578. {
  1579. ProductList = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
  1580. Guid productId = Guid.Empty;
  1581. foreach (var itt in ProductList)
  1582. {
  1583. if (itt.Name == q)
  1584. {
  1585. productId = itt.ID;
  1586. break;
  1587. }
  1588. }
  1589. if (currentProduct.ID != productId)
  1590. {
  1591. //切换产品
  1592. _productService.LoadProduct(productId);
  1593. _productService.SetCurrentProduct(productId);
  1594. await WritePositionToPlcAsync();
  1595. SendTaskMessage($"切换产品成功", MessageLevel.Debug);
  1596. }
  1597. }
  1598. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
  1599. return;
  1600. }
  1601. else
  1602. {
  1603. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  1604. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3);
  1605. LogHelper.WriteLogMes($"询问mes失败");
  1606. SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
  1607. return;
  1608. }
  1609. }
  1610. if (sysConfig.ScannerUse == true && cameraIndex == 1 && sysConfig.CodeUse == true)
  1611. {
  1612. ScanValue = "";
  1613. _scanDoneEvent.Reset(); // 重要:先关门
  1614. await Scan_Client.SendAsync("T\r\n");
  1615. // 等待扫码结果,最多 3 秒
  1616. bool scanOk = await Task.Run(() => _scanDoneEvent.Wait(3000));
  1617. if (!scanOk || ScanValue.IsNullOrWhiteSpace())
  1618. {
  1619. SendTaskMessage("二维码拍照失败或超时", MessageLevel.Alarm);
  1620. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (short)3);
  1621. return;
  1622. }
  1623. code = ScanValue;
  1624. SendTaskMessage($"扫码成功,SN:{code}", MessageLevel.Info);
  1625. //这里缺少从MES获取产品配方的内容,需要补充
  1626. _LastMesCheckTime[0] = (await _mesService.GetServerTimeAsync(code, 2)).Now;
  1627. LogHelper.WriteLogMes($"【mes开始QUERY】");
  1628. SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
  1629. //(bool isSuccess, string response) = await _mesService.StationGetAsync(code, "", 2);//询问mes
  1630. (bool isSuccess, string response) = await _mesService.StationGetExAsync(code, "", 2);//基于电池的SN获取产品SN,询问mes
  1631. if (isSuccess)
  1632. {
  1633. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  1634. string ProductMainSN_Temp = "";
  1635. LogHelper.WriteLogMes($"询问mes成功");
  1636. SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
  1637. if (response != "MES功能未启用!")
  1638. {
  1639. string[] item = response.Split('\n');
  1640. string snItem = item.FirstOrDefault(f => f.Contains("sn="));
  1641. if (snItem != null)
  1642. {
  1643. ProductMainSN_Temp = snItem.Replace("sn=", "").Trim();
  1644. SendTaskMessage($"sn:{ProductMainSN_Temp}", MessageLevel.Info);
  1645. }
  1646. }
  1647. LogHelper.WriteLogMes($"询问mes成功");
  1648. SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
  1649. //20260214,特别版(电池组装)
  1650. (bool isSuccess2, string response2) = await _mesService.StationGetAsync(ProductMainSN_Temp, "", 2);//询问mes
  1651. if (isSuccess2)
  1652. {
  1653. LogHelper.WriteLogMes($"询问mes成功");
  1654. SendTaskMessage($"询问mes成功:{response2}", MessageLevel.Debug);
  1655. if (response2 != "MES功能未启用!")
  1656. {
  1657. string[] item = response2.Split('\n');
  1658. string snItem = item.FirstOrDefault(f => f.Contains("sn="));
  1659. if (snItem != null)
  1660. {
  1661. ProductMainSN = snItem.Replace("sn=", "").Trim();
  1662. _productService.CurrentProductCode = ProductMainSN;
  1663. SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info);
  1664. }
  1665. string woItem = item.FirstOrDefault(f => f.Contains("wo="));
  1666. if (woItem != null)
  1667. {
  1668. wo = woItem.Replace("wo=", "").Trim();
  1669. SendTaskMessage($"产品wo:{wo}", MessageLevel.Info);
  1670. }
  1671. string modelItem = item.FirstOrDefault(f => f.Contains("model_num="));
  1672. if (modelItem != null)
  1673. {
  1674. model_num = modelItem.Replace("model_num=", "").Trim();
  1675. SendTaskMessage($"model_num:{model_num}", MessageLevel.Info);
  1676. }
  1677. string colorItem = item.FirstOrDefault(f => f.Contains("color="));
  1678. if (colorItem != null)
  1679. {
  1680. color = colorItem.Replace("color=", "").Trim();
  1681. SendTaskMessage($"color:{color}", MessageLevel.Info);
  1682. }
  1683. string ppidItem = item.FirstOrDefault(f => f.Contains("ppid="));
  1684. if (ppidItem != null)
  1685. {
  1686. ppid = ppidItem.Replace("ppid=", "").Trim();
  1687. SendTaskMessage($"ppid:{ppid}", MessageLevel.Info);
  1688. }
  1689. string stageItem = item.FirstOrDefault(f => f.Contains("stage="));
  1690. if (stageItem != null)
  1691. {
  1692. stage = stageItem.Replace("stage=", "").Trim();
  1693. SendTaskMessage($"stage:{revision}", MessageLevel.Info);
  1694. }
  1695. }
  1696. LogHelper.WriteLogMes($"第二次询问mes成功");
  1697. SendTaskMessage($"第二次询问mes成功:{response2}", MessageLevel.Debug);
  1698. var q = await _systemDatabaseService.QueryProductFromMesAsync(model_num, color);
  1699. if (!string.IsNullOrEmpty(q))
  1700. {
  1701. ProductList = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
  1702. Guid productId = Guid.Empty;
  1703. foreach (var itt in ProductList)
  1704. {
  1705. if (itt.Name == q)
  1706. {
  1707. productId = itt.ID;
  1708. break;
  1709. }
  1710. }
  1711. if (currentProduct.ID != productId)
  1712. {
  1713. //切换产品
  1714. _productService.LoadProduct(productId);
  1715. _productService.SetCurrentProduct(productId);
  1716. await WritePositionToPlcAsync();
  1717. SendTaskMessage($"切换产品成功", MessageLevel.Debug);
  1718. }
  1719. }
  1720. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
  1721. }
  1722. else
  1723. {
  1724. LogHelper.WriteLogMes($"第二次询问mes失败");
  1725. SendTaskMessage($"第二次询问mes失败:{response2}", MessageLevel.Error);
  1726. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3);
  1727. }
  1728. }
  1729. else
  1730. {
  1731. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  1732. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3);
  1733. LogHelper.WriteLogMes($"询问mes失败");
  1734. SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
  1735. }
  1736. return;
  1737. }
  1738. if (procIds.Count == 0)
  1739. {
  1740. SendTaskMessage($"Point#{cameraIndex} 未配置任何视觉流程 (CameraProcedureId1/2/3)", MessageLevel.Alarm);
  1741. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
  1742. return;
  1743. }
  1744. var cameraProcedures = currentProduct.CameraProcedures;
  1745. if (cameraProcedures == null || cameraProcedures.Count == 0)
  1746. {
  1747. SendTaskMessage($"当前产品未配置 CameraProcedures,无法执行视觉流程", MessageLevel.Alarm);
  1748. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
  1749. return;
  1750. }
  1751. if (cameraIndex == currentProduct.PhotoCount)
  1752. {
  1753. _PrcTaskList.Clear();
  1754. lock (_stateLock)
  1755. {
  1756. lockResultsAll.Clear();
  1757. }
  1758. App.Current.Dispatcher.Invoke(() =>
  1759. {
  1760. _eventAggregator.GetEvent<LockResetNotification>().Publish();
  1761. });
  1762. }
  1763. if (sysConfig.CodeUse==true && cameraIndex == 1)
  1764. {
  1765. var cts = new CancellationTokenSource();
  1766. // CameraProcedureId 存储的是具体的视觉流程 Id(ProcedureModel.Id),
  1767. // 需要在所有 CameraProcedures 的 ProcedureModels 中查找匹配的流程。
  1768. ProcedureModel selectedProcedure = null;
  1769. try
  1770. {
  1771. cameraProcedures = currentProduct.CameraProcedures;
  1772. if (cameraProcedures != null)
  1773. {
  1774. foreach (var cp in cameraProcedures)
  1775. {
  1776. if (cp?.ProcedureModels == null) continue;
  1777. selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == targetPoint.CameraProcedureId1);
  1778. if (selectedProcedure != null) break;
  1779. }
  1780. }
  1781. }
  1782. catch (Exception ex)
  1783. {
  1784. LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
  1785. }
  1786. if (selectedProcedure == null)
  1787. {
  1788. SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{cameraIndex} ProcedureId={targetPoint.CameraProcedureId1}", MessageLevel.Alarm);
  1789. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
  1790. return;
  1791. }
  1792. if (selectedProcedure.Id == currentProduct.FixedDownCameraProcedureId && sysConfig.TurnOnAllLightUse == true)
  1793. {
  1794. await _remoteCommandService.SetLightBeforePhoto(selectedProcedure);
  1795. }
  1796. var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint2(selectedProcedure, null, null, cts.Token);
  1797. if (visionResult.IsSucceed)
  1798. {
  1799. code = visionResult.X.ToUpper();
  1800. SendTaskMessage($"扫码成功,SN:{code}", MessageLevel.Info);
  1801. //这里缺少从MES获取产品配方的内容,需要补充
  1802. _LastMesCheckTime[0] = (await _mesService.GetServerTimeAsync(code, 2)).Now;
  1803. LogHelper.WriteLogMes($"【mes开始QUERY】");
  1804. SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
  1805. //(bool isSuccess, string response) = await _mesService.StationGetAsync(code, "", 2);//询问mes
  1806. (bool isSuccess, string response) = await _mesService.StationGetExAsync(code, "", 2);//基于电池的SN获取产品SN,询问mes
  1807. if (isSuccess)
  1808. {
  1809. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  1810. string ProductMainSN_Temp = "";
  1811. LogHelper.WriteLogMes($"询问mes成功");
  1812. SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
  1813. if (response != "MES功能未启用!")
  1814. {
  1815. string[] item = response.Split('\n');
  1816. string snItem = item.FirstOrDefault(f => f.Contains("sn="));
  1817. if (snItem != null)
  1818. {
  1819. ProductMainSN_Temp = snItem.Replace("sn=", "").Trim();
  1820. SendTaskMessage($"sn:{ProductMainSN_Temp}", MessageLevel.Info);
  1821. }
  1822. }
  1823. LogHelper.WriteLogMes($"询问mes成功");
  1824. SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
  1825. //20260214,特别版(电池组装)
  1826. (bool isSuccess2, string response2) = await _mesService.StationGetAsync(ProductMainSN_Temp, "", 2);//询问mes
  1827. if (isSuccess2)
  1828. {
  1829. LogHelper.WriteLogMes($"询问mes成功");
  1830. SendTaskMessage($"询问mes成功:{response2}", MessageLevel.Debug);
  1831. if (response2 != "MES功能未启用!")
  1832. {
  1833. string[] item = response2.Split('\n');
  1834. string snItem = item.FirstOrDefault(f => f.Contains("sn="));
  1835. if (snItem != null)
  1836. {
  1837. ProductMainSN = snItem.Replace("sn=", "").Trim();
  1838. _productService.CurrentProductCode = ProductMainSN;
  1839. SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info);
  1840. }
  1841. string woItem = item.FirstOrDefault(f => f.Contains("wo="));
  1842. if (woItem != null)
  1843. {
  1844. wo = woItem.Replace("wo=", "").Trim();
  1845. SendTaskMessage($"产品wo:{wo}", MessageLevel.Info);
  1846. }
  1847. string modelItem = item.FirstOrDefault(f => f.Contains("model_num="));
  1848. if (modelItem != null)
  1849. {
  1850. model_num = modelItem.Replace("model_num=", "").Trim();
  1851. SendTaskMessage($"model_num:{model_num}", MessageLevel.Info);
  1852. }
  1853. string colorItem = item.FirstOrDefault(f => f.Contains("color="));
  1854. if (colorItem != null)
  1855. {
  1856. color = colorItem.Replace("color=", "").Trim();
  1857. SendTaskMessage($"color:{color}", MessageLevel.Info);
  1858. }
  1859. string ppidItem = item.FirstOrDefault(f => f.Contains("ppid="));
  1860. if (ppidItem != null)
  1861. {
  1862. ppid = ppidItem.Replace("ppid=", "").Trim();
  1863. SendTaskMessage($"ppid:{ppid}", MessageLevel.Info);
  1864. }
  1865. string stageItem = item.FirstOrDefault(f => f.Contains("stage="));
  1866. if (stageItem != null)
  1867. {
  1868. stage = stageItem.Replace("stage=", "").Trim();
  1869. SendTaskMessage($"stage:{revision}", MessageLevel.Info);
  1870. }
  1871. }
  1872. LogHelper.WriteLogMes($"第二次询问mes成功");
  1873. SendTaskMessage($"第二次询问mes成功:{response2}", MessageLevel.Debug);
  1874. var q = await _systemDatabaseService.QueryProductFromMesAsync(model_num, color);
  1875. if (!string.IsNullOrEmpty(q))
  1876. {
  1877. ProductList = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
  1878. Guid productId = Guid.Empty;
  1879. foreach (var itt in ProductList)
  1880. {
  1881. if (itt.Name == q)
  1882. {
  1883. productId = itt.ID;
  1884. break;
  1885. }
  1886. }
  1887. if (currentProduct.ID != productId)
  1888. {
  1889. //切换产品
  1890. _productService.LoadProduct(productId);
  1891. _productService.SetCurrentProduct(productId);
  1892. await WritePositionToPlcAsync();
  1893. SendTaskMessage($"切换产品成功", MessageLevel.Debug);
  1894. }
  1895. }
  1896. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
  1897. }
  1898. else
  1899. {
  1900. LogHelper.WriteLogMes($"第二次询问mes失败");
  1901. SendTaskMessage($"第二次询问mes失败:{response2}", MessageLevel.Error);
  1902. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3);
  1903. }
  1904. }
  1905. else
  1906. {
  1907. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  1908. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3);
  1909. LogHelper.WriteLogMes($"询问mes失败");
  1910. SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
  1911. }
  1912. }
  1913. else
  1914. {
  1915. SendTaskMessage($"扫码失败", MessageLevel.Alarm);
  1916. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3);
  1917. }
  1918. return;
  1919. }
  1920. if (sysConfig.CodeUse2 == true && cameraIndex == 1)
  1921. {
  1922. var cts = new CancellationTokenSource();
  1923. // CameraProcedureId 存储的是具体的视觉流程 Id(ProcedureModel.Id),
  1924. // 需要在所有 CameraProcedures 的 ProcedureModels 中查找匹配的流程。
  1925. ProcedureModel selectedProcedure = null;
  1926. try
  1927. {
  1928. cameraProcedures = currentProduct.CameraProcedures;
  1929. if (cameraProcedures != null)
  1930. {
  1931. foreach (var cp in cameraProcedures)
  1932. {
  1933. if (cp?.ProcedureModels == null) continue;
  1934. selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == targetPoint.CameraProcedureId1);
  1935. if (selectedProcedure != null) break;
  1936. }
  1937. }
  1938. }
  1939. catch (Exception ex)
  1940. {
  1941. LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
  1942. }
  1943. if (selectedProcedure == null)
  1944. {
  1945. SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{cameraIndex} ProcedureId={targetPoint.CameraProcedureId1}", MessageLevel.Alarm);
  1946. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
  1947. return;
  1948. }
  1949. var ctsAll = new CancellationTokenSource();
  1950. if (selectedProcedure.Id == currentProduct.FixedDownCameraProcedureId && sysConfig.TurnOnAllLightUse == true)
  1951. {
  1952. await _remoteCommandService.SetLightBeforePhoto(selectedProcedure);
  1953. }
  1954. var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint2(selectedProcedure, null, null, ctsAll.Token);
  1955. if (visionResult.IsSucceed)
  1956. {
  1957. code = visionResult.X;
  1958. ProductMainSN = visionResult.X;
  1959. SendTaskMessage($"扫码成功,SN:{code}", MessageLevel.Info);
  1960. //这里缺少从MES获取产品配方的内容,需要补充
  1961. _LastMesCheckTime[0] = (await _mesService.GetServerTimeAsync(code, 2)).Now;
  1962. //_LastMesCheckTime[1] = DateTime.Now;
  1963. LogHelper.WriteLogMes($"【mes开始QUERY】");
  1964. SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
  1965. (bool isSuccess, string response) = await _mesService.StationGetAsync(code, "", 2);//询问mes
  1966. if (isSuccess)
  1967. {
  1968. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  1969. LogHelper.WriteLogMes($"询问mes成功");
  1970. SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
  1971. if (response != "MES功能未启用!")
  1972. {
  1973. string[] items = response.Split('\n');
  1974. string snItem = items.FirstOrDefault(f => f.Contains("sn="));
  1975. if (snItem != null)
  1976. {
  1977. ProductMainSN = snItem.Replace("sn=", "").Trim();
  1978. _productService.CurrentProductCode = ProductMainSN;
  1979. SendTaskMessage($"产品主sn:{ProductMainSN}", MessageLevel.Info);
  1980. }
  1981. string woItem = items.FirstOrDefault(f => f.Contains("wo="));
  1982. if (woItem != null)
  1983. {
  1984. wo = woItem.Replace("wo=", "").Trim();
  1985. SendTaskMessage($"产品wo:{wo}", MessageLevel.Info);
  1986. }
  1987. string modelItem = items.FirstOrDefault(f => f.Contains("model_num="));
  1988. if (modelItem != null)
  1989. {
  1990. model_num = modelItem.Replace("model_num=", "").Trim();
  1991. SendTaskMessage($"model_num:{model_num}", MessageLevel.Info);
  1992. }
  1993. string colorItem = items.FirstOrDefault(f => f.Contains("color="));
  1994. if (colorItem != null)
  1995. {
  1996. color = colorItem.Replace("color=", "").Trim();
  1997. SendTaskMessage($"color:{color}", MessageLevel.Info);
  1998. }
  1999. string ppidItem = items.FirstOrDefault(f => f.Contains("ppid="));
  2000. if (ppidItem != null)
  2001. {
  2002. ppid = ppidItem.Replace("ppid=", "").Trim();
  2003. SendTaskMessage($"ppid:{ppid}", MessageLevel.Info);
  2004. }
  2005. string stageItem = items.FirstOrDefault(f => f.Contains("stage="));
  2006. if (stageItem != null)
  2007. {
  2008. stage = stageItem.Replace("stage=", "").Trim();
  2009. SendTaskMessage($"stage:{revision}", MessageLevel.Info);
  2010. }
  2011. }
  2012. LogHelper.WriteLogMes($"【mes结束QUERY】");
  2013. SendTaskMessage($"mes结束QUERY", MessageLevel.Info);
  2014. var q = await _systemDatabaseService.QueryProductFromMesAsync(model_num, color);
  2015. if (!string.IsNullOrEmpty(q))
  2016. {
  2017. ProductList = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
  2018. Guid productId = Guid.Empty;
  2019. foreach (var itt in ProductList)
  2020. {
  2021. if (itt.Name == q)
  2022. {
  2023. productId = itt.ID;
  2024. break;
  2025. }
  2026. }
  2027. if (currentProduct.ID != productId)
  2028. {
  2029. //切换产品
  2030. _productService.LoadProduct(productId);
  2031. _productService.SetCurrentProduct(productId);
  2032. await WritePositionToPlcAsync();
  2033. SendTaskMessage($"切换产品成功", MessageLevel.Debug);
  2034. }
  2035. }
  2036. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
  2037. return;
  2038. }
  2039. else
  2040. {
  2041. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  2042. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3);
  2043. LogHelper.WriteLogMes($"询问mes失败");
  2044. SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
  2045. }
  2046. }
  2047. else
  2048. {
  2049. SendTaskMessage($"扫码失败", MessageLevel.Alarm);
  2050. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)3);
  2051. }
  2052. return;
  2053. }
  2054. _ImageTaskList.Clear();
  2055. foreach (var prcId in procIds)
  2056. {
  2057. _ImageTaskList.Add(GrabImageEx(cameraIndex, prcId));
  2058. }
  2059. if (cameraIndex != currentProduct.PhotoCountStop)
  2060. {
  2061. //直接放行,执行下一个检测点
  2062. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
  2063. }
  2064. if (_ImageTaskList.Count > 0)//如果2D取图有队列
  2065. {
  2066. var ImageTaskResults = await Task.WhenAll(_ImageTaskList);
  2067. foreach (var item in ImageTaskResults)
  2068. {
  2069. if (item.IsSucceed)
  2070. {
  2071. bool Is3d = Is3D(item.procedureId);
  2072. _PrcTaskList.Add(ExecuteProcedureAsync(item.cameraIndex, item.procedureId, item.Images, Is3d));
  2073. //_PrcTaskList.Add(ExecuteProcedureAsync(cameraIndex, prcId, imageData.imges));
  2074. }
  2075. else
  2076. {
  2077. SendTaskMessage($"图像采集失败!{item.cameraIndex}: {item.procedureId}", MessageLevel.Alarm);
  2078. }
  2079. }
  2080. }
  2081. //如果最后一个拍照点,则需要等待前面所有的拍照处理完成
  2082. if (cameraIndex == currentProduct.PhotoCountStop)
  2083. {
  2084. //等待所有的图像处理流程处理完成
  2085. var results = await Task.WhenAll(_PrcTaskList);
  2086. //结果输出
  2087. bool resultFlog = true;
  2088. foreach (var item in results)
  2089. {
  2090. if (!item.IsSucceed || item.Result == null)
  2091. {
  2092. resultFlog = false;
  2093. break;
  2094. }
  2095. else
  2096. {
  2097. foreach (var item_1 in item.Result)
  2098. {
  2099. if (!item_1)
  2100. {
  2101. resultFlog = false;
  2102. break;
  2103. }
  2104. }
  2105. }
  2106. }
  2107. //全部OK
  2108. if (resultFlog)
  2109. {
  2110. SendTaskMessage($"检测执行成功", MessageLevel.Debug);
  2111. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)1);
  2112. }
  2113. //存在NG
  2114. else
  2115. {
  2116. SendTaskMessage($"检测执行失败", MessageLevel.Alarm);
  2117. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)2);
  2118. }
  2119. }
  2120. }
  2121. else
  2122. {
  2123. SendTaskMessage($"触发固定相机检测拍照信号已关闭", MessageLevel.Alarm);
  2124. await plc.WriteNodeAsync(addressConfig.Out_FixedCameraPickStatus.Address, (Int16)0);
  2125. }
  2126. }
  2127. }
  2128. // 过站检查
  2129. else
  2130. {
  2131. for (int i = 0; i < 10; i++)
  2132. {
  2133. if (string.Format(addressConfig.In_MesCheck.Address, i).Contains(tuple.nodeId))
  2134. {
  2135. if (tuple.value is Int16 state)
  2136. {
  2137. if (_LastMesCheck[i] != state)
  2138. {
  2139. _LastMesCheck[i] = state;
  2140. }
  2141. else
  2142. {
  2143. return;
  2144. }
  2145. var sysConfig = _configService.GetSystemConfiguration();
  2146. if (sysConfig.CodeUse == true && state == 1)
  2147. {
  2148. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
  2149. return;
  2150. }
  2151. if (sysConfig.CodeUse2 == true && state == 1)
  2152. {
  2153. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
  2154. return;
  2155. }
  2156. if (sysConfig.CodeUse == false && sysConfig.CodeUse2 == false)
  2157. {
  2158. code = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, i));
  2159. }
  2160. var homeview = _container.Resolve<HomeViewModel>();
  2161. //过站检查
  2162. if (state == 1)
  2163. {
  2164. //这里缺少从MES获取产品配方的内容,需要补充
  2165. _LastMesCheckTime[i] = (await _mesService.GetServerTimeAsync(code, 2)).Now;
  2166. if (homeview.IsNoCode == false)
  2167. {
  2168. var device = _configService.GetDeviceInfo();
  2169. code = device.XnSN;
  2170. }
  2171. LogHelper.WriteLogMes($"【mes开始QUERY】");
  2172. SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
  2173. ShowMes_Query = false;
  2174. (bool isSuccess, string response) = await _mesService.StationGetAsync(code, "", 2);//询问mes
  2175. if (i == 0)
  2176. {
  2177. SendTaskMessage($"收到当前过站检查请求(当站是否生产)...", MessageLevel.Debug);
  2178. }
  2179. else
  2180. {
  2181. SendTaskMessage($"收到{i}过站检查请求(当站是否生产)...", MessageLevel.Debug);
  2182. }
  2183. if (isSuccess)
  2184. {
  2185. string[] item = response.Split('\n');
  2186. //获取产品主sn和wo用于后续上传数据使用
  2187. string snItem = item.FirstOrDefault(f => f.Contains("sn="));
  2188. if (snItem != null)
  2189. {
  2190. ProductMainSN = snItem.Replace("sn=", "").Trim();
  2191. if (i == 0)
  2192. {
  2193. _productService.CurrentProductCode = ProductMainSN;
  2194. }
  2195. SendTaskMessage($"产品主sn:{ProductMainSN[i]}", MessageLevel.Info);
  2196. }
  2197. string woItem = item.FirstOrDefault(f => f.Contains("wo="));
  2198. if (woItem != null)
  2199. {
  2200. wo = woItem.Replace("wo=", "").Trim();
  2201. SendTaskMessage($"工单信息:{wo[i]}", MessageLevel.Info);
  2202. }
  2203. string modelItem = item.FirstOrDefault(f => f.Contains("model_num="));
  2204. if (modelItem != null)
  2205. {
  2206. model_num = modelItem.Replace("model_num=", "").Trim();
  2207. SendTaskMessage($"model_num:{model_num}", MessageLevel.Info);
  2208. }
  2209. string colorItem = item.FirstOrDefault(f => f.Contains("color="));
  2210. if (colorItem != null)
  2211. {
  2212. color = colorItem.Replace("color=", "").Trim();
  2213. SendTaskMessage($"color:{color}", MessageLevel.Info);
  2214. }
  2215. string ppidItem = item.FirstOrDefault(f => f.Contains("ppid="));
  2216. if (ppidItem != null)
  2217. {
  2218. ppid = ppidItem.Replace("ppid=", "").Trim();
  2219. SendTaskMessage($"ppid:{ppid}", MessageLevel.Info);
  2220. }
  2221. string stageItem = item.FirstOrDefault(f => f.Contains("stage="));
  2222. if (stageItem != null)
  2223. {
  2224. stage = stageItem.Replace("stage=", "").Trim();
  2225. SendTaskMessage($"stage:{revision}", MessageLevel.Info);
  2226. }
  2227. ShowMes_Query = true;
  2228. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  2229. //切换产品
  2230. if (i == 0)//i=0时才会切换产品
  2231. {
  2232. var q = await _systemDatabaseService.QueryProductFromMesAsync(model_num, color);
  2233. if (!string.IsNullOrEmpty(q))
  2234. {
  2235. ProductList = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
  2236. Guid productId = Guid.Empty;
  2237. foreach (var itt in ProductList)
  2238. {
  2239. if (itt.Name == q)
  2240. {
  2241. productId = itt.ID;
  2242. break;
  2243. }
  2244. }
  2245. if (currentProduct.ID != productId)
  2246. {
  2247. //切换产品
  2248. _productService.LoadProduct(productId);
  2249. _productService.SetCurrentProduct(productId);
  2250. await WritePositionToPlcAsync();
  2251. SendTaskMessage($"切换产品成功", MessageLevel.Debug);
  2252. }
  2253. }
  2254. }
  2255. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
  2256. LogHelper.WriteLogMes($"【mes结束QUERY】");
  2257. SendTaskMessage($"mes结束QUERY", MessageLevel.Info);
  2258. return;
  2259. }
  2260. else
  2261. {
  2262. //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
  2263. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
  2264. LogHelper.WriteLogMes($"询问mes失败");
  2265. SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
  2266. }
  2267. LogHelper.WriteLogMes($"【mes结束QUERY】");
  2268. SendTaskMessage($"mes结束QUERY", MessageLevel.Info);
  2269. }
  2270. // 上传本站数据
  2271. else if (state == 2)
  2272. {
  2273. //获取当前工位的配置
  2274. var stationConfig = _configService.GetDeviceInfo();
  2275. List<DataFormCtq> DFC = new List<DataFormCtq>();
  2276. SendTaskMessage($"收到{i}上传本站数据请求...", MessageLevel.Debug);
  2277. //这里缺少上传MES的本站数据结果及开始和结束时间,需要补充
  2278. //从服务器中获取当前时间
  2279. var serverTimeResult = await _mesService.GetServerTimeAsync(ProductMainSN, 2);
  2280. double ct = serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds;
  2281. if (i == 0)
  2282. {
  2283. CTtime = ct;
  2284. }
  2285. //读取产品结果
  2286. Int16 resultIndex = plc.ReadNode<Int16>(string.Format(addressConfig.In_Result.Address, i));
  2287. if (homeview.IsResultTrue == false)
  2288. {
  2289. resultIndex = 1;
  2290. }
  2291. //Int16 resultIndex = 1;
  2292. //目前只记录当前站
  2293. if (i == 0)
  2294. await _systemDatabaseService.RecordProductionAsync(new ProductionRecord()
  2295. {
  2296. ProductName = currentProduct.Name,
  2297. ProductCode = ProductMainSN,
  2298. DeviceId = i,
  2299. DeviceName = "",
  2300. Category = resultIndex == 1 ? "OK" : "NG",
  2301. Quantity = 1,
  2302. Remark = $"TotalSeconds:{DateTime.UtcNow.Subtract(_LastMesCheckTime[i]).TotalSeconds.ToString("F2")}",
  2303. });
  2304. LogHelper.WriteLogMes($"【mes开始ADD】");
  2305. SendTaskMessage($"mes开始ADD", MessageLevel.Info);
  2306. StringBuilder submitData = new StringBuilder();
  2307. foreach (var item in lockResultsAll)
  2308. {
  2309. submitData.Append($"{item.PhotoName}={item.ResultData}");
  2310. }
  2311. ShowMes_Result = resultIndex == 1 ? true : false;
  2312. //(bool isSuccess, string response) = await _mesService.SubmitGetAsync(ProductMainSN, "", MesData.Replace("--", "-"), resultIndex == 1 ? true : false, _LastMesCheckTime[i], DateTime.UtcNow);
  2313. (bool isSuccess, string response) = await _mesService.SubmitGetAsync(ProductMainSN, "", submitData.ToString(), resultIndex == 1 ? true : false, _LastMesCheckTime[i], serverTimeResult.Now);
  2314. if (isSuccess)
  2315. {
  2316. LogHelper.WriteLogMes($"上传mes成功");
  2317. SendTaskMessage($"上传mes成功", MessageLevel.Debug);
  2318. }
  2319. else
  2320. {
  2321. LogHelper.WriteLogMes($"上传mes失败");
  2322. SendTaskMessage($"上传mes失败", MessageLevel.Error);
  2323. }
  2324. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3);
  2325. //是否保存当前的产品记录至CSV?
  2326. if (stationConfig.SaveCsv)
  2327. {
  2328. //判断锁付路径字符串是否为空,如果不为空则保存,否则不保存
  2329. if (!string.IsNullOrEmpty(stationConfig.SaveCsvPath))
  2330. {
  2331. foreach (var item in lockResultsAll)
  2332. {
  2333. for (int k = 1; k <=8; k++)
  2334. {
  2335. if (item.PhotoName == "-"+"_"+k.ToString())
  2336. {
  2337. item.PhotoName = "'-" + "_" + k.ToString();
  2338. }
  2339. if (item.PhotoName == "=" + "_" + k.ToString())
  2340. {
  2341. item.PhotoName = "'=" + "_" + k.ToString();
  2342. }
  2343. }
  2344. DFC.Add(new DataFormCtq
  2345. {
  2346. PPID = ppid,
  2347. PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
  2348. PROCESS_START_TIME = _LastMesCheckTime[i].ToString("o"),
  2349. CTQ_NAME = item.PhotoName,
  2350. CTQ_VALUE = item.ResultData.Replace(",", ";"),
  2351. CTQ_LSL = item.DownLimit,
  2352. CTQ_USL = item.UpLimit,
  2353. PROCESS_END_TIME = serverTimeResult.Now.ToString("o"),
  2354. SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
  2355. COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
  2356. REVISION = stage,
  2357. WO = wo,
  2358. MFG_LOT = stationConfig.DataInfo.MFG_LOT,
  2359. MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
  2360. PROCESS_OUTCOME = item.PhotoPassed == "OK" ? "PASS" : "FAIL",
  2361. PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
  2362. CTQ_UNIT_OF_MEASURE = "mm",
  2363. ERROR_MESSAGE = item.PhotoPassed == "OK" ? "" : $"{item.PhotoName} OOS",
  2364. PD_ATTR_01= ProductMainSN,
  2365. PD_ATTR_02 = item.MidLimit,
  2366. PD_ATTR_03 = "",
  2367. PD_ATTR_04 = "",
  2368. PD_ATTR_05 = ""
  2369. });
  2370. }
  2371. bool recordResult = RecordStationResult(i, DFC, ProductMainSN, serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds, _LastMesCheckTime[i], stationConfig.SaveCsvPath);
  2372. if (recordResult)
  2373. {
  2374. SendTaskMessage($"{i}:{stationConfig.DeviceName}产品记录保存成功", MessageLevel.Debug);
  2375. //上传数据
  2376. try
  2377. {
  2378. if (stationConfig.EnableMES)
  2379. {
  2380. DateTime dt = DateTime.Now;
  2381. string filename = $"{ProductMainSN}_{dt.ToString("yyyyMMddHHmmss")}";
  2382. var device = _configService.GetDeviceInfo();
  2383. var config = _configService.GetSystemConfiguration();
  2384. (bool isSuc, string resp) = await _mesService.SendFtpFileAsync(ProductMainSN, filename);
  2385. if (isSuc)
  2386. {
  2387. LogHelper.WriteLogMes($"上传数据成功");
  2388. SendTaskMessage($"上传数据成功", MessageLevel.Debug);
  2389. string filePath = $"D:\\image\\Recored\\{dt.ToString("yyyy-MM")}\\{dt.ToString("MM-dd")}\\{currentProduct.Name}\\{ProductMainSN}";
  2390. string csvfilename = $"{i}_{stationConfig.DeviceName}_{dt.ToString("yyyy-MM-dd")}";
  2391. //复制csv
  2392. string source_csv = $"{stationConfig.SaveCsvPath}\\{dt.ToString("yyyy-MM")}\\{i}_{stationConfig.DeviceName}_{dt.ToString("yyyy-MM-dd")}.csv";
  2393. string target_csv = Path.Combine(filePath, Path.GetFileName(source_csv));
  2394. File.Copy(source_csv, target_csv, true);
  2395. //复制log
  2396. string source_log = $"..\\Log\\LogInfo\\{dt.ToString("yyyy-MM")}\\{dt.ToString("yyyy-MM-dd")}.txt";
  2397. string target_log = Path.Combine(filePath, Path.GetFileName(source_log));
  2398. File.Copy(source_log, target_log, true);
  2399. CompressionImage(filePath, filename, device.Station, device.FixtureId);
  2400. //上传csv
  2401. bool isAfter20 = dt.Hour >= 20;
  2402. //判断是否是新的一天
  2403. bool isNewDay = dt.Date != _lastCompressDate.Date;
  2404. //当天还没执行过压缩
  2405. if (isAfter20 && isNewDay && !_hasCompressedToday)
  2406. {
  2407. // 执行压缩
  2408. CompressionImage(source_csv, csvfilename, device.Station, device.FixtureId);
  2409. _lastCompressDate = dt;
  2410. _hasCompressedToday = true;
  2411. LogHelper.WriteLogMes("csv上传数据成功");
  2412. SendTaskMessage($"csv上传数据成功", MessageLevel.Debug);
  2413. }
  2414. // 跨天后重置当天执行标记
  2415. if (!isNewDay && _hasCompressedToday)
  2416. {
  2417. _hasCompressedToday = false;
  2418. }
  2419. }
  2420. else
  2421. {
  2422. LogHelper.WriteLogMes($"上传数据失败");
  2423. SendTaskMessage($"上传数据失败", MessageLevel.Error);
  2424. }
  2425. }
  2426. else
  2427. {
  2428. LogHelper.WriteLogMes($"未启用mes");
  2429. SendTaskMessage($"未启用mes", MessageLevel.Error);
  2430. }
  2431. }
  2432. catch (Exception ex)
  2433. {
  2434. SendTaskMessage($"上传数据时出错:{ex.Message}", MessageLevel.Error);
  2435. LogHelper.WriteLogError($"上传数据时出错", ex);
  2436. }
  2437. }
  2438. else
  2439. {
  2440. SendTaskMessage($"{i}:{stationConfig.DeviceName}产品记录保存失败", MessageLevel.Error);
  2441. }
  2442. }
  2443. else
  2444. {
  2445. SendTaskMessage($"{i}:{stationConfig.DeviceName}工位未配置保存路径,无法保存产品记录", MessageLevel.Error);
  2446. }
  2447. }
  2448. else
  2449. {
  2450. SendTaskMessage($"{i}:{stationConfig.DeviceName}工位未配置保存产品记录", MessageLevel.Debug);
  2451. }
  2452. //WriteProductLog(lockResultsAll, code, CTtime);
  2453. lock (_stateLock)
  2454. {
  2455. lockResultsAll.Clear();
  2456. }
  2457. ProductMainSN = "";
  2458. LogHelper.WriteLogMes($"【mes结束ADD】");
  2459. SendTaskMessage($"mes结束ADD", MessageLevel.Info);
  2460. }
  2461. else
  2462. {
  2463. SendTaskMessage($"{i}过站检查信号:state={state},处理为默认状态", MessageLevel.Alarm);
  2464. await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)0);
  2465. }
  2466. }
  2467. }
  2468. }
  2469. }
  2470. }
  2471. catch (Exception ex)
  2472. {
  2473. SendTaskMessage(ex.Message, MessageLevel.Error);
  2474. }
  2475. }
  2476. /// <summary>
  2477. /// 异步执行流程拍照
  2478. /// </summary>
  2479. /// <param name="pointIndex"></param>
  2480. /// <param name="procedureId"></param>
  2481. /// <returns></returns>
  2482. private Task<(bool IsSucceed, bool[] Result, string Message)> ExecuteProcedureAsync(int pointIndex, Guid procedureId)
  2483. {
  2484. return Task.Run(async () =>
  2485. {
  2486. List<bool> results = new List<bool>();
  2487. // 获取当前产品
  2488. var currentProduct = _productService.GetCurrentProduct();
  2489. if (currentProduct == null)
  2490. {
  2491. return (false, null, "当前产品为空,未加载产品!");
  2492. }
  2493. var cameraProcedures = currentProduct.CameraProcedures;
  2494. if (cameraProcedures == null || cameraProcedures.Count == 0)
  2495. {
  2496. SendTaskMessage($"当前产品未配置 CameraProcedures,无法执行视觉流程", MessageLevel.Alarm);
  2497. return (false, null, $"当前产品未配置 CameraProcedures,无法执行视觉流程");
  2498. }
  2499. var ctsAll = new CancellationTokenSource();
  2500. try
  2501. {
  2502. ProcedureModel selectedProcedure = null;
  2503. try
  2504. {
  2505. foreach (var cp in cameraProcedures)
  2506. {
  2507. if (cp?.ProcedureModels == null) continue;
  2508. selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == procedureId);
  2509. if (selectedProcedure != null) break;
  2510. }
  2511. }
  2512. catch (Exception ex)
  2513. {
  2514. LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
  2515. }
  2516. if (selectedProcedure == null)
  2517. {
  2518. SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={pointIndex}", MessageLevel.Alarm);
  2519. return (false, null, $"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId}");
  2520. }
  2521. SendTaskMessage($"开始执行 AOI 流程 (Point#{pointIndex}) 流程Id={pointIndex}", MessageLevel.Debug);
  2522. try
  2523. {
  2524. //1. 执行拍照,图像处理
  2525. var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint1(selectedProcedure, null, null, ctsAll.Token);
  2526. if (visionResult.Count == 0)
  2527. {
  2528. SendTaskMessage("Count值为0", MessageLevel.Alarm);
  2529. return (false, null, $"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId}");
  2530. }
  2531. //2. 结果分析
  2532. for (int i = 1; i <= visionResult.Count; i++)
  2533. {
  2534. LockResult lockResult1 = new LockResult();
  2535. //if (pointIndex == currentProduct.PhotoCount && selectedProcedure.Id == currentProduct.FixedUpCamera1ProcedureId && i == 1)
  2536. //{
  2537. // lockResult1.Number = 1;
  2538. //}
  2539. string[] strpoints1 = visionResult.Items[i].Split(',');
  2540. lockResult1.PhotoName = strpoints1[0];
  2541. string[] body1 = strpoints1[1].Split(";");
  2542. string body2 = null;
  2543. if (body1.Length == 8)
  2544. {
  2545. body2 = $"{body1[0]},{body1[2]},{body1[4]},{body1[6]}";
  2546. }
  2547. else
  2548. {
  2549. body2 = strpoints1[1];
  2550. }
  2551. lockResult1.ResultData = body2;
  2552. lockResult1.PhotoCode = ProductMainSN;
  2553. var globalParam = currentProduct.GlobalParamListCollection.FirstOrDefault(p => p.Name == strpoints1[0]);
  2554. if (globalParam != null)
  2555. {
  2556. lockResult1.UpLimit = globalParam.Param1;
  2557. lockResult1.DownLimit = globalParam.Param2;
  2558. lockResult1.MidLimit = globalParam.Param5;
  2559. string ResData = strpoints1[1];
  2560. if (ResData.Contains("NA"))
  2561. {
  2562. ResData = "-1000";
  2563. }
  2564. string[] body = ResData.Split(";");
  2565. bool resultflog = true;
  2566. foreach (var item in body)
  2567. {
  2568. if (Convert.ToDouble(item) >= Convert.ToDouble(globalParam.Param2) && Convert.ToDouble(item) <= Convert.ToDouble(globalParam.Param1))
  2569. {
  2570. }
  2571. else
  2572. {
  2573. resultflog = false;
  2574. }
  2575. }
  2576. if (resultflog)
  2577. {
  2578. lockResult1.PhotoPassed = "OK";
  2579. results.Add(true);
  2580. }
  2581. else
  2582. {
  2583. lockResult1.PhotoPassed = "NG";
  2584. results.Add(false);
  2585. }
  2586. }
  2587. lock (_stateLock)
  2588. {
  2589. lockResultsAll.Add(lockResult1);
  2590. }
  2591. App.Current.Dispatcher.Invoke(() =>
  2592. {
  2593. _eventAggregator.GetEvent<LockFinishNotification>().Publish(lockResult1);
  2594. });
  2595. }
  2596. //排序
  2597. //lock (_stateLock)
  2598. //{
  2599. // var bf1 = lockResultsAll.OrderBy(p => p.Number);
  2600. // lockResultsAll = new List<LockResult>(bf1);
  2601. //}
  2602. }
  2603. catch (Exception ex)
  2604. {
  2605. LogHelper.WriteLogError("执行 AOI 视觉流程时出错", ex);
  2606. SendTaskMessage($"执行 AOI 视觉流程异常: {ex.Message}", MessageLevel.Alarm);
  2607. }
  2608. return (true, results.ToArray(), $"成功");
  2609. }
  2610. catch (Exception ex)
  2611. {
  2612. LogHelper.WriteLogError("处理固定相机检测拍照时出错", ex);
  2613. return (false, null, $"处理固定相机检测拍照时出错");
  2614. }
  2615. });
  2616. }
  2617. /// <summary>
  2618. /// 异步执行流程拍照
  2619. /// </summary>
  2620. /// <param name="pointIndex"></param>
  2621. /// <param name="procedureId"></param>
  2622. /// <returns></returns>
  2623. private Task<(bool IsSucceed, bool[] Result, string Message)> ExecuteProcedureAsync(int pointIndex, Guid procedureId, ICogImage[] images,bool is3dmodel)
  2624. {
  2625. return Task.Run(async () =>
  2626. {
  2627. List<bool> results = new List<bool>();
  2628. // 获取当前产品
  2629. var currentProduct = _productService.GetCurrentProduct();
  2630. if (currentProduct == null)
  2631. {
  2632. return (false, null, "当前产品为空,未加载产品!");
  2633. }
  2634. var cameraProcedures = currentProduct.CameraProcedures;
  2635. if (cameraProcedures == null || cameraProcedures.Count == 0)
  2636. {
  2637. SendTaskMessage($"当前产品未配置 CameraProcedures,无法执行视觉流程", MessageLevel.Alarm);
  2638. return (false, null, $"当前产品未配置 CameraProcedures,无法执行视觉流程");
  2639. }
  2640. var ctsAll = new CancellationTokenSource();
  2641. try
  2642. {
  2643. ProcedureModel selectedProcedure = null;
  2644. try
  2645. {
  2646. foreach (var cp in cameraProcedures)
  2647. {
  2648. if (cp?.ProcedureModels == null) continue;
  2649. selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == procedureId);
  2650. if (selectedProcedure != null) break;
  2651. }
  2652. }
  2653. catch (Exception ex)
  2654. {
  2655. LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
  2656. }
  2657. if (selectedProcedure == null)
  2658. {
  2659. SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={pointIndex}", MessageLevel.Alarm);
  2660. return (false, null, $"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId}");
  2661. }
  2662. SendTaskMessage($"开始执行 AOI 流程 (Point#{pointIndex}) 流程Id={pointIndex}", MessageLevel.Debug);
  2663. try
  2664. {
  2665. var sysConfig = _configService.GetSystemConfiguration();
  2666. if (selectedProcedure.Id == currentProduct.MoveDownCameraLockPhotoProcedureId && sysConfig.TurnOffAllLightUse == true)
  2667. {
  2668. await _remoteCommandService.TurnOffLightAfterPhoto(selectedProcedure);
  2669. }
  2670. //1. 执行拍照,图像处理
  2671. var visionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint1(selectedProcedure, images, null, null, ctsAll.Token,is3dmodel);
  2672. if (visionResult.Count == 0)
  2673. {
  2674. SendTaskMessage("Count值为0", MessageLevel.Alarm);
  2675. return (false, null, $"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId}");
  2676. }
  2677. //2. 结果分析
  2678. lock (_stateLock)
  2679. {
  2680. for (int i = 1; i <= visionResult.Count; i++)
  2681. {
  2682. LockResult lockResult1 = new LockResult();
  2683. //if (pointIndex == currentProduct.PhotoCount && selectedProcedure.Id == currentProduct.FixedUpCamera1ProcedureId && i == 1)
  2684. //{
  2685. // lockResult1.Number = 1;
  2686. // lock (_stateLock)
  2687. // {
  2688. // lockResultsAll.Clear();
  2689. // }
  2690. //}
  2691. string[] strpoints1 = visionResult.Items[i].Split(',');
  2692. string[] body1 = strpoints1[1].Split(";");
  2693. if (body1.Length > 1)
  2694. {
  2695. for (int j = 1; j <= body1.Length; j++)
  2696. {
  2697. lockResult1.PhotoName = strpoints1[0] + "_" + j.ToString();
  2698. lockResult1.ResultData = body1[j - 1];
  2699. lockResult1.PhotoCode = ProductMainSN;
  2700. var globalParam = currentProduct.GlobalParamListCollection.FirstOrDefault(p => p.Name == strpoints1[0]);
  2701. if (globalParam != null)
  2702. {
  2703. lockResult1.UpLimit = globalParam.Param1;
  2704. lockResult1.DownLimit = globalParam.Param2;
  2705. lockResult1.MidLimit = globalParam.Param5;
  2706. string ResData = body1[j - 1];
  2707. if (ResData.Contains("NA"))
  2708. {
  2709. ResData = "-1000";
  2710. }
  2711. bool resultflog = true;
  2712. if (Convert.ToDouble(ResData) >= Convert.ToDouble(globalParam.Param2) && Convert.ToDouble(ResData) <= Convert.ToDouble(globalParam.Param1))
  2713. {
  2714. }
  2715. else
  2716. {
  2717. resultflog = false;
  2718. }
  2719. if (resultflog)
  2720. {
  2721. lockResult1.PhotoPassed = "OK";
  2722. results.Add(true);
  2723. }
  2724. else
  2725. {
  2726. lockResult1.PhotoPassed = "NG";
  2727. results.Add(false);
  2728. }
  2729. }
  2730. lockResultsAll.Add(lockResult1.Copy());
  2731. }
  2732. }
  2733. else
  2734. {
  2735. lockResult1.PhotoName = strpoints1[0];
  2736. lockResult1.ResultData = strpoints1[1];
  2737. lockResult1.PhotoCode = ProductMainSN;
  2738. var globalParam = currentProduct.GlobalParamListCollection.FirstOrDefault(p => p.Name == strpoints1[0]);
  2739. if (globalParam != null)
  2740. {
  2741. lockResult1.UpLimit = globalParam.Param1;
  2742. lockResult1.DownLimit = globalParam.Param2;
  2743. lockResult1.MidLimit = globalParam.Param5;
  2744. string ResData = strpoints1[1];
  2745. if (ResData.Contains("NA"))
  2746. {
  2747. ResData = "-1000";
  2748. }
  2749. bool resultflog = true;
  2750. if (Convert.ToDouble(ResData) >= Convert.ToDouble(globalParam.Param2) && Convert.ToDouble(ResData) <= Convert.ToDouble(globalParam.Param1))
  2751. {
  2752. }
  2753. else
  2754. {
  2755. resultflog = false;
  2756. }
  2757. if (resultflog)
  2758. {
  2759. lockResult1.PhotoPassed = "OK";
  2760. results.Add(true);
  2761. }
  2762. else
  2763. {
  2764. lockResult1.PhotoPassed = "NG";
  2765. results.Add(false);
  2766. }
  2767. }
  2768. lockResultsAll.Add(lockResult1);
  2769. }
  2770. App.Current.Dispatcher.Invoke(() =>
  2771. {
  2772. _eventAggregator.GetEvent<LockFinishNotification>().Publish(lockResult1);
  2773. });
  2774. }
  2775. }
  2776. ////排序
  2777. //lock (_stateLock)
  2778. //{
  2779. // var bf1 = lockResultsAll.OrderBy(p => int.Parse(p.PhotoName));
  2780. // lockResultsAll = new List<LockResult>(bf1);
  2781. //}
  2782. }
  2783. catch (Exception ex)
  2784. {
  2785. LogHelper.WriteLogError("执行 AOI 视觉流程时出错", ex);
  2786. SendTaskMessage($"执行 AOI 视觉流程异常: {ex.Message}", MessageLevel.Alarm);
  2787. }
  2788. return (true, results.ToArray(), $"成功");
  2789. }
  2790. catch (Exception ex)
  2791. {
  2792. LogHelper.WriteLogError("处理固定相机检测拍照时出错", ex);
  2793. return (false, null, $"处理固定相机检测拍照时出错");
  2794. }
  2795. });
  2796. }
  2797. /// <summary>
  2798. /// 是否是3D相机
  2799. /// </summary>
  2800. /// <param name="procedureId"></param>
  2801. /// <returns></returns>
  2802. private bool Is3D(Guid procedureId)
  2803. {
  2804. // 获取当前产品
  2805. var currentProduct = _productService.GetCurrentProduct();
  2806. if (currentProduct == null)
  2807. {
  2808. return false;
  2809. }
  2810. var cameraProcedures = currentProduct.CameraProcedures;
  2811. if (cameraProcedures == null || cameraProcedures.Count == 0)
  2812. {
  2813. return false;
  2814. }
  2815. ProcedureModel selectedProcedure = null;
  2816. try
  2817. {
  2818. foreach (var cp in cameraProcedures)
  2819. {
  2820. if (cp?.ProcedureModels == null) continue;
  2821. selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == procedureId);
  2822. if (selectedProcedure != null) break;
  2823. }
  2824. }
  2825. catch (Exception ex)
  2826. {
  2827. LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
  2828. }
  2829. if (selectedProcedure == null)
  2830. {
  2831. return false;
  2832. }
  2833. var camera = _cameraService.GetCamera(selectedProcedure.CameraId);
  2834. if (camera == null)
  2835. {
  2836. return false;
  2837. }
  2838. return camera.Is3D;
  2839. }
  2840. /// <summary>
  2841. /// 2D相机先采集图像
  2842. /// </summary>
  2843. /// <param name="procedureId"></param>
  2844. /// <returns></returns>
  2845. private async Task<(bool IsSucceed, ICogImage[] imges, string Message)> GrabImage(int pointIndex, Guid procedureId)
  2846. {
  2847. // 获取当前产品
  2848. var currentProduct = _productService.GetCurrentProduct();
  2849. if (currentProduct == null)
  2850. {
  2851. return (false, null, "当前产品为空,未加载产品!");
  2852. }
  2853. var cameraProcedures = currentProduct.CameraProcedures;
  2854. if (cameraProcedures == null || cameraProcedures.Count == 0)
  2855. {
  2856. SendTaskMessage($"当前产品未配置 CameraProcedures,无法执行视觉流程", MessageLevel.Alarm);
  2857. return (false, null, $"当前产品未配置 CameraProcedures,无法执行视觉流程");
  2858. }
  2859. try
  2860. {
  2861. ProcedureModel selectedProcedure = null;
  2862. try
  2863. {
  2864. foreach (var cp in cameraProcedures)
  2865. {
  2866. if (cp?.ProcedureModels == null) continue;
  2867. selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == procedureId);
  2868. if (selectedProcedure != null) break;
  2869. }
  2870. }
  2871. catch (Exception ex)
  2872. {
  2873. LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
  2874. }
  2875. if (selectedProcedure == null)
  2876. {
  2877. SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={pointIndex}", MessageLevel.Alarm);
  2878. return (false, null, $"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId}");
  2879. }
  2880. SendTaskMessage($"开始执行 AOI 流程 (Point#{pointIndex}) 流程Id={pointIndex}", MessageLevel.Debug);
  2881. try
  2882. {
  2883. var sysConfig = _configService.GetSystemConfiguration();
  2884. if (selectedProcedure.Id == currentProduct.FixedDownCameraProcedureId && sysConfig.TurnOnAllLightUse == true)
  2885. {
  2886. await _remoteCommandService.SetLightBeforePhoto(selectedProcedure);
  2887. }
  2888. //1. 执行拍照
  2889. return await _remoteCommandService.ExecuteGrabImageAsync(selectedProcedure);
  2890. }
  2891. catch (Exception ex)
  2892. {
  2893. LogHelper.WriteLogError("执行 AOI 视觉图像采集时出错", ex);
  2894. SendTaskMessage($"执行 AOI 视觉图像采集时出错: {ex.Message}", MessageLevel.Alarm);
  2895. }
  2896. return (false, null, $"图像采集失败");
  2897. }
  2898. catch (Exception ex)
  2899. {
  2900. LogHelper.WriteLogError("处理固定相机检测拍照时出错", ex);
  2901. return (false, null, $"处理固定相机检测拍照时出错");
  2902. }
  2903. }
  2904. /// <summary>
  2905. /// 为所有相机设置批处理点数(会调用具体相机实现的 SetBatchPoints)
  2906. /// </summary>
  2907. /// <param name="points"></param>
  2908. public void SetBatchPoints(int CameraNum, int points)
  2909. {
  2910. try
  2911. {
  2912. if (points == 0 || points < 0)
  2913. {
  2914. return;
  2915. }
  2916. var cameras = _cameraService.GetCameraByNumber(CameraNum);
  2917. if (cameras == null) return;
  2918. try
  2919. {
  2920. // 优先针对已知的 SSZNCamera 类型直接调用
  2921. if (cameras is TeamAAS_VP.Core.Cameras.SSZNCamera sszn)
  2922. {
  2923. sszn.CameraRevFinish = false;
  2924. sszn.SetBatchPoints(points);
  2925. }
  2926. }
  2927. catch (Exception ex)
  2928. {
  2929. LogHelper.WriteLogError($"SetBatchPoints to camera {cameras?.Name} failed", ex);
  2930. }
  2931. }
  2932. catch (Exception ex)
  2933. {
  2934. LogHelper.WriteLogError("SetBatchPoints failed", ex);
  2935. }
  2936. }
  2937. public void SetBatchPoints(int[] CameraSpoints)
  2938. {
  2939. try
  2940. {
  2941. for (int i = 0; i < CameraSpoints.Length; i++)
  2942. {
  2943. SetBatchPoints(i + 1, CameraSpoints[i]);
  2944. }
  2945. }
  2946. catch (Exception ex)
  2947. {
  2948. LogHelper.WriteLogError("SetBatchPoints failed", ex);
  2949. }
  2950. }
  2951. #endregion
  2952. #region 方法
  2953. private void SendTaskMessage(string msg, MessageLevel level)
  2954. {
  2955. App.Current.Dispatcher.Invoke(() =>
  2956. {
  2957. _eventAggregator.GetEvent<TaskMessageNotification>().Publish(new Models.MessageStruct() { Message = msg, level = level });
  2958. });
  2959. }
  2960. private async void DoYieldTime(object state)
  2961. {
  2962. try
  2963. {
  2964. //获取当前产品
  2965. CurrentProduct= _productService.GetCurrentProduct();
  2966. var currentproduct = _productService.GetCurrentProduct();
  2967. if (currentproduct == null) return;
  2968. TotalQuantity = await _systemDatabaseService.GetOverallProductionAsync(currentproduct.Name);
  2969. TotalQuantityToday = await _systemDatabaseService.GetTodayProductionAsync(currentproduct.Name);
  2970. CurrentUPH = await _systemDatabaseService.GetLastHourProductionAsync(currentproduct.Name);
  2971. NgNumber = await _systemDatabaseService.GetNGProductionAsync (currentproduct.Name);
  2972. Yield = ((double)TotalQuantityToday - (double)NgNumber) / (double)TotalQuantityToday * 100;
  2973. }
  2974. catch (Exception)
  2975. {
  2976. }
  2977. }
  2978. #region vm启动检测
  2979. /// <summary>
  2980. /// 杀死所有VM有关进程
  2981. /// </summary>
  2982. public void KillVMProcess()
  2983. {
  2984. KillProcess("VisionMasterServerApp");
  2985. KillProcess("VisionMaster");
  2986. KillProcess("VmModuleProxy.exe");
  2987. KillProcess("vServerApp.exe");
  2988. }
  2989. /// <summary>
  2990. /// 杀死指定进程名的进程
  2991. /// </summary>
  2992. /// <param name="strKillName"></param>
  2993. public void KillProcess(string strKillName)
  2994. {
  2995. foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcesses())
  2996. {
  2997. if (p.ProcessName.Contains(strKillName))
  2998. {
  2999. try
  3000. {
  3001. p.Kill();
  3002. p.WaitForExit();
  3003. }
  3004. catch (Exception ex)
  3005. {
  3006. LogHelper.WriteLogError($"杀死进程:{strKillName}时失败!", ex);
  3007. }
  3008. }
  3009. }
  3010. }
  3011. #endregion
  3012. /// <summary>
  3013. /// 记录工位的结果,其他工位要存储的数据项按照键值对集合的形式传入,键为数据项名称,值为数据项的值
  3014. /// </summary>
  3015. /// <param name="stationIndex"></param>
  3016. /// <param name="dfcs"></param>
  3017. /// <param name="productMainSN"></param>
  3018. /// <param name="ct"></param>
  3019. /// <param name="timestamp"></param>
  3020. /// <param name="savePath"></param>
  3021. /// <param name="isFirstEnter"></param>
  3022. /// <returns></returns>
  3023. private bool RecordStationResult(int stationIndex, IEnumerable<DataFormCtq> dfcs, string productMainSN, double ct, DateTime timestamp, string savePath, bool isFirstEnter = true)
  3024. {
  3025. try
  3026. {
  3027. //获取当前工位的配置
  3028. var stationConfig = _configService.GetDeviceInfo();
  3029. if (stationConfig == null) return false;
  3030. //如果保存路径为空,则不保存
  3031. if (string.IsNullOrEmpty(savePath)) return false;
  3032. string fullPath = savePath;
  3033. //如果保存路径是一个文件路径,则直接保存,否则按照工位和日期进行保存
  3034. if (File.Exists(savePath) || Path.HasExtension(savePath))
  3035. {
  3036. fullPath = savePath;
  3037. //如果路径不存在,则创建
  3038. // 创建目录
  3039. string directory = Path.GetDirectoryName(fullPath);
  3040. if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
  3041. {
  3042. Directory.CreateDirectory(directory);
  3043. }
  3044. }
  3045. else
  3046. {
  3047. //结果保存至CSV文件,文件名格式:savePath\yyyy-MM\工位编号_工位名称_yyyy-MM-dd.csv
  3048. string datePath = timestamp.ToString("yyyy-MM") + "\\";
  3049. string dirPath = Path.Combine(savePath, datePath);
  3050. if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
  3051. string fileName = $"{stationIndex}_{stationConfig.DeviceName}_{timestamp.ToString("yyyy-MM-dd")}.csv";
  3052. fullPath = Path.Combine(dirPath, fileName);
  3053. }
  3054. StringBuilder sb = new StringBuilder();
  3055. if (!File.Exists(fullPath))
  3056. {
  3057. sb.Append("PPID,PROCESS_NAME,PROCESS_START_TIME,CTQ_NAME,CTQ_VALUE,CTQ_LSL,CTQ_USL,PROCESS_END_TIME,SUPPLIER_NAME,COMMODITY_TYPE,REVISION,WO#,MFG_LOT#," +
  3058. "MFG_ASSY_LINE,PROCESS_OUTCOME,PROCESS_MACHINE_ID,CTQ_UNIT_OF_MEASURE,ERROR_MESSAGE,PD_ATTR_01,PD_ATTR_02,PD_ATTR_03,PD_ATTR_04,PD_ATTR_05");
  3059. sb.AppendLine();
  3060. }
  3061. if (dfcs == null || dfcs.Count() == 0)
  3062. {
  3063. return false;
  3064. }
  3065. foreach (var dfc in dfcs)
  3066. {
  3067. sb.Append($"{dfc.PPID},{dfc.PROCESS_NAME},{dfc.PROCESS_START_TIME},{dfc.CTQ_NAME},{dfc.CTQ_VALUE},{dfc.CTQ_LSL},{dfc.CTQ_USL},{dfc.PROCESS_END_TIME},{dfc.SUPPLIER_NAME},{dfc.COMMODITY_TYPE},{dfc.REVISION},{dfc.WO},{dfc.MFG_LOT},{dfc.MFG_ASSY_LINE},{dfc.PROCESS_OUTCOME},{dfc.PROCESS_MACHINE_ID},{dfc.CTQ_UNIT_OF_MEASURE},{dfc.ERROR_MESSAGE},{dfc.PD_ATTR_01},{dfc.PD_ATTR_02},{dfc.PD_ATTR_03},{dfc.PD_ATTR_04},{dfc.PD_ATTR_05}");
  3068. sb.AppendLine();
  3069. }
  3070. // 使用 StreamWriter 以追加模式打开文件
  3071. StreamWriter sw = new StreamWriter(fullPath, true, Encoding.UTF8);
  3072. sw.Write(sb.ToString());
  3073. sw.Close();
  3074. sw.Dispose();
  3075. return true;
  3076. }
  3077. catch (Exception ex)
  3078. {
  3079. if (!isFirstEnter)
  3080. {
  3081. return false;
  3082. }
  3083. LogHelper.WriteLogError("记录其他工位结果时出错!", ex);
  3084. //我希望在这里生成一个临时文件来保存这次的记录,因为如果本地文件被打开时可能会导致无法写入,如果不保存的话可能会丢失这次的记录,所以我想在这里生成一个临时文件来保存这次的记录
  3085. //生成临时文件的路径,格式为savePath\yyyy-MM\工位编号_yyyy-MM-dd_temp\工位编号_yyyy-MM-dd_HH-mm-ss-fff_temp.csv
  3086. string datePath = timestamp.ToString("yyyy-MM") + "\\";
  3087. string tempDirPath = Path.Combine(savePath, datePath, $"{stationIndex}_{timestamp.ToString("yyyy-MM-dd")}_temp");
  3088. string tempFileName = $"{stationIndex}_{timestamp.ToString("yyyy-MM-dd_HH-mm-ss-fff")}_temp.csv";
  3089. RecordStationResult(stationIndex, dfcs, productMainSN, ct, timestamp, tempFileName, false);
  3090. return false;
  3091. }
  3092. }
  3093. #endregion
  3094. // 用于等待“指定相机的下一张图到达”
  3095. private readonly object _imageSyncLock = new object();
  3096. private readonly Dictionary<Guid, TaskCompletionSource<ICogImage>> _nextImageTcsByCamera =
  3097. new Dictionary<Guid, TaskCompletionSource<ICogImage>>();
  3098. private Task<ICogImage> PrepareNextImageWait(Guid cameraId)
  3099. {
  3100. lock (_imageSyncLock)
  3101. {
  3102. var tcs = new TaskCompletionSource<ICogImage>(TaskCreationOptions.RunContinuationsAsynchronously);
  3103. _nextImageTcsByCamera[cameraId] = tcs;
  3104. return tcs.Task;
  3105. }
  3106. }
  3107. public async Task SignalImageArrived(Guid cameraId, ICogImage image)
  3108. {
  3109. await Task.Delay(500);
  3110. TaskCompletionSource<ICogImage> tcs = null;
  3111. lock (_imageSyncLock)
  3112. {
  3113. _nextImageTcsByCamera.TryGetValue(cameraId, out tcs);
  3114. }
  3115. tcs?.TrySetResult(image);
  3116. }
  3117. public async Task<ICogImage> WaitNextImageAsync(Guid cameraId, int timeoutMs, CancellationToken token)
  3118. {
  3119. var waitTask = PrepareNextImageWait(cameraId);
  3120. var completed = await Task.WhenAny(waitTask, Task.Delay(timeoutMs, token)).ConfigureAwait(false);
  3121. if (completed != waitTask) return null;
  3122. return await waitTask.ConfigureAwait(false);
  3123. }
  3124. //public async Task<bool> WaitImageFlagAsync(int cameraNo, int timeoutMs, CancellationToken token)
  3125. //{
  3126. // if (cameraNo < 0 || cameraNo >= ImageData.Length)
  3127. // {
  3128. // SendTaskMessage($"等待相机图像失败:CameraNo={cameraNo} 越界", MessageLevel.Alarm);
  3129. // return false;
  3130. // }
  3131. // var start = DateTime.UtcNow;
  3132. // while (ImageData[cameraNo] == 0)
  3133. // {
  3134. // token.ThrowIfCancellationRequested();
  3135. // if ((DateTime.UtcNow - start).TotalMilliseconds >= timeoutMs)
  3136. // {
  3137. // SendTaskMessage($"等待相机图像超时:CameraNo={cameraNo} Timeout={timeoutMs}ms", MessageLevel.Alarm);
  3138. // return false;
  3139. // }
  3140. // await Task.Delay(100, token).ConfigureAwait(false);
  3141. // }
  3142. // return true;
  3143. //}
  3144. // ====== 新增:最简等待:TCS + 超时(比 SemaphoreSlim + CurrentCount 轮询更轻、更可靠)======
  3145. private async Task<string> ScanT1Async(int timeoutMs)
  3146. {
  3147. var scannerId = GetDefaultScannerId();
  3148. if (scannerId == Guid.Empty) return null;
  3149. var scanner = _scannerService.GetScanner(scannerId);
  3150. if (scanner == null || !scanner.IsConnected) return null;
  3151. // 关键:先注册等待,再发送 T1,避免“回包先到”导致丢信号
  3152. var tcs = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
  3153. _scanTcs = tcs;
  3154. await scanner.SendAsync("T1").ConfigureAwait(false);
  3155. var completed = await Task.WhenAny(tcs.Task, Task.Delay(timeoutMs)).ConfigureAwait(false);
  3156. if (completed != tcs.Task)
  3157. {
  3158. // 超时:清掉本次等待,避免下次误用
  3159. if (ReferenceEquals(_scanTcs, tcs)) _scanTcs = null;
  3160. return null;
  3161. }
  3162. var reply = await tcs.Task.ConfigureAwait(false);
  3163. if (ReferenceEquals(_scanTcs, tcs)) _scanTcs = null;
  3164. return reply;
  3165. }
  3166. private Guid GetDefaultScannerId()
  3167. {
  3168. if (_defaultScannerId != Guid.Empty) return _defaultScannerId;
  3169. var scannerInfo = _configService.GetAllScanners()
  3170. .OrderBy(s => s.ScannerNo)
  3171. .FirstOrDefault();
  3172. _defaultScannerId = scannerInfo == null ? Guid.Empty : scannerInfo.Id;
  3173. return _defaultScannerId;
  3174. }
  3175. private async Task Scan_DataReceived(ISerialPortClient client, ReceivedDataEventArgs e)
  3176. {
  3177. try
  3178. {
  3179. // 串口名
  3180. string portName = client.MainSerialPort.PortName;
  3181. // 注意:DataReceived 可能一次收到多段/包含回车换行
  3182. string data = e.ByteBlock.Span.ToString(Encoding.ASCII);
  3183. await Console.Out.WriteLineAsync(data);
  3184. // 取第一段(到 \r 之前),并去掉首尾空白
  3185. string response = data.Split('\r')[0].Trim();
  3186. // 过滤:空数据不要当成一次有效扫码
  3187. if (string.IsNullOrWhiteSpace(response))
  3188. return;
  3189. SendTaskMessage($"扫码机:{portName} Receive:{response}", MessageLevel.Info);
  3190. // 写入结果
  3191. ScanValue = response;
  3192. // 通知等待方继续执行(PLC 逻辑里 Wait 的地方)
  3193. _scanDoneEvent.Set();
  3194. }
  3195. catch (Exception ex)
  3196. {
  3197. LogHelper.WriteLogError("扫码枪接收信息时出错!", ex);
  3198. SendTaskMessage(Lang.扫码枪接收信息时出错 + ex.Message, MessageLevel.Error);
  3199. }
  3200. }
  3201. /// <summary>
  3202. /// 2D相机先采集图像
  3203. /// </summary>
  3204. /// <param name="procedureId"></param>
  3205. /// <returns></returns>
  3206. private async Task<(bool IsSucceed, ICogImage[] imges, string Message, int pointIndex, Guid procedureId)> GrabImageEx(int pointIndex, Guid procedureId)
  3207. {
  3208. // 获取当前产品
  3209. var currentProduct = _productService.GetCurrentProduct();
  3210. if (currentProduct == null)
  3211. {
  3212. return (false, null, "当前产品为空,未加载产品!", pointIndex, procedureId);
  3213. }
  3214. var cameraProcedures = currentProduct.CameraProcedures;
  3215. if (cameraProcedures == null || cameraProcedures.Count == 0)
  3216. {
  3217. SendTaskMessage($"当前产品未配置 CameraProcedures,无法执行视觉流程", MessageLevel.Alarm);
  3218. return (false, null, $"当前产品未配置 CameraProcedures,无法执行视觉流程", pointIndex, procedureId);
  3219. }
  3220. try
  3221. {
  3222. ProcedureModel selectedProcedure = null;
  3223. try
  3224. {
  3225. foreach (var cp in cameraProcedures)
  3226. {
  3227. if (cp?.ProcedureModels == null) continue;
  3228. selectedProcedure = cp.ProcedureModels.FirstOrDefault(pm => pm.Id == procedureId);
  3229. if (selectedProcedure != null) break;
  3230. }
  3231. }
  3232. catch (Exception ex)
  3233. {
  3234. LogHelper.WriteLogError("查找 AOI 点位对应视觉流程时出错", ex);
  3235. }
  3236. if (selectedProcedure == null)
  3237. {
  3238. SendTaskMessage($"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={pointIndex}", MessageLevel.Alarm);
  3239. return (false, null, $"未找到 AOI 点位对应的视觉流程,Point#{pointIndex} ProcedureId={procedureId}", pointIndex, procedureId);
  3240. }
  3241. SendTaskMessage($"开始执行 AOI 流程 (Point#{pointIndex}) 流程Id={pointIndex}", MessageLevel.Debug);
  3242. try
  3243. {
  3244. var sysConfig = _configService.GetSystemConfiguration();
  3245. if (selectedProcedure.Id == currentProduct.FixedDownCameraProcedureId && sysConfig.TurnOnAllLightUse == true)
  3246. {
  3247. await _remoteCommandService.SetLightBeforePhoto(selectedProcedure);
  3248. }
  3249. //1. 执行拍照
  3250. var res = await _remoteCommandService.ExecuteGrabImageAsync(selectedProcedure);
  3251. return (res.IsSucceed, res.Image, res.Msg, pointIndex, procedureId);
  3252. }
  3253. catch (Exception ex)
  3254. {
  3255. LogHelper.WriteLogError("执行 AOI 视觉图像采集时出错", ex);
  3256. SendTaskMessage($"执行 AOI 视觉图像采集时出错: {ex.Message}", MessageLevel.Alarm);
  3257. }
  3258. return (false, null, $"图像采集失败", pointIndex, procedureId);
  3259. }
  3260. catch (Exception ex)
  3261. {
  3262. LogHelper.WriteLogError("处理固定相机检测拍照时出错", ex);
  3263. return (false, null, $"处理固定相机检测拍照时出错", pointIndex, procedureId);
  3264. }
  3265. }
  3266. #region 压缩图片文件夹
  3267. /// <summary>
  3268. /// 压缩文件
  3269. /// </summary>
  3270. /// <param name="sourcePath">原路径</param>
  3271. /// <param name="zipname">压缩后文件的名称</param>
  3272. /// <param name="station">mes中的station</param>
  3273. /// <param name="fixid">mes中的fixtureID</param>
  3274. public async void CompressionImage(string sourcePath, string zipname, string station, string fixid)
  3275. {
  3276. string zipPath = "";
  3277. try
  3278. {
  3279. SendTaskMessage($"开始压缩文件", MessageLevel.Info);
  3280. await Task.Run(() =>
  3281. {
  3282. zipPath = $"Z:\\{station}\\{fixid}\\{DateTime.Now.ToString("yyyyMMdd")}\\{zipname}.zip";//生成的zip文件路径
  3283. string path = $"Z:\\{station}\\{fixid}\\{DateTime.Now.ToString("yyyyMMdd")}";
  3284. if (!Directory.Exists(path))
  3285. {
  3286. Directory.CreateDirectory(path);
  3287. }
  3288. ZipFile.CreateFromDirectory(sourcePath, zipPath);
  3289. });
  3290. }
  3291. catch (Exception ex)
  3292. {
  3293. LogHelper.WriteLogError($"压缩文件时出错", ex);
  3294. }
  3295. }
  3296. #endregion
  3297. }
  3298. }