Clamp.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using FluentResults;
  7. using GSG.NET.Concurrent;
  8. using GSG.NET.Logging;
  9. using GSG.NET.Utils;
  10. using OHV.Common.Events;
  11. using OHV.Common.Model;
  12. using OHV.Common.Shareds;
  13. using OHV.SqliteDAL;
  14. using Prism.Events;
  15. using VehicleControlSystem.ControlLayer.Axis;
  16. using VehicleControlSystem.ControlLayer.Lib.EziPlusE;
  17. using static OHV.Common.Events.AxisControlEventArgs;
  18. namespace VehicleControlSystem.ControlLayer
  19. {
  20. public class Clamp : ControlObjectBase
  21. {
  22. SqliteManager sql = null;
  23. List<EzAxis> axes = new List<EzAxis>();
  24. static Logger logger = Logger.GetLogger();
  25. IEventAggregator eventAggregator;
  26. TaskCancel taskCancel = new TaskCancel();
  27. eClampState _clampState;
  28. public eClampState ClampState
  29. {
  30. get { return this._clampState; }
  31. set { this.SetField( ref this._clampState, value ); }
  32. }
  33. public Clamp( SqliteManager sqliteManager, IEventAggregator ea )
  34. {
  35. this.sql = sqliteManager;
  36. this.eventAggregator = ea;
  37. }
  38. public void Init()
  39. {
  40. this.CreateAxis();
  41. this.eventAggregator.GetEvent<AxisControlPubSubEvent>().Unsubscribe( ReceivedMessageEvent );
  42. this.eventAggregator.GetEvent<AxisControlPubSubEvent>().Subscribe( ReceivedMessageEvent );
  43. }
  44. void ReceivedMessageEvent( AxisControlEventArgs args )
  45. {
  46. if ( args.Dir == AxisControlEventArgs.eEventDir.ToBack )
  47. {
  48. Task.Factory.StartNew( () =>
  49. {
  50. var arg = ObjectCopyUtils.DeepClone( args );
  51. switch ( arg.Kind )
  52. {
  53. case AxisControlEventArgs.eAxisControlKind.Stop:
  54. ReqStop();
  55. break;
  56. case AxisControlEventArgs.eAxisControlKind.EStop:
  57. break;
  58. case AxisControlEventArgs.eAxisControlKind.Move:
  59. ReqOrderByMove( arg );
  60. break;
  61. case AxisControlEventArgs.eAxisControlKind.Jog:
  62. ReqJog( arg );
  63. break;
  64. case AxisControlEventArgs.eAxisControlKind.ServoOn:
  65. ReqServoOn( arg );
  66. break;
  67. case AxisControlEventArgs.eAxisControlKind.ServoOff:
  68. ReqServoOff( arg );
  69. break;
  70. case AxisControlEventArgs.eAxisControlKind.ReqCurrentPosition:
  71. ReqStartAxisState();
  72. break;
  73. case AxisControlEventArgs.eAxisControlKind.ReqStopCurrentPosition:
  74. taskCancel.Cancel();
  75. taskCancel.WaitAll();
  76. break;
  77. case AxisControlEventArgs.eAxisControlKind.OriginReturn:
  78. ReqOriginReturn( arg );
  79. break;
  80. case AxisControlEventArgs.eAxisControlKind.FaultReset:
  81. ReqFaultReset( arg );
  82. break;
  83. case eAxisControlKind.NONE:
  84. break;
  85. case eAxisControlKind.AxisState:
  86. break;
  87. case eAxisControlKind.SyncMove:
  88. ReqSyncMove( arg );
  89. break;
  90. case eAxisControlKind.SyncState:
  91. ReqSyncState( arg );
  92. break;
  93. case eAxisControlKind.AllOriginReturn:
  94. ReqAllOriginReturn();
  95. break;
  96. default:
  97. break;
  98. }
  99. } );
  100. }
  101. }
  102. private void ReqStop()
  103. {
  104. logger.D( $"JogMove - Stop Command" );
  105. this.axes.ForEach( x => { x.Stop(); } );
  106. }
  107. void PublishEvent( AxisControlEventArgs args )
  108. {
  109. args.Dir = AxisControlEventArgs.eEventDir.ToFront;
  110. this.eventAggregator.GetEvent<AxisControlPubSubEvent>().Publish( args );
  111. }
  112. #region Request Method
  113. private void ReqSyncState( AxisControlEventArgs args )
  114. {
  115. var leftPositionDatas = sql.AxisPositionDataDAL.GetKFromName( ConstString.AXIS_CARRIER_LOCK_LEFT ).ToList();
  116. var leftLockData = leftPositionDatas.Where( x => x.Name.Equals( ConstString.TEACH_POSITION_LOCK ) ).Single();
  117. var leftUnLockData = leftPositionDatas.Where( x => x.Name.Equals( ConstString.TEACH_POSITION_UNLOCK ) ).Single();
  118. var left = this.axes.Where( x => x.Config.AxisName.Equals( ConstString.AXIS_CARRIER_LOCK_LEFT ) ).Single();
  119. var rightPositionDatas = sql.AxisPositionDataDAL.GetKFromName( ConstString.AXIS_CARRIER_LOCK_RIGHT ).ToList();
  120. var rightLockData = leftPositionDatas.Where( x => x.Name.Equals( ConstString.TEACH_POSITION_LOCK ) ).Single();
  121. var rightUnLockData = leftPositionDatas.Where( x => x.Name.Equals( ConstString.TEACH_POSITION_UNLOCK ) ).Single();
  122. var right = this.axes.Where( x => x.Config.AxisName.Equals( ConstString.AXIS_CARRIER_LOCK_RIGHT ) ).Single();
  123. if ( left.CurrentPosition == leftLockData.Value && right.CurrentPosition == rightLockData.Value )
  124. this.ClampState = eClampState.LOCK;
  125. else if ( left.CurrentPosition == leftUnLockData.Value && right.CurrentPosition == rightUnLockData.Value )
  126. this.ClampState = eClampState.UNLOCK;
  127. else
  128. this.ClampState = eClampState.NONE;
  129. //this.ClampState = eClampState.NONE;
  130. var msg = new AxisControlEventArgs
  131. {
  132. Kind = eAxisControlKind.SyncState
  133. };
  134. this.PublishEvent( msg );
  135. }
  136. private void ReqSyncMove( AxisControlEventArgs args )
  137. {
  138. var result = 0;
  139. var reply = new AxisControlEventArgs
  140. {
  141. Kind = eAxisControlKind.SyncMove
  142. };
  143. if ( args.PosDir == ePosDir.Lock )
  144. {
  145. result = this.Lock_Sync();
  146. if ( result == 0 )
  147. {
  148. reply.Result = Results.Ok();
  149. this.ClampState = eClampState.LOCK;
  150. }
  151. else
  152. {
  153. var alarm = this.sql.AlarmDAL.GetK( result );
  154. if ( alarm == null )
  155. alarm = new Alarm() { Name = "UnKnown Alarm", Text = "Not Define" };
  156. var error = new Error().WithMetadata( "Alarm", alarm );
  157. reply.Result = Results.Fail( error );
  158. this.ClampState = eClampState.NONE;
  159. }
  160. }
  161. else
  162. {
  163. result = this.Unlock_Sync();
  164. if ( result == 0 )
  165. {
  166. reply.Result = Results.Ok();
  167. this.ClampState = eClampState.UNLOCK;
  168. }
  169. else
  170. {
  171. var alarm = this.sql.AlarmDAL.GetK( result );
  172. if ( alarm == null )
  173. alarm = new Alarm() { Name = "UnKnown Alarm", Text = "Not Define" };
  174. var error = new Error().WithMetadata( "Alarm", alarm );
  175. reply.Result = Results.Fail( error );
  176. this.ClampState = eClampState.NONE;
  177. }
  178. }
  179. this.PublishEvent( reply );
  180. }
  181. private void ReqFaultReset( AxisControlEventArgs args )
  182. {
  183. var axis = this.axes.Where( x => x.Config.AxisName.Equals( args.AxisName ) ).FirstOrDefault();
  184. int resultNo = axis.ResetAmpFault();
  185. var msg = new AxisControlEventArgs
  186. {
  187. AxisName = args.AxisName,
  188. Dir = AxisControlEventArgs.eEventDir.ToFront,
  189. Kind = AxisControlEventArgs.eAxisControlKind.FaultReset,
  190. };
  191. msg.Result = Results.Ok( "Servo Fault Reset" );
  192. this.PublishEvent( msg );
  193. }
  194. private void ReqServoOn( AxisControlEventArgs args )
  195. {
  196. var axis = this.axes.Where( x => x.Config.AxisName.Equals( args.AxisName ) ).FirstOrDefault();
  197. axis.ServoOn();
  198. var msg = new AxisControlEventArgs
  199. {
  200. AxisName = args.AxisName,
  201. Dir = AxisControlEventArgs.eEventDir.ToFront,
  202. Kind = AxisControlEventArgs.eAxisControlKind.ServoOn,
  203. };
  204. msg.Result = Results.Ok( "Servo On" );
  205. this.PublishEvent( msg );
  206. }
  207. private void ReqServoOff( AxisControlEventArgs args )
  208. {
  209. var axis = this.axes.Where( x => x.Config.AxisName.Equals( args.AxisName ) ).FirstOrDefault();
  210. axis.ServoOff();
  211. var msg = new AxisControlEventArgs
  212. {
  213. AxisName = args.AxisName,
  214. Dir = AxisControlEventArgs.eEventDir.ToFront,
  215. Kind = AxisControlEventArgs.eAxisControlKind.ServoOff,
  216. };
  217. msg.Result = Results.Ok( "Servo Off" );
  218. this.PublishEvent( msg );
  219. }
  220. void ReqStartAxisState()
  221. {
  222. var task = Task.Factory.StartNew( () =>
  223. {
  224. double[] beforePosition = new double[this.axes.Count];
  225. beforePosition.Initialize();
  226. while ( !this.taskCancel.Canceled )
  227. {
  228. LockUtils.Wait( 500 );
  229. int index = 0;
  230. //this.axes.ForEach(a =>
  231. //{
  232. // if (beforePosition[index] != a.CurrentPosition)
  233. // {
  234. // beforePosition[index] = a.CurrentPosition;
  235. // var msg = new AxisControlEventArgs
  236. // {
  237. // AxisName = a.Config.AxisName,
  238. // Dir = AxisControlEventArgs.eEventDir.ToFront,
  239. // Kind = AxisControlEventArgs.eAxisControlKind.CurrentPosition,
  240. // CurrentPosition = a.CurrentPosition,
  241. // };
  242. // this.PublishEvent(msg);
  243. // }
  244. // index++;
  245. //});
  246. var msg = new AxisControlEventArgs();
  247. msg.Kind = AxisControlEventArgs.eAxisControlKind.AxisState;
  248. msg.Args = new Dictionary<string, object>();
  249. this.axes.ForEach( a =>
  250. {
  251. var state = new AxisState();
  252. state.IsServoOn = a.IsServoOn();
  253. state.IsOriginReturn = a.IsOriginReturn();
  254. state.IsAmpFault = a.IsAmpFault();
  255. state.CurrentPosition = a.CurrentPosition;
  256. if ( a.Config.AxisName.Equals( ConstString.AXIS_CARRIER_LOCK_LEFT ) )
  257. msg.Args.Add( "Left", state );
  258. else
  259. msg.Args.Add( "Right", state );
  260. } );
  261. this.PublishEvent( msg );
  262. }
  263. } );
  264. this.taskCancel.Add( task );
  265. }
  266. void ReqJog( AxisControlEventArgs arg )
  267. {
  268. var velocity = arg.JogVelocity;
  269. if ( arg.JogDir == AxisControlEventArgs.eJogMoveDir.Positive )
  270. this.JogMove( arg.AxisName, E_JogMoveDir.Positive, velocity );
  271. else
  272. this.JogMove( arg.AxisName, E_JogMoveDir.Negative, velocity );
  273. }
  274. void ReqOriginReturn( AxisControlEventArgs arg )
  275. {
  276. int result = 0;
  277. if ( arg.AxisName.Equals( ConstString.AXIS_CARRIER_LOCK_LEFT ) )
  278. result = this.LeftOriginReturn();
  279. else
  280. result = this.RightOriginReturn();
  281. var msg = new AxisControlEventArgs
  282. {
  283. AxisName = arg.AxisName,
  284. Kind = AxisControlEventArgs.eAxisControlKind.OriginReturn,
  285. };
  286. if ( result != EziMOTIONPlusELib.FMM_OK )
  287. msg.Result = Results.Fail( "Origin Fail" );
  288. else
  289. msg.Result = Results.Ok();
  290. this.PublishEvent( msg );
  291. }
  292. void ReqAllOriginReturn()
  293. {
  294. var msg = new AxisControlEventArgs
  295. {
  296. Kind = eAxisControlKind.AllOriginReturn
  297. };
  298. var ll = this.AllOriginReturn();
  299. LockUtils.Wait( 3000 );
  300. var result = this.IsAllAxisOriginReturn();
  301. if ( result == 5 )
  302. msg.Result = Results.Fail( "Left Fail" );
  303. else if ( result == 6 )
  304. msg.Result = Results.Fail( "Right Fail" );
  305. else if ( result <= 0 )
  306. msg.Result = Results.Ok();
  307. this.PublishEvent( msg );
  308. }
  309. void ReqOrderByMove( AxisControlEventArgs arg )
  310. {
  311. var msg = new AxisControlEventArgs();
  312. msg.Kind = AxisControlEventArgs.eAxisControlKind.Move;
  313. msg.PosDir = arg.PosDir;
  314. int result = 0;
  315. if ( arg.PosDir == AxisControlEventArgs.ePosDir.Lock )
  316. {
  317. result = this.MoveToLockPosition( arg.AxisName );
  318. if ( result != 0 )
  319. {
  320. var alarm = this.sql.AlarmDAL.GetK( result );
  321. if ( alarm == null )
  322. alarm = new Alarm() { Name = "Unknown Alarm", Text = "Not define" };
  323. var error = new Error().WithMetadata( "Alarm", alarm );
  324. msg.Result = Results.Fail( error );
  325. }
  326. else
  327. {
  328. msg.Result = Results.Ok();
  329. }
  330. }
  331. else
  332. {
  333. result = this.MoveToUnlockPosition( arg.AxisName );
  334. if ( result != 0 )
  335. {
  336. var alarm = this.sql.AlarmDAL.GetK( result );
  337. if ( alarm == null )
  338. alarm = new Alarm() { Name = "Unknown Alarm", Text = "Not define" };
  339. var error = new Error().WithMetadata( "Alarm", alarm );
  340. msg.Result = Results.Fail( error );
  341. }
  342. else
  343. {
  344. msg.Result = Results.Ok();
  345. }
  346. }
  347. this.PublishEvent( msg );
  348. }
  349. #endregion
  350. public void ClampEStop()
  351. {
  352. this.axes.ForEach( x => { x.EmergencyStop(); } );
  353. }
  354. void CreateAxis()
  355. {
  356. sql.AxisConfigDAL.All.ForEach( config =>
  357. {
  358. Axis.AxisConfig c = new Axis.AxisConfig
  359. {
  360. AxisName = config.Name,
  361. Scale = config.Scale,
  362. Address = config.Address,
  363. AxisNo = config.Id,
  364. };
  365. //if ( config.Name.Equals( ConstString.AXIS_CARRIER_LOCK_LEFT ) )
  366. // c.AxisNo = 40;
  367. //else
  368. // c.AxisNo = 41;
  369. axes.Add( new EzAxis( c ) );
  370. } );
  371. this.axes.ForEach( axis =>
  372. {
  373. var data = sql.AxisVelocityDataDAL.GetK( axis.Config.AxisName );
  374. Axis.AxisData axisData = new AxisData
  375. {
  376. AxisNo = data.id,
  377. AxisName = data.AxisName,
  378. AutoRunVelocity = data.AutoRunVelocity,
  379. AutoRunAccelerate = data.AutoRunAccelerate,
  380. AutoRunDecelerate = data.AutoRunDecelerate,
  381. ManualRunVelocity = data.ManualRunVelocity,
  382. JogFast = data.JogFast,
  383. JogSlow = data.JogSlow,
  384. Tolerance = data.Tolerance,
  385. };
  386. axis.Initialize( axisData );
  387. } );
  388. }
  389. public int LeftOriginReturn()
  390. {
  391. var servo = this.axes.Where( s => s.Config.AxisName.Equals( ConstString.AXIS_CARRIER_LOCK_LEFT ) ).Single();
  392. return servo.OriginReturn( true );
  393. }
  394. public int RightOriginReturn()
  395. {
  396. var servo = this.axes.Where( s => s.Config.AxisName.Equals( ConstString.AXIS_CARRIER_LOCK_RIGHT ) ).Single();
  397. return servo.OriginReturn( true );
  398. }
  399. public int AllOriginReturn()
  400. {
  401. int result = 0;
  402. this.axes.ForEach( axis =>
  403. {
  404. if ( axis.IsAmpFault() )
  405. axis.ResetAmpFault();
  406. Thread.Sleep( 500 );
  407. if ( axis.IsServoOff() )
  408. axis.ServoOn();
  409. } );
  410. Thread.Sleep( 500 );
  411. result = LeftOriginReturn();
  412. if ( result != EziMOTIONPlusELib.FMM_OK )
  413. return 7;
  414. Thread.Sleep( 1000 );
  415. result = RightOriginReturn();
  416. if ( result != EziMOTIONPlusELib.FMM_OK )
  417. return 8;
  418. return result;
  419. }
  420. public int IsAllAxisOriginReturn()
  421. {
  422. int result = 0;
  423. this.axes.ForEach( x =>
  424. {
  425. if ( !x.IsOriginReturn() )
  426. {
  427. if ( x.Config.AxisName.Equals( ConstString.AXIS_CARRIER_LOCK_LEFT ) )
  428. result = 5;
  429. else
  430. result = 6;
  431. return;
  432. }
  433. } );
  434. return result;
  435. }
  436. #region Data
  437. public void SavePositionData( string pos, double left, double right )
  438. {
  439. var dataList = sql.AxisPositionDataDAL.GetKFromPostion( pos );
  440. var sqlLeft = dataList.Where( x => x.AxisName.Equals( ConstString.AXIS_CARRIER_LOCK_LEFT ) ).Single();
  441. var sqlRight = dataList.Where( x => x.AxisName.Equals( ConstString.AXIS_CARRIER_LOCK_RIGHT ) ).Single();
  442. sqlLeft.Value = left;
  443. sql.AxisPositionDataDAL.Update( sqlLeft );
  444. sqlRight.Value = right;
  445. sql.AxisPositionDataDAL.Update( sqlRight );
  446. }
  447. #endregion
  448. public int JogMove( string axisName, E_JogMoveDir dir, int velocity )
  449. {
  450. logger.D( $"JogMove - Axis[{axisName}] / Dir[{dir}] / vel[{velocity}]" );
  451. var axis = this.axes.Where( x => x.Config.AxisName.Equals( axisName ) ).Single();
  452. return axis.JogMove( dir, velocity );
  453. }
  454. public int MoveToLockPosition( string axisName )
  455. {
  456. var servo = this.axes.Where( x => x.Config.AxisName.Equals( axisName ) ).Single();
  457. var axisPositionDatas = sql.AxisPositionDataDAL.GetKFromName( axisName ).ToList();
  458. var data = axisPositionDatas.Where( x => x.Name.Equals( ConstString.TEACH_POSITION_LOCK ) ).Single();
  459. int result = servo.Move( data.Value );
  460. return result;
  461. }
  462. public int MoveToUnlockPosition( string axisName )
  463. {
  464. var servo = this.axes.Where( x => x.Config.AxisName.Equals( axisName ) ).Single();
  465. var axisPositionDatas = sql.AxisPositionDataDAL.GetKFromName( axisName ).ToList();
  466. var data = axisPositionDatas.Where( x => x.Name.Equals( ConstString.TEACH_POSITION_UNLOCK ) ).Single();
  467. int result = servo.Move( data.Value );
  468. return result;
  469. }
  470. /// <summary>
  471. /// 두개를 동시에 Lock
  472. /// </summary>
  473. /// <returns></returns>
  474. public int Lock_Sync()
  475. {
  476. #if SIMULATION
  477. Thread.Sleep(2000);
  478. #else
  479. int result = 0;
  480. result = this.IsAllAxisOriginReturn();
  481. if ( result != 0 )
  482. return result;
  483. var leftPositionDatas = sql.AxisPositionDataDAL.GetKFromName( ConstString.AXIS_CARRIER_LOCK_LEFT ).ToList();
  484. var leftData = leftPositionDatas.Where( x => x.Name.Equals( ConstString.TEACH_POSITION_LOCK ) ).Single();
  485. var left = this.axes.Where( x => x.Config.AxisName.Equals( ConstString.AXIS_CARRIER_LOCK_LEFT ) ).Single();
  486. var rightPositionDatas = sql.AxisPositionDataDAL.GetKFromName( ConstString.AXIS_CARRIER_LOCK_RIGHT ).ToList();
  487. var rightData = leftPositionDatas.Where( x => x.Name.Equals( ConstString.TEACH_POSITION_LOCK ) ).Single();
  488. var right = this.axes.Where( x => x.Config.AxisName.Equals( ConstString.AXIS_CARRIER_LOCK_RIGHT ) ).Single();
  489. result = left.StartMove( leftData.Value, 0 );
  490. if ( result != EziMOTIONPlusELib.FMM_OK )
  491. return 1;
  492. result = right.StartMove( rightData.Value, 0 );
  493. if ( result != EziMOTIONPlusELib.FMM_OK )
  494. return 3;
  495. result = left.Wait4Done();
  496. if ( result != EziMOTIONPlusELib.FMM_OK )
  497. return 1;
  498. result = right.Wait4Done();
  499. if ( result != EziMOTIONPlusELib.FMM_OK )
  500. return 1;
  501. #endif
  502. this.ClampState = eClampState.LOCK;
  503. return EziMOTIONPlusELib.FMM_OK;
  504. }
  505. /// <summary>
  506. /// 두개의 Axis 를 동시에 Unlock
  507. /// </summary>
  508. /// <returns></returns>
  509. public int Unlock_Sync()
  510. {
  511. #if SIMULATION
  512. Thread.Sleep(2000);
  513. #else
  514. int result = 0;
  515. result = this.IsAllAxisOriginReturn();
  516. if ( result != 0 )
  517. return result;
  518. var leftPositionDatas = sql.AxisPositionDataDAL.GetKFromName( ConstString.AXIS_CARRIER_LOCK_LEFT ).ToList();
  519. var leftData = leftPositionDatas.Where( x => x.Name.Equals( ConstString.TEACH_POSITION_UNLOCK ) ).Single();
  520. var left = this.axes.Where( x => x.Config.AxisName.Equals( ConstString.AXIS_CARRIER_LOCK_LEFT ) ).Single();
  521. var rightPositionDatas = sql.AxisPositionDataDAL.GetKFromName( ConstString.AXIS_CARRIER_LOCK_RIGHT ).ToList();
  522. var rightData = leftPositionDatas.Where( x => x.Name.Equals( ConstString.TEACH_POSITION_UNLOCK ) ).Single();
  523. var right = this.axes.Where( x => x.Config.AxisName.Equals( ConstString.AXIS_CARRIER_LOCK_RIGHT ) ).Single();
  524. result = left.StartMove( leftData.Value, 0 );
  525. if ( result != EziMOTIONPlusELib.FMM_OK )
  526. return 2;
  527. result = right.StartMove( rightData.Value, 0 );
  528. if ( result != EziMOTIONPlusELib.FMM_OK )
  529. return 4;
  530. result = left.Wait4Done();
  531. if ( result != EziMOTIONPlusELib.FMM_OK )
  532. return 2;
  533. result = right.Wait4Done();
  534. if ( result != EziMOTIONPlusELib.FMM_OK )
  535. return 4;
  536. #endif
  537. this.ClampState = eClampState.UNLOCK;
  538. return EziMOTIONPlusELib.FMM_OK;
  539. }
  540. }
  541. }