Hello All,
I am working on a laser simulator, which consists of the usual MVP components, a Laser model, a LaserShell presenter and the associated view. The laser model has a shotcounter which needs to be incremented with the repetition frequency of the laser, typically between 1 and 200 Hz. At the same time the view should be updated continuously with the current value of the shotcounter. Furthermore the process needs to terminate once the laser stop method is called. So in pseudo code: start "Start the laser" begin-loop self incrementcounter self trigger #counterUpdated wait (1 / self frequency) "wait fraction of second" (self stopFlag) ifTrue: [Terminate loop] end-loop "loop until stop method is called" I have three problems: 1. I don't know how to construct the loop with a timed wait condition in the background (so that the rest of the app continues). 2. I don't know how the best way to interrupt the loop. 3. I am concerned that the UI cannot handle the potential 200 event triggers per second. Any ideas? Thanks in advance, Frank |
Frank,
> 1. I don't know how to construct the loop with a timed wait condition in > the background (so that the rest of the app continues). > > 2. I don't know how the best way to interrupt the loop. The attached (Dolphin 4) package should show one way of doing this. There are other ways but, IMHO, this is about the simplest. Controls - Firing rate - the interval between shots in mS. Dynamic, can be altered on the fly. Start - start firing Stop - stop firing Shots fired - cumulative shots fired. Shots/sec - average number of shots per second (see below) The Shell subclass is not particularly interesting - it just starts, stops the model and reports the results. The model's #start method is where the looping is done. A block is forked that increments the counter and then waits for the appropriate interval. This loop is controlled by an instVar that is set to true while the model is running. Setting the instVar to false (in the #stop method) stops the loop running and the forked process terminates. As the block is forked the normal UI keeps running so the shell is updated and the buttons still work even though the model is in a loop. The #finalize bits are to ensure that if the process is always terminated, even if the shell is closed while the model is still running. > 3. I am concerned that the UI cannot handle the potential 200 event > triggers per second. The attached package has an additional button that runs the model for 10 seconds to show the number of shots that can be achieved in that time period. I expected to find a point where you could move from an accurate shot/sec to one that wobbles due to the inner forked loop not having enough time to update. It doesn't appear to work like that though, inaccuracy creeps in at rates that shouldn't pose a problem. The strange thing is that if you prevent the #firedCounter method triggering the #fired event, so the UI is not updated on every shot and the only work performed is therefore to update the instVar, the same inaccuracies occur. Changing the forking priority doesn't seem to make a difference either (in case anyone was wondering). I'm a bit stumped by this. I don't think I'm doing anything wrong but it's not something I've noticed before. It looks like overhead introduced by the forked loop but seems a bit excessive to me? I'll have another check later. Have a look anyway and see if the package helps Ian begin 666 Las.zip M4$L#!!0````(`*RD*2S1%;OMF0L``&\W```'````3&%S+G!A8]5:ZV_;1A+_ MG +]'VCG@^Q>Y>-C24H.>H!$B6F -F?$:>Y#X "T1-N\T*2.I.*ZU_O?;V9V MAR)73\MV+K=!+'%WYSV_V0?UIS&+)I^CZ]CX\_OO^.OI3\:9^II%M_&IT?DE M*CLGBPFSZ/</<5$F>79JF*^^_^[%950FDR"_O8VS2DX_OXG3U"AO\CLD7)#2 M3,6]YM&1<PX'TZE1W<2U3N6D2&95>=@:G*1169)BY8]&FN=E;-S&U4T^Y;[K M-+^,4GXJXC*?%Q-I"K)BYL3G+7:"`=%T>FJ\!+U_S:=Q^JK90Y9@SSWP*>/T MJF6/%,UL5DZ1^FR<PDJNG'0X3+*HN#=>2[O>:G9<TNCKA9!3X^@\KHPLOFMP M.@96A^_8%SJ/*$W?-55HL6A[PNC^S>B,XJMHGE;&ER2^Z[S2Q#0#6<1%_*]Y M4B;5<@#*N#IKC*/0-U-(H*2ZUX1W1GDZNTFR%:(4LP,2&U!J@'))EE206>4A M]5-,C7)^22%OQ!FX)5E91=DD_A 52729LOF=JZ2(IT$^SZJX,. AR:[?16!$ M4H;T`*;ED[@L.\"#V.H,<&"6Y^DHF: J,%IWT_PW:P1W0&4%GI;"U+=!X0*T M.S-([3,#IA15/!U4\"V?S?#;LRAZ^ OA[U<"@?+VX3B;&OE5#>)I'0XYCO\X M`,:DKAF=@]; ]3R!P!^]_NW-R+@J\MOS"KT.\_[M#]V>YXV";C 8CKHB' ZZ M/:LW[O9&/6'#H./W!__I'!.[@X4@<,]UCK:%>4%Y<O!;1O8E5TD\/3 .FK,E MJG$JL0$#HC3Y(T9/R; ;65Z]33 >+Y*K]\4<BN1'?*C'(6UN@:J*3UK=4%JS M)+U07!<I!I,.SXKD"Z98UQADY1VD'2+H2Y3.8W0G/A3Q)$Z^Q$6G!'\UR3L= M@_,"*&2<3JALOOC4G+<D]]2(LK]?_C.>5&T-$("/$V]4.1%%Q?4<0_QC+4DI MUD(8^*4>AC'$MP$1O[Y&%5_25-9=(7$_CRGB+?Y2LS2)C_+5!L&[>(K+3\-/ MI!TABW.SG,_ !XLN*I#2E^V8FR=+7"W3/#&,P]MSXR=\^/F/0ZPU7.Q@PE64 MEDV.EW$H48$FD"ZPV.?5:H%+7<9?#$L28:5JBJKA] F)+J3$IB(5#)\TD A= M!+V//.G"N+M)TKB)2I)/^DDXGDG:O##*-(YGIXT*?W%A7.7%9Z5</FOK%J(7 M-BA'7H)*TBXGK>)#^2SKR<$/W7FS",WFEVDRV4K<P',T03M ^,%,YN,#B$_W MH69H[$_Z<+&+C-[+813W_2@Q.?>DS&<;".M54*[T*U9!.;!^%?1Z@_%@V'.Z MIF\'73'LA=U>?Q1V[;$(+#,,A]; ;*Z"2M".JZ"<K:V"DR(&<MCES_(,M"WK MBJ,/2%C(#0E@@L!'^[BW\]O+N(!-7QE3$8 M'I\P<';GA)>%W>EH>J=>,[9- MAURHJ Z#G0N;SB<W\6U4)9-_4)9JAFFC3>ON;F(XOKRDRA_<1-EU/ 6U,]PO MYQG*^= <J7)9"4]J>B(\I>*[6!//C%O,*8C[$=E$3T94SJ#H?Y $+1P?J['W M<KTL>5@&?UD/]I7DVUS?&DH1;3'/+!.F?Y3U$]& NB]53]"?+%!U%G)?%M$! MI/1B\KR,BS>H<#&?P<X_@3RL[LGNUDH@C9YQ]'"[.6U&[IB]9IXL9-:VZ*O< M8B<,&?4^N8436Y*F21E/\FP:I/GD,[E&8R2!WU@"6F/Y3')6.^NMG!]B5"OF MK17SK\;10F1WL<4_/C9^H B<F+@V9HCQ]SFYQSIN+$4K*@!DBH[=+=5N$Q,- M)WMQ6L[6O=A0XNY%N4O)7T>YI>0W2'&&7EZG\DS-!]-/]=H"Y4L73?2Z`DT& M&Q4Q]#L%/KGQ'8!Z/N)G>2P'1H6A3J2U*JJNMBX$L""5R354QB.Y5:6U2TH\ MK_(B'M[C<1\$X)=!443W-./G^/=Z@;,MUW&%L&W3,6U3>/ G@!RG2F.:KN?U M/=?W71O^.E[HN[[M.9YK<AN;EBU@'O'09\E>."SV?>&YPO)MZ+?\OK!@U,&Y M--MV86V%SY[?9[:.!W_@:9G6#"W23=-[;/9([X'26^K#VB_QA_FV.6K8*35U MO !D@%9K-/)PIB]@K.^-/=_T%3?AA5[@FUX/^_NV(NDS;^AW@7/ ^MC("WRX ML,H:FBM;P+SX$_3M@\]);YL46MTPCBX*`<U )U_P@&V!PZ#U+66[7_/>K8'G M8,O#'NM[$!WD[T&<(++PZ3GX!'+''MK77_:E/VBSY$?VG*4^=^%>>TBYPM5X M;Y,%>4/-!4F@HQ"N1]*8K]4FKSVN1X;R`S)08 ;9G@\Y2WX'_>&[#RG*'(# M$@(8"\5/%]%N_L;1I3:T%3^6-P[\$>0<"'(PX]M:@=4A6ZYSJCVD-];7@V\A M<!PI)%O(TT5<6[Z+<=,JA8UQK9$6(B)@5AW//?)$:2*@AF"FP%^(WBK>=;0< M]8G>&*[2';1>> *1-JZKB>/WO9%G(_=E76N=6(!#VEBJ>@EG(+TL\]D9Z/D3 MZMYV)2O'63T^5GG!XYQ'/;N-Y\&@_5Q'-90?OD.UJ1D'J$A8W3RWH>4BY@XB MAK,($.C![*!FS_[E^8_4#I#HU,@<@7:H(U513RQKUR@%EOI"&>KZHB_&0HC0 MA;5 !,(2CG#%"/Z/W3K:Z]<<6]EG+^R43<D-M[0>YX;*EE"APN':H7G!5:8$ MK=[E' BL]B<W2WF]]J:RD:P!RY9JI++DH35OJ=9@:]0VNSVRW)ZRMF'M'4/= M083N6]F4WRPM2[?&1]'IV3W4YVW!.N2JM6I<QSK[59=G*4UT7 B[QJ5L:U"Z MCJ^_AF_#+*(;:'("]?Q4^.DI/S!^.(W7Q2=<6-K*@25\J#V CSNUT!?NL^/$ M;N%D0"IO:$^$D[&]I#*U;Q4/HQW7/O;?4^-A'=]M>&"ZY\:#IZTGW/]H/"A^ MN-+*/96Y:UN97RO:FGD/SC3UN7>F#=N?^KA^6F*$[[R/494%5B7<][D"*XN] M8E^E&O-_<.:HMBUSZCJC/OL*:<%(/F_U-Y]I]<JH/?-C[0?5@:=GJJUPCN/5 M^?'5%)^IFG+KF9O:(ZMI. X=M>N@.P3:=<!Y@\X=8]@/XZZ8]L8;F%+[VMEN MJ5WUNC/%B+-@D7ODR9VS7665KR*[G.?Z*4G("D.W*;;)ZRZ(ZWDCU[$QVTB# M!^-AQTK*YPS>F?OL`:7GOI54QX>E['CJ7._5B%S3GBC7(3B;,:7:_RJCU^T4 M](QF?ZW8*5#_NGSE]<%5.T3?L3EW875DKL^=I9Z6I8]=[_F<O'<U-WV\[\6? M`\$1VQ?-FQ:^F^&V>X;;O#>6XPOQJ]LC,]RV0X$9+CQ3T+VCTHNJ^0C^X5V( M$()NMO%.I^^;?%/"/+?60[GJP:J@C[CUR-J=D^I_,+(XXQ^)++[ATL<'"A&. MRD6.T\YKA8HJWO (O'6SX-P>;+[762=C*WJ7O,V<GANQCJ+G'30C;5_$ZD@- ME!U/C;H>L=[0G@AUMEWOP*FMS19%1T@*_:5^5_5_:RCBD^JN*&*_Z_)"M0*M M0\8ZNJW(T/S'?)X+%[[BRK@(^.W+(W$Q4!C_6O@P\=W IO:U\<$K#:S$WM@! MM^@WZ2Z-V'BF#Y$MSK'E[;\#4?G&<#-0-Z'K<./RVY%1W47Q>"ANUM%MQ<UN M7E7<GPM-([X'4_0]J[V?VQ=-7_'T$IJ;VB-1]/]R>EEW[[_B]$(4#\[6YB\1 MY.DEE#G*')\K0SF^?'//)Q=.L'TSU%[TM\=5'83=O$LC:K[H>TYSQU[/YR_X M=MHRZS>]\D8"]Z/R5/-U?T%BJ3RV5-:*/IU#\ VU36]KZ08-;YKP#(I:B@#H M'>J'.O20]]8LBS6!NN72>T]Z3UV/JKBM^"W+V"/?D@?#V@_J73?PP9U]H/\R M"/3M>_+MZLI?B-0>4,]>RS\>^,^!T#H"I O4ANDZQ_+'F/\%4$L!`A0+% `` M``@`K*0I+-$5N^V9"P``;S<```<``````````0`@`````````$QA<RYP86-0 52P4&``````$``0`U````O@L````` ` end |
In reply to this post by Frank Sonnemans-3
Frank,
I'm not sure whether this will help, but have you taken a look at the Bouncing Balls sample. If it's not already in your image you can find the package at: http://www.object-arts.com/Lib/Downloads/4.0/BouncingBalls.zip This was originally created to illustrate the use of a DoubleBufferedView to provide flicker-free animation. However, you'll also see that BouncingBallView starts a background process to update the animation a certain number of times a second (set by default to 30 in #frameRate). Take a look at BouncingBallView>>initialize and BouncingBallView>>onDestroyed to see how the background process is started and stopped. You shouldn't have any problem triggering 200 (or many more) event triggers per second providing the event handlers don't do too much work. As to whether you'd be able to update the display at 200Hz this will depend on how fast your machine is and how complex the update process. Personally, I would have thought that forcibly updating the screen 200 times a second is a bit pointless since no human could discern the changes that fast. You could probably just #invalidate the view (or a particular area of it) and let Windows do the actual painting at it's leisure when the normal WM_PAINT messages come in. Best Regards, Andy Bower Dolphin Support http://www.object-arts.com --- Are you trying too hard? http://www.object-arts.com/Relax.htm --- "Frank" <[hidden email]> wrote in message news:[hidden email]... > Hello All, > > I am working on a laser simulator, which consists of the usual MVP > components, a Laser model, a LaserShell presenter and the associated view. > > The laser model has a shotcounter which needs to be incremented with the > repetition frequency of the laser, typically between 1 and 200 Hz. At > the same time the view should be updated continuously with the current > value of the shotcounter. Furthermore the process needs to terminate > once the laser stop method is called. > > So in pseudo code: > > start > "Start the laser" > begin-loop > self incrementcounter > self trigger #counterUpdated > wait (1 / self frequency) "wait fraction of second" > (self stopFlag) ifTrue: [Terminate loop] > end-loop "loop until stop method is called" > > I have three problems: > > 1. I don't know how to construct the loop with a timed wait condition in > the background (so that the rest of the app continues). > > 2. I don't know how the best way to interrupt the loop. > > 3. I am concerned that the UI cannot handle the potential 200 event > triggers per second. > > Any ideas? > > Thanks in advance, > > > > Frank > |
In reply to this post by Frank Sonnemans-3
Frank
You wrote in message news:[hidden email]... > > I am working on a laser simulator, which consists of the usual MVP > components, a Laser model, a LaserShell presenter and the associated view. > > The laser model has a shotcounter which needs to be incremented with the > repetition frequency of the laser, typically between 1 and 200 Hz. At > the same time the view should be updated continuously with the current > value of the shotcounter. Furthermore the process needs to terminate > once the laser stop method is called. > ....[snip]... > I have three problems: > > 1. I don't know how to construct the loop with a timed wait condition in > the background (so that the rest of the app continues). > > 2. I don't know how the best way to interrupt the loop. > > 3. I am concerned that the UI cannot handle the potential 200 event > triggers per second. You have basically two choices. 1) Use a Windows timer - these can be set up so that Windows sends a message at regular intervals to a window through the message queue. 2) Use a background Smaltlalk Process (really a "thread") in conjunction with Delays Given the rate of update and some other considerations, I would go for (2). Now Smalltalk events are not really intended for cross-thread use - if you fork off an update process in the background which triggers events to do the update you will run into thread synchronisation issues. There is also the issue of keeping up with the synchronous updates. This may or may not be a problem, but generally speaking it is best to design the solution so that the UI makes best efforts to keep up with the updates in an asynchronous fashion that does not allow it to get behind. So based on your pseudo code you might want something like: clockProcess := [self startLaser. [ [self incrementCounter. view invalidate. (Delay forMilliseconds: 1000 / self frequency) wait] repeat] ifCurtailed: [self stopLaser]] forkAt: Processor userInterruptPriority In this case 'view' is a variable referencing the View object that is displaying the shot counter. The important point is that the #invalidate message instructs that view only that it needs to repaint, without actually waiting for it to repaint at that time. The view can then update in an asynchronous fashion when there is CPU time available to do so. Obviously the 'view' will need access the current value of the shot counter in order to repaint itself (and furthermore access to that shot counter and the #incrementcounter operation will need to be atomic - you can use a Mutex object to protect against more than one thread accessing it at once). If the GUI is not able to keep up with every change in the counter, this will not really matter since when it is able to repaint it will use the current value of the counter, whatever thay may be at the time. Note that the frequency will not be absolute if arranged like this, since it does not account for the time taken to execute the loop, and also the wait period of a delay is the minimum period. If, for example, the OS has switched control to another task, then the loop may not start running again until Dolphin regains control, even though the Delay has expired. Over time it will operate at a lower frequency than specified. To be more accurate one needs to get the current time and adjust the length of each delay to keep the loop working at the right frequency. You can work out how to do that yourself, but as a hint you'll probably need to use Time class>>millisecondClockValue (or even #microsecondClockValue!). As for how to stop the loop-counting process, just send it a #terminate message. The use of #ifCurtailed: guarantees that #stopLaser (or whatever other cleanup you want to do) is run. Regards Blair |
Free forum by Nabble | Edit this page |