OCRReaderBase.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. using Aitex.Core.Common;
  2. using Aitex.Core.RT.DataCenter;
  3. using Aitex.Core.RT.Device;
  4. using Aitex.Core.RT.Event;
  5. using Aitex.Core.RT.Fsm;
  6. using Aitex.Core.RT.OperationCenter;
  7. using Aitex.Core.RT.SCCore;
  8. using Aitex.Sorter.Common;
  9. using MECF.Framework.Common.DBCore;
  10. using MECF.Framework.Common.Equipment;
  11. using MECF.Framework.Common.Event;
  12. using MECF.Framework.Common.SubstrateTrackings;
  13. using System;
  14. using System.Collections.Generic;
  15. using System.Linq;
  16. using System.Text;
  17. using System.Threading.Tasks;
  18. namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.OcrReaders
  19. {
  20. public abstract class OCRReaderBaseDevice : Entity, IDevice, IEntity
  21. {
  22. public enum PictureOptionEnum
  23. {
  24. None =0,
  25. All,
  26. Failed,
  27. Success,
  28. }
  29. public OCRReaderBaseDevice(string module,string name):base()
  30. {
  31. Module = module;
  32. Name = name;
  33. InitializeOCRReader();
  34. }
  35. public ModuleName InstalledModule { get; set; }
  36. public event Action<bool> ActionDone;
  37. public event Action<string, AlarmEventItem> OnDeviceAlarmStateChanged;
  38. public bool IsBusy = false;
  39. public OCRReaderStateEnum DeviceState => (OCRReaderStateEnum)fsm.State;
  40. public string CurrentJobName { get; set; }
  41. public bool IsReadLaserMark1 { get; set; }
  42. public string LaserMark1 { get; set; } = "";
  43. public string LaserMark1Score { get; set; } = "";
  44. public string LaserMark1ReadTime { get; set; } = string.Empty;
  45. public string LaserMark2 { get; set; } = "";
  46. public string LaserMark2Score { get; set; } = "";
  47. public string LaserMark2ReadTime { get; set; } = string.Empty;
  48. public string CurrentLaserMark { get; set; } = "";
  49. public float CurrentLaserMarkScore { get; set; }
  50. public string CurrentLaserMarkReadTime { get; set; } = "";
  51. public virtual string CurrentLaserMarkOnWafer
  52. {
  53. get
  54. {
  55. if(InstalledModule == ModuleName.System)
  56. return CurrentLaserMark;
  57. if (WaferManager.Instance.CheckHasWafer(InstalledModule, 0))
  58. return CurrentLaserMark;
  59. return "";
  60. }
  61. }
  62. public virtual string CurrentImageFileName
  63. {
  64. get
  65. {
  66. if (SC.ContainsItem($"OCRReader.{Name}.TempImageFilePath"))
  67. {
  68. return SC.GetStringValue($"OCRReader.{Name}.TempImageFilePath");
  69. }
  70. return "";
  71. }
  72. }
  73. public virtual int ScoreThresholdToSaveImage
  74. {
  75. get
  76. {
  77. if (SC.ContainsItem($"OCRReader.{Name}.PassScoreThreshhold"))
  78. return SC.GetValue<int>($"OCRReader.{Name}.PassScoreThreshhold");
  79. return -1;
  80. }
  81. }
  82. public virtual int KeepLaserMarkCharatersNumber
  83. {
  84. get
  85. {
  86. if (SC.ContainsItem($"OCRReader.{Name}.KeepLaserMarkCharatersNumber"))
  87. return SC.GetValue<int>($"OCRReader.{Name}.KeepLaserMarkCharatersNumber");
  88. return 100;
  89. }
  90. }
  91. public virtual int PicturesQuanlityLimit
  92. {
  93. get
  94. {
  95. if (SC.ContainsItem($"OCRReader.{Name}.LimitForPicture"))
  96. return SC.GetValue<int>($"OCRReader.{Name}.LimitForPicture");
  97. return 3000;
  98. }
  99. }
  100. public virtual PictureOptionEnum SavePictureOption
  101. {
  102. get
  103. {
  104. if (!SC.ContainsItem($"OCRReader.{Name}.SavePictureOption"))
  105. return PictureOptionEnum.All;
  106. return (PictureOptionEnum)SC.GetValue<int>($"OCRReader.{Name}.SavePictureOption");
  107. }
  108. }
  109. public DateTime StartReadTime { get; private set; }
  110. public int TimeLimitForRead
  111. { get
  112. {
  113. if (SC.ContainsItem($"OCRReader.{Name}.TimeLimitForWID"))
  114. return SC.GetValue<int>($"OCRReader.{Name}.TimeLimitForWID");
  115. return 300;
  116. }
  117. }
  118. public List<string> JobFileList { get; set; }
  119. public bool ReadOK { get; set; }
  120. public string AlarmWIDReadTimeout { get => Name.ToString() + "WIDReadTimeout"; }
  121. public string AlarmWIDLostCommunication { get => Name.ToString() + "WIDLostCommunication"; }
  122. public string AlarmWIDLoadJobFail { get => Name.ToString() + "WIDLoadJobFail"; }
  123. public string AlarmWIDSavePictureFail { get => Name.ToString() + "WIDSavePictureFail"; }
  124. public string LaserMark1ReadResult { get; set; }
  125. public string LaserMark2ReadResult { get; set; }
  126. public object[] CurrentParamter { get; private set; }
  127. public virtual bool IsReady()
  128. {
  129. if (DeviceState != OCRReaderStateEnum.Idle)
  130. return false;
  131. if (IsBusy)
  132. return false;
  133. return true;
  134. }
  135. private void InitializeOCRReader()
  136. {
  137. BuildTransitionTable();
  138. SubscribeDataVariable();
  139. SubscribeOperation();
  140. SubscribeDeviceOperation();
  141. Running = true;
  142. }
  143. private void SubscribeDeviceOperation()
  144. {
  145. DEVICE.Register(string.Format("{0}.{1}", Name, "SavePicture"),//DeviceOperationName.ReadWaferID),
  146. (out string reason, int time, object[] param) =>
  147. {
  148. var ret = SavePicture();
  149. if (ret)
  150. {
  151. reason = string.Format("{0}", Name, "Save picture.");
  152. return true;
  153. }
  154. else
  155. reason = string.Format("{0}", Name, "Can't Save picture.");
  156. return false;
  157. });
  158. DEVICE.Register(string.Format("{0}.{1}", Name, "ReadWaferID"),//DeviceOperationName.ReadWaferID),
  159. (out string reason, int time, object[] param) =>
  160. {
  161. var bLaser = bool.Parse((string)param[0]);
  162. var jobName = (string)param[1];
  163. var ret = ReadWaferID(jobName, bLaser?0:1);
  164. if (ret)
  165. {
  166. reason = string.Format("{0}", Name, "Read Laser Mark.");
  167. return true;
  168. }
  169. else
  170. reason = string.Format("{0}", Name, "Can't read Laser Mark.");
  171. return false;
  172. });
  173. DEVICE.Register(string.Format("{0}.{1}", Name, "ReadLM1"),//DeviceOperationName.ReadWaferID),
  174. (out string reason, int time, object[] param) =>
  175. {
  176. var jobName = (string)param[0];
  177. var ret = ReadWaferID(jobName, 0);
  178. if (ret)
  179. {
  180. reason = string.Format("{0}", Name, "Read Laser Mark.");
  181. return true;
  182. }
  183. else
  184. reason = string.Format("{0}", Name, "Can't read Laser Mark.");
  185. return false;
  186. });
  187. DEVICE.Register(string.Format("{0}.{1}", Name, "ReadLM2"),//DeviceOperationName.ReadWaferID),
  188. (out string reason, int time, object[] param) =>
  189. {
  190. reason = "";
  191. var jobName = (string)param[0];
  192. var ret = ReadWaferID(jobName,1);
  193. if (ret)
  194. {
  195. reason = string.Format("{0}", Name, "Read Laser Mark.");
  196. return true;
  197. }
  198. else
  199. reason = string.Format("{0}", Name, "Can't read Laser Mark.");
  200. return false;
  201. });
  202. DEVICE.Register($"{Name}.RefreshJobList", (out string reason, int time, object[] param) =>
  203. {
  204. reason = "";
  205. return CheckToPostMessage((int)OCRReaderMsg.ReadParameter, new object[] { "JobList" });
  206. });
  207. DEVICE.Register($"{Name}.Reset", (out string reason, int time, object[] param) =>
  208. {
  209. reason = "";
  210. return CheckToPostMessage((int)OCRReaderMsg.Reset, new object[] { "Reset" });
  211. });
  212. DEVICE.Register($"{Name}.ManualSetLaserMark", (out string reason, int time, object[] param) =>
  213. {
  214. reason = "";
  215. CurrentLaserMark = param[0].ToString();
  216. var wafer = WaferManager.Instance.GetWafer(InstalledModule, 0);
  217. if (!wafer.IsEmpty)
  218. {
  219. wafer.LaserMarker = CurrentLaserMark;
  220. Guid guid = Guid.NewGuid();
  221. OCRDataRecorder.OcrReadComplete(guid.ToString(), wafer.WaferID, wafer.OriginStation.ToString(),
  222. wafer.OriginCarrierID ?? "", (wafer.OriginSlot+1).ToString(), "0", "0", true, CurrentLaserMark,
  223. "0", "0");
  224. }
  225. return true;
  226. });
  227. }
  228. private void SubscribeOperation()
  229. {
  230. OP.Subscribe($"{Name}.SavePicture", (string cmd, object[] param) =>
  231. {
  232. var ret = SavePicture();
  233. if (!ret)
  234. {
  235. EV.PostWarningLog(Module, $"{Name} can not save picture.");
  236. return false;
  237. }
  238. EV.PostInfoLog(Module, $"{Name} start save picture");
  239. return true;
  240. });
  241. OP.Subscribe($"{Name}.ReadWaferID", (string cmd, object[] param) =>
  242. {
  243. var bLaser = bool.Parse(param[0].ToString());
  244. var jobName = (string)param[1];
  245. var ret = ReadWaferID(jobName, bLaser ? 0 : 1);
  246. if (!ret)
  247. {
  248. EV.PostWarningLog(Module, $"{Name} can not read laser mark.");
  249. return false;
  250. }
  251. EV.PostInfoLog(Module, $"{Name} start read laser mark");
  252. return true;
  253. });
  254. OP.Subscribe($"{Name}.ReadLM1", (string cmd, object[] param) =>
  255. {
  256. var jobName = (string)param[0];
  257. var ret = ReadWaferID(jobName, 0);
  258. if (ret)
  259. {
  260. return true;
  261. }
  262. return false;
  263. });
  264. OP.Subscribe($"{Name}.RefreshJobList", (string cmd, object[] param) =>
  265. {
  266. return CheckToPostMessage((int)OCRReaderMsg.ReadParameter, new object[] { "JobList" });
  267. });
  268. OP.Subscribe($"{Name}.Reset", (out string reason, int time, object[] param) =>
  269. {
  270. reason = "";
  271. return CheckToPostMessage((int)OCRReaderMsg.Reset, new object[] { "Reset" });
  272. });
  273. }
  274. private void SubscribeDataVariable()
  275. {
  276. DATA.Subscribe(Name, "WIDReaderState", () => DeviceState.ToString());
  277. DATA.Subscribe(Name, "WIDReaderBusy", () => (DeviceState != OCRReaderStateEnum.Idle && DeviceState != OCRReaderStateEnum.Init));
  278. DATA.Subscribe(Name, "WRIDReaderState", () => DeviceState.ToString());
  279. DATA.Subscribe(Name, "WRIDReaderBusy", () => (DeviceState != OCRReaderStateEnum.Idle && DeviceState != OCRReaderStateEnum.Init));
  280. DATA.Subscribe(Name, "LaserMaker1", () => LaserMark1);
  281. DATA.Subscribe(Name, "LaserMaker2", () => LaserMark2);
  282. DATA.Subscribe(Name, "LaserMark1Result", () => LaserMark1ReadResult);
  283. DATA.Subscribe(Name, "LaserMark2Result", () => LaserMark2ReadResult);
  284. DATA.Subscribe(Name, "JobFileList", () => JobFileList);
  285. DATA.Subscribe(Name, "CurrentLaserMark", () => CurrentLaserMarkOnWafer);
  286. DATA.Subscribe(Name, "CurrentImageFileName", () => CurrentImageFileName);
  287. DATA.Subscribe(Name, "CurrentWaferID", () => WaferManager.Instance.GetWafer(InstalledModule, 0).WaferID);
  288. //EV.Subscribe(new EventItem("Alarm", AlarmWIDLoadJobFail, $"{Name} WID Reader load job failed.", EventLevel.Alarm, EventType.EventUI_Notify));
  289. //EV.Subscribe(new EventItem("Alarm", AlarmWIDLostCommunication, $"{Name} WID Reader lost communication.", EventLevel.Alarm, EventType.EventUI_Notify));
  290. //EV.Subscribe(new EventItem("Alarm", AlarmWIDReadTimeout, $"{Name} WID Reader read laser mark timeout.", EventLevel.Alarm, EventType.EventUI_Notify));
  291. //EV.Subscribe(new EventItem("Alarm", AlarmWIDSavePictureFail, $"{Name} WID Reade save picture timeout.", EventLevel.Alarm, EventType.EventUI_Notify));
  292. }
  293. private void BuildTransitionTable()
  294. {
  295. fsm = new StateMachine<OCRReaderBaseDevice>(Module + Name + ".OCRReaderReaderStateMachine", (int)OCRReaderStateEnum.Init, 50);
  296. AnyStateTransition(OCRReaderMsg.Error, fError, OCRReaderStateEnum.Error);
  297. AnyStateTransition(OCRReaderMsg.Reset, fStartReset, OCRReaderStateEnum.Resetting);
  298. Transition(OCRReaderStateEnum.Resetting, OCRReaderMsg.ActionDone, fResetComplete, OCRReaderStateEnum.Idle);
  299. Transition(OCRReaderStateEnum.Resetting, OCRReaderMsg.ResetComplete, fResetComplete, OCRReaderStateEnum.Idle);
  300. Transition(OCRReaderStateEnum.Resetting, FSM_MSG.TIMER, fMonitorReset, OCRReaderStateEnum.Idle);
  301. Transition(OCRReaderStateEnum.Init, OCRReaderMsg.StartInit, fStartInit, OCRReaderStateEnum.Initializing);
  302. Transition(OCRReaderStateEnum.Initializing, OCRReaderMsg.InitComplete, fInitComplete, OCRReaderStateEnum.Initializing);
  303. Transition(OCRReaderStateEnum.Initializing, OCRReaderMsg.ActionDone, fInitComplete, OCRReaderStateEnum.Idle);
  304. Transition(OCRReaderStateEnum.Initializing, FSM_MSG.TIMER, fMonitorInit, OCRReaderStateEnum.Idle);
  305. Transition(OCRReaderStateEnum.Error, OCRReaderMsg.Clear, fStartClear, OCRReaderStateEnum.Idle);
  306. Transition(OCRReaderStateEnum.Idle, OCRReaderMsg.SetParameter, fStartSetParameter, OCRReaderStateEnum.SetParameter);
  307. Transition(OCRReaderStateEnum.SetParameter, OCRReaderMsg.SetComplete, fSetParameterComplete, OCRReaderStateEnum.SetParameter);
  308. Transition(OCRReaderStateEnum.SetParameter, OCRReaderMsg.ActionDone, fSetParameterComplete, OCRReaderStateEnum.SetParameter);
  309. Transition(OCRReaderStateEnum.Idle, OCRReaderMsg.ReadParameter, fStartReadParameter, OCRReaderStateEnum.ReadParameter);
  310. Transition(OCRReaderStateEnum.ReadParameter, OCRReaderMsg.ReadParaComplete, fReadParameterComplete, OCRReaderStateEnum.Idle);
  311. Transition(OCRReaderStateEnum.ReadParameter, OCRReaderMsg.ActionDone, fReadParameterComplete, OCRReaderStateEnum.Idle);
  312. Transition(OCRReaderStateEnum.ReadParameter, FSM_MSG.TIMER, fMonitorReadParameter, OCRReaderStateEnum.Idle);
  313. Transition(OCRReaderStateEnum.Idle, OCRReaderMsg.ReadWaferID, fStartReadWaferID, OCRReaderStateEnum.ReadWaferID);
  314. Transition(OCRReaderStateEnum.ReadWaferID, OCRReaderMsg.ReadCarrierIDComplete, fReadWaferIDComplete, OCRReaderStateEnum.Idle);
  315. Transition(OCRReaderStateEnum.ReadWaferID, OCRReaderMsg.ActionDone, fReadWaferIDComplete, OCRReaderStateEnum.Idle);
  316. Transition(OCRReaderStateEnum.ReadWaferID, FSM_MSG.TIMER, fMonitorReading, OCRReaderStateEnum.Idle);
  317. Transition(OCRReaderStateEnum.Idle, OCRReaderMsg.SavePicture, fStartSavePicture, OCRReaderStateEnum.SavingPicture);
  318. Transition(OCRReaderStateEnum.SavingPicture, OCRReaderMsg.SavePictureComplete, fSavePictureComplete, OCRReaderStateEnum.Idle);
  319. Transition(OCRReaderStateEnum.SavingPicture, OCRReaderMsg.ActionDone, fSavePictureComplete, OCRReaderStateEnum.Idle);
  320. Transition(OCRReaderStateEnum.SavingPicture, FSM_MSG.TIMER, fMonitorSavingPicture, OCRReaderStateEnum.Idle);
  321. }
  322. protected virtual void OnWaferIDRead(string wid, string score, string readtime)
  323. {
  324. EV.PostInfoLog(Name, $"{Name} read laser mark successfully,ID:{wid},score:{score},read time:{readtime}.");
  325. CheckToPostMessage((int)OCRReaderMsg.ReadCarrierIDComplete, null);
  326. }
  327. protected virtual bool fMonitorSavingPicture(object[] param)
  328. {
  329. return false;
  330. }
  331. protected virtual bool fMonitorReading(object[] param)
  332. {
  333. if (DateTime.Now - StartReadTime > TimeSpan.FromSeconds((double)TimeLimitForRead))
  334. {
  335. OnError(AlarmWIDReadTimeout);
  336. }
  337. return false;
  338. }
  339. protected virtual bool fMonitorReadParameter(object[] param)
  340. {
  341. return false;
  342. }
  343. protected virtual bool fSavePictureComplete(object[] param)
  344. {
  345. return true; ;
  346. }
  347. protected abstract bool fStartSavePicture(object[] param);
  348. protected virtual bool fError(object[] param)
  349. {
  350. return true;
  351. }
  352. protected abstract bool fStartReset(object[] param);
  353. protected virtual bool fResetComplete(object[] param)
  354. {
  355. return true;
  356. }
  357. protected virtual bool fMonitorReset(object[] param)
  358. {
  359. return true;
  360. }
  361. protected abstract bool fStartInit(object[] param);
  362. protected virtual bool fInitComplete(object[] param)
  363. {
  364. return true;
  365. }
  366. protected virtual bool fMonitorInit(object[] param)
  367. {
  368. return true;
  369. }
  370. protected virtual bool fStartClear(object[] param)
  371. {
  372. return true;
  373. }
  374. protected abstract bool fStartSetParameter(object[] param);
  375. protected virtual bool fSetParameterComplete(object[] param)
  376. {
  377. return true;
  378. }
  379. protected abstract bool fStartReadParameter(object[] param);
  380. protected virtual bool fReadParameterComplete(object[] param)
  381. {
  382. return true;
  383. }
  384. protected abstract bool fStartReadWaferID(object[] param);
  385. protected virtual bool fReadWaferIDComplete(object[] param)
  386. {
  387. return true;
  388. }
  389. public virtual bool ReadWaferID(string jobname,int lasermarkindex=0)
  390. {
  391. StartReadTime = DateTime.Now;
  392. return CheckToPostMessage((int)OCRReaderMsg.ReadWaferID, new object[] { jobname, lasermarkindex });
  393. }
  394. public abstract string[] GetJobFileList();
  395. public bool SavePicture(string path = "",string filename = "")
  396. {
  397. return CheckToPostMessage((int)OCRReaderMsg.SavePicture, new object[] { "SavePicture", path, filename });
  398. }
  399. protected override bool Init()
  400. {
  401. return base.Init();
  402. }
  403. public virtual void Monitor()
  404. {
  405. return;
  406. }
  407. public virtual void Reset()
  408. {
  409. }
  410. public virtual bool OcrReset()
  411. {
  412. return CheckToPostMessage((int)OCRReaderMsg.Reset, new object[] { "Reset" });
  413. }
  414. public virtual bool OnActionDone(object[] param)
  415. {
  416. IsBusy = false;
  417. CheckToPostMessage((int)OCRReaderMsg.ActionDone, new object[] { "ActionDone" });
  418. if (ActionDone != null)
  419. ActionDone(true);
  420. return true;
  421. }
  422. public void OnActionDone(bool result)
  423. {
  424. if (ActionDone != null)
  425. ActionDone(result);
  426. }
  427. public virtual bool OnError(string errorMsg)
  428. {
  429. EV.PostAlarmLog(Module, $"{Name} occured error:{errorMsg}");
  430. return CheckToPostMessage((int)OCRReaderMsg.Error, null);
  431. }
  432. public bool CheckToPostMessage(int msg, params object[] args)
  433. {
  434. if (!fsm.FindTransition(fsm.State, msg))
  435. {
  436. EV.PostWarningLog(Name, $"{Name} is in { (OCRReaderStateEnum)fsm.State} state,can not do {(OCRReaderMsg)msg}");
  437. return false;
  438. }
  439. if ((OCRReaderMsg)msg == OCRReaderMsg.Reset || (OCRReaderMsg)msg == OCRReaderMsg.ReadParameter ||
  440. (OCRReaderMsg)msg == OCRReaderMsg.ReadWaferID || (OCRReaderMsg)msg == OCRReaderMsg.SavePicture ||
  441. (OCRReaderMsg)msg == OCRReaderMsg.SetParameter || (OCRReaderMsg)msg == OCRReaderMsg.StartInit)
  442. {
  443. CurrentParamter = args;
  444. IsBusy = true;
  445. }
  446. else
  447. IsBusy = false;
  448. fsm.PostMsg(msg, args);
  449. return true;
  450. }
  451. public bool Check(int msg, out string reason, params object[] args)
  452. {
  453. if (!fsm.FindTransition(fsm.State, msg))
  454. {
  455. reason = String.Format("{0} is in {1} state,can not do {2}", Name, (OCRReaderStateEnum)fsm.State, (OCRReaderMsg)msg);
  456. return false;
  457. }
  458. reason = "";
  459. return true;
  460. }
  461. public virtual bool Error
  462. {
  463. get;
  464. }
  465. public string Module { get ; set ; }
  466. public string Name { get; set ; }
  467. public bool HasAlarm { get; set; }
  468. }
  469. public enum OCRReaderStateEnum
  470. {
  471. Undefined = 0,
  472. Init,
  473. Initializing,
  474. Idle,
  475. SetParameter,
  476. ReadParameter,
  477. ReadWaferID,
  478. SavingPicture,
  479. Error,
  480. Resetting,
  481. }
  482. public enum OCRReaderMsg
  483. {
  484. Reset,
  485. ResetComplete,
  486. Clear,
  487. StartInit,
  488. InitComplete,
  489. SetParameter,
  490. SetComplete,
  491. ReadParameter,
  492. ReadParaComplete,
  493. ReadWaferID,
  494. ReadCarrierIDComplete,
  495. SavePicture,
  496. SavePictureComplete,
  497. ActionDone,
  498. Error,
  499. }
  500. }