1 #ReleaseTask.py
2
3
4 # **** Import Section ****
5 #
6 # This section includes all the import files needed for the script.
7 # The first set of imports are jython specific, the second set are
8 # java/nemo specific (but the order is not important)
9 from time import *
10 from random import *
11 from threading import Lock
12 from string import *
13 from thread import *
14 from math import *
15
16 from nemo.pdi import *
17 from nemo.server.experiment import Task
18 from nemo.messaging import Message
19 from nemo.experiment import GenericDataPoint
20 from java.lang import *
21 from java.util import *
22
23 # Device interface objects
24 buttonBox = 0
25 display = 0
26
27 # The data type name
28 dtName = "release_task"
29
30 # The data type
31 dt = 0
32 dataSet = None
33
34 # Global variables
35 numClients = 1
36 wordDataFile = "color_words.txt"
37 waitingForChoice = 0
38 waitingForMovieChoice = 0
39 waitingForReady = 0
40 run = 0
41 totalRuns = 4
42
43
44
45 #This method removes all quotes from a given string. This is useful when reading in text from config files.
46 def stripQuotes(data):
47     if (len(data) >= 2):
48         if (data[0] == '"' and data[len(data) - 1] == '"'):
49             return data[1:len(data) - 1]
50     return data
51
52 # This is a class. It contains variables and methods for a common purpose.
53 # This particualr class, called Word, has methods for parsing data read in
54 # from a configuratoin file.
55 class Word:
56
57     # The __init__ method is called when the class is instatiated (when
58     # an instance of this class is created.
59     
60     # This is a good place to initialize any variables necessary.
61     #
62     # The first argument for each method in a class should be called 'self'.
63     # 'self' is basically a self-reference, referring to this instance of
64     # a class.    
65     def __init__(self, descriptor, info, dataFile):
66         self.descriptors = self.parse(descriptor)
67         self.fields = self.parse(info)
68         self.dataFile = dataFile
69         if (len(self.fields) <> len(self.descriptors)):
70             raise Exception('Descriptor count does not match field count')
71     
72     def parse(self, info):
73         ar = split(info, '\t')
74         for i in range(len(ar)):
75             ar[i] = stripQuotes(ar[i])
76         return ar
77     
78     
79     #Returns a word from the array that was created when the config file was read in.
80     def getWord(self):
81         return self.fields[0]
82     
83     #Returns the RGB color values from the array that was created when the config file was read in.
84     def getRGB(self):
85         return self.fields[1] + "," + self.fields[2] + "," + self.fields[3]
86
87
88 # This particualr class, called WordSet, has methods for reading in data
89 # from a configuratoin file.
90 class WordSet:
91     
92     def __init__(self, dataFile):
93         self.dataFile = dataFile
94         self.loadData(dataFile)
95     
96     def loadData(self, dataFile):
97         file = open(dataFile)
98         line = None
99         count = 0
100         self.words = []
101         self.descriptor = file.readline()
102         if (len(self.descriptor) == 0):
103             print 'Data file is empty:', dataFile
104             file.close()
105             return
106         while (1):
107             line = file.readline()
108             line = line.strip()
109             if (len(line) == 0):
110                 break
111             count += 1
112             p = Word(self.descriptor, line, dataFile)
113             self.words.append(p)
114     
115     def getWordCount(self):
116         return len(self.words)
117     
118     def getWord(self, index):
119         return self.words[index]
120
121 # This particualr class, called Words, has methods for displaying words on the screen.
122 # The call to this method was made at the bottom of this script:
123 # wordDisplay = Words(task, display, dataSet, task.getResourcePath(wordDataFile).getAbsolutePath())
124 class Words:
125     submitLock = Lock()
126     submitWaitLock = Lock()
127     submitStr = ''
128     lastSubmit = 0
129     lastShow = time() * 1000 * 5
130
131
132     def __init__(self, task, display, dataSet, wordsDataFile):
133         self.task = task
134         self.display = display
135         self.dataSet = dataSet
136         self.wordsList = WordSet(wordsDataFile)
137         self.createWordGraphic()
138     
139
140     # Create several graphics for later use and store them in class
141     # variables.
142     def createWordGraphic(self):
143         self.wordGraphic = GraphicFactory.createGraphic(GraphicFactory.DRAW_STRING)
144         self.wordGraphic.name = "text-graphic"
145         self.wordGraphic.description = ''
146         self.wordGraphic.x = Graphic.CENTER
147         self.wordGraphic.y = Graphic.CENTER
148         self.wordGraphic.fontWidth = str(90)
149         self.wordGraphic.fontHeight = str(10)
150         self.wordGraphic.red = 255
151         self.wordGraphic.blue = 255
152         self.wordGraphic.green = 255
153         self.wordGraphic.fontName = "Arial"
154         self.wordGraphic.fontStyle = self.wordGraphic.NORMAL
155         self.wordGraphic.text = ''
156
157     def start(self):
158
159         self.doWordRun()
160
161     
162     def doWordRun(self):
163         self.display.showGraphics(0)
164
165         sleep(2)
166         
167         # Loop through all the words in the list
168         for i in range(self.wordsList.getWordCount()):
169             
170             # Set the specific word and colors for each word in the list
171             # See def setWord for more detail
172             self.setWord(self.wordsList.getWord(i).getWord(), self.wordsList.getWord(i).getRGB())
173             
174             # Add the word graphic to the display
175             self.display.addGraphic(0, self.wordGraphic)
176             sleep(1)
177             self.display.clearGraphics(0)
178             sleep(1)
179
180         return
181     
182     # Set individual parameters for each word in the list
183     # This method parses through the RGB colors and sets each
184     # color respectively.
185     def setWord(self, aWord, rgb):
186         
187         # Set the text
188         self.wordGraphic.text = aWord
189         
190         # Set the description
191         self.wordGraphic.description = aWord
192
193         # Parse the RGB colors and set them
194         comma1 = rgb.find(',')
195         r = rgb[0:comma1]
196         gb = rgb[comma1+1:len(rgb)]
197         comma2 = gb.find(',')
198         g = gb[0:comma2]
199         b = gb[comma2+1:len(gb)]
200         self.wordGraphic.red = int(r)
201         self.wordGraphic.green = int(g)
202         self.wordGraphic.blue = int(b)
203     
204
205     # Logs events specific to this class with a timestamp
206     def log(self, time, event):
207         gdp = GenericDataPoint()
208         gdp.dt = dt
209         gdp.setField("time", str(time))
210         gdp.setField("event", event)
211         
212         if (dataSet <> None):
213             dataSet.logDataPoint(gdp)
214
215
216 # This particualr class, called Words, has methods for displaying words on the screen.
217 # The call to this method was made at the bottom of this script:
218 # wordDisplay = Words(task, display, dataSet, task.getResourcePath(wordDataFile).getAbsolutePath())
219 class Images:
220     submitLock = Lock()
221     submitWaitLock = Lock()
222     submitStr = ''
223     lastSubmit = 0
224     lastShow = time() * 1000 * 5
225
226
227     def __init__(self, task, display, dataSet, imageList):
228         self.task = task
229         self.display = display
230         self.dataSet = dataSet
231         self.imageList = imageList
232         self.createImageGraphic()
233     
234
235     # Create several graphics for later use and store them in class
236     # variables.
237     def createImageGraphic(self):
238         self.imageGraphic = GraphicFactory.createGraphic(GraphicFactory.DRAW_IMAGE)
239         self.imageGraphic.name = "image"
240         self.imageGraphic.description = "name=?"
241         self.imageGraphic.x = Graphic.CENTER
242         self.imageGraphic.y = Graphic.CENTER
243         self.imageGraphic.red = 255
244         self.imageGraphic.blue = 255
245         self.imageGraphic.green = 255
246         self.imageGraphic.imageBytes = []
247         self.imageGraphic.isResource = 1
248         self.imageGraphic.imageName = ""
249
250     def start(self):
251
252         self.doImageRun()
253
254     
255     def doImageRun(self):
256         self.display.showGraphics(0)
257
258         sleep(2)
259         
260         # Loop through all the images in the list
261         for i in range(len(self.imageList)):
262
263             # Search through the string and finds the first "\"
264             subIndex = self.imageList[i].rfind("\\") + 1
265             length = len(self.imageList[i])
266             
267             
268             # Grab the image name from the list. You do not need to
269             # include the leading folder names or "\" since the images
270             # are stored on the client
271             if (subIndex == -1):
272                 # If there is no "\" in the image name, set the image name
273                 self.imageGraphic.imageName = self.imageList[i]
274             else:
275                 # If there is a "\" set only the image name after the "\"
276                 self.imageGraphic.imageName = self.imageList[i][subIndex:length]
277
278             # Set the description for the image
279             self.imageGraphic.description = "name=" + str(self.imageList[i])
280             # Display the image on the display
281             self.display.addGraphic(0, self.imageGraphic)
282
283             sleep(1)
284             self.display.clearGraphics(0)
285             sleep(1)
286
287         return
288
289
290 class Movies:
291     submitLock = Lock()
292     submitWaitLock = Lock()
293     movieWaitLock = Lock()
294     movieLoadLock = Lock()
295     postMovieSleepTime = 1
296
297     lastSubmit = 0
298     lastShow = time() * 1000 * 5
299     count = 0
300
301     def __init__(self, task, display, dataSet, configFile):
302         self.loadConfig(configFile)
303         self.task = task
304         self.dataSet = dataSet
305         self.display = display
306         self.createGraphics()
307         
308     #Load the config file and parse through the data
309     def loadConfig(self, filename):
310         # Open the file for reading
311         file = open(filename)
312         self.vidList = []
313         line = None
314         while (1):
315             # Read one line in the file
316             line = file.readline()
317             if (line == ''):
318                 # Leave the while loop if there is no
319                 # more data in the file
320                 break
321             # Remove whitespace
322             line = line.strip()
323             index = line.find('=')
324             comma = line.find(',')
325             if (index <= 0):
326                 # If there is no "=" sign in the data
327                 # skip the next part
328                 continue
329             else:
330                 # Parse the data and set each item
331                 tuple = [None, None]
332                 probe = line[0:index].strip()
333                 vid1 = line[index+1:comma].strip()
334                 vid2 = line[comma+1:len(line)].strip()
335
336             if (len(vid1) == 0):
337                 continue
338             if (len(vid2) == 0):
339                 continue
340         
341             tuple[0] = vid1
342             tuple[1] = vid2
343             # Build a list of all the video names from the datafile
344             self.vidList.append([tuple[0], tuple[1]])
345         
346     
347     # Create several graphics for later use and store them in class
348     # variables.
349     def createGraphics(self):
350         p = GraphicFactory.createGraphic(GraphicFactory.DRAW_STRING)
351         p.name = "video"
352         p.description = ""
353         p.x = Graphic.CENTER
354         p.y = Graphic.CENTER
355         p.fontWidth = "90"
356         p.fontHeight = "15"
357         p.red = 255
358         p.blue = 255
359         p.green = 255
360         p.fontName = "Arial"
361         p.fontStyle = p.BOLD
362         p.text = ""
363         self.cue = p
364     
365
366 # Loads a movie and creates a lock. The script pauses while locked
367     # and does not continue until the lock has been released. This
368     # specific lock is released by the method movieLoaded() which
369     # is called by fromMovie()
370     def loadMediaFile(self, fileName):
371         global movieThing
372
373         self.display.hideGraphics(0)
374
375         message = movieThing.createMessage(0, Movie.LOAD, fileName)
376
377         movieThing.send(message, 0)
378
379         # Get the movie-load lock
380         self.movieLoadLock.acquire()
381
382         # Try to get it again -- blocks until released by event from movie device
383         self.movieLoadLock.acquire()
384         self.movieLoadLock.release()
385
386     def start(self):
387
388         # Clear and hide all graphics
389         self.wipeScreen()
390
391         self.count = 0
392
393         sleep(1.5)
394
395         # Randomly shuffle the outter list
396         # This changes the order of the sports shown
397         shuffle(self.vidList)
398
399         for x in range(len(self.vidList)):
400             # Randomly shuffle the inner list
401             # This changes the order of whehter a live or
402             # test video is shown first
403             shuffle(self.vidList[x])
404
405         for i in range(len(self.vidList)):
406         
407             # If the script is waiting for a submitLock
408             # release it before continuing
409             if (self.submitLock.locked()):
410                 self.submitLock.release()
411
412             # Set the parameters for the cue text.
413             # This text will prompt the user for
414             # input later in the script
415             self.cue.text = "1"
416             self.cue.description = self.cue.text
417             self.display.addGraphic(0, self.cue)
418
419             sleep(1.5)
420
421             self.wipeScreen()
422
423             # Play the video
424             self.playMediaFile(self.vidList[i][0])
425
426             sleep(1.5)
427
428             self.display.showGraphics(0)
429
430             self.cue.text = "2"
431             self.cue.description = self.cue.text
432             self.display.addGraphic(0, self.cue)
433
434             sleep(1.5)
435
436             self.wipeScreen()
437
438             # Play the video
439             self.playMediaFile(self.vidList[i][1])
440
441             sleep(1.5)
442
443             self.showChoiceScreen()
444
445             # Get the lock
446             self.submitWaitLock.acquire()
447                 
448             # Try to get the lock again -- won't work until it has been released from the prior acquire
449             self.submitWaitLock.acquire()
450             self.submitWaitLock.release()
451     
452             self.wipeScreen()
453         
454             self.count = self.count + 1
455
456             sleep(1.5)
457
458             self.blankOut()
459
460
461     def playMediaFile(self, fileName):
462
463         # Loads the current movie
464         self.loadMediaFile(fileName)
465
466         # Sends a message to the server to start the movie that
467         # was just loaded
468         message = movieThing.createMessage(0, Movie.START, "")
469         movieThing.send(message, 0)
470
471         # Get the movie-over lock
472         self.movieWaitLock.acquire()
473
474         # Try to get it again -- blocks until released by eventglobal graphicalDisplay from movie device
475         self.movieWaitLock.acquire()
476         self.movieWaitLock.release()
477
478         # Hide and close the movie
479         message = movieThing.createMessage(0, Movie.HIDE, "")
480         movieThing.send(message, 0)
481
482         message = movieThing.createMessage(0, Movie.CLOSE, "")
483         movieThing.send(message, 0)
484
485
486     # Displays the text "1 or 2" on the screen
487     # This is a prompt for the user to select
488     # which movie the user liked more, either
489     # the first or the second movie.
490     def showChoiceScreen(self):
491         global display
492         global waitingForMovieChoice
493
494         display.clearGraphics(0)
495
496         g = GraphicFactory.createGraphic(GraphicFactory.DRAW_STRING)
497         g.name = "choice-screen"
498         g.description = "choice-screen"
499         g.x = Graphic.CENTER
500         g.y = Graphic.CENTER
501         g.fontWidth = "90"
502         g.fontHeight = "15"
503         g.red = 255
504         g.blue = 255
505         g.green = 255
506         g.fontName = "Arial"
507         g.fontStyle = g.BOLD
508         g.text = "1 or 2"
509
510         display.addGraphic(0, g)
511         display.showGraphics(0)
512
513         waitingForMovieChoice = 1
514     
515
516     # Allows input from the user and logs the entry
517     def submit(self, aTime, key):
518         if (not self.submitWaitLock.locked()):
519             print "submit wait lock not locked"
520             return
521
522         if (self.submitLock.acquire(0) == 0):
523             print "submit lock already acquired"
524             return
525
526         print 'submit lock acquired'
527         self.lastSubmit = aTime        
528         self.submitWaitLock.release()
529         waitingForMovieChoice = 0
530         self.log(aTime, "keypress: submit " + str(key))
531
532         
533     def movieOver(self):
534         # When the movie is over, release
535         # the lock that was waiting for the
536         # movie to complete
537         self.movieWaitLock.release()
538
539     def movieLoaded(self):
540         # When the movie loads completely
541         # release the lock that was waiting
542         # for it to load
543         self.movieLoadLock.release()
544
545     def blankOut(self):
546         # Clear all graphics on the display
547         self.display.clearGraphics(0)
548
549     def wipeScreen(self):
550         # Clear and hide all graphics on the display
551         self.display.clearGraphics(0)
552         self.display.showGraphics(0)
553
554     # Log events specific to this Class
555     def log(self, time, event):
556         gdp = GenericDataPoint()
557         gdp.dt = dt
558         gdp.setField("time", str(time))
559         gdp.setField("event", event)
560
561         if (dataSet <> None):
562             dataSet.logDataPoint(gdp)
563
564
565 # This method is called from NEMO and is passed an
566 # event when the scanner performs an operation.
567 # The events are then logged in the output
568 def fromScanner(event):
569     global dataSet
570     global dt
571     
572     client = event.getClient()
573     aTime = event.getTime()
574     aType = event.getType()
575     
576     type = ""
577     if (aType == Scanner.START_SCAN):
578         type = "STARTED SCANNER"
579     elif (aType == Scanner.STOP_SCAN):
580         type = "STOPPED SCANNER"
581 elif (aType == Scanner.GET_IMAGES):
582         type = "IMAGES"
583     else:
584         type = "UNKNOWN TYPE"
585     
586     gdp = GenericDataPoint()
587     gdp.dt = dt
588     gdp.setField("time", String.valueOf(aTime))
589
590     gdp.setField("event", str(type))
591     
592     if (dataSet <> None):
593         dataSet.logDataPoint(gdp)
594
595
596 # This method is called from NEMO and is passed an
597 # event when a button is pressed on a button box.
598 # This method allows control over where the
599 # script continues after is has received
600 # input from the user.
601 # The events are then logged in the output
602 def fromButtonBox(event):
603     global display
604     global waitingForMovieChoice
605     global waitingForReady
606     global waitingForChoice
607     global listType
608     global run
609
610     key = event.getData()
611
612     if (len(key) == 0):
613         return
614     
615     if (not key[0] in (letters+digits)):
616         return
617
618     client = event.getClient()
619     pressTime = event.getTime()
620
621     if (waitingForReady):
622         if (key == "r" or key == "R"):
623             waitingForReady = 0
624         else:
625             print "Press R to continue"
626         return
627
628     if (waitingForMovieChoice):
629      if (key in ["1", "2"]):
630             # Call the submit method in the Movies Class
631          movieDisplay.submit(pressTime, key)
632          return
633     
634     if (waitingForChoice):
635         if (key in ["1","2","3","q","Q"]):
636             waitingForChoice = 0
637             # Call the startRun() method
638             startRun(key)
639         return
640
641
642 # This method is called from NEMO and is passed an
643 # event when a graphic is displayed on the
644 # screen.
645 # The events are then logged in the output
646 def fromDisplay(event):
647     global dataSet
648     global dt
649     global run
650     global motor
651     
652     s = ""
653     gs = event.getGraphics()
654     for i in gs:
655         s = s + i + " "
656     
657     client = event.getClient()
658     aTime = event.getTime()
659     typeText = ""
660     if (event.getType() == GraphicalDisplay.HIDE):
661         typeText = "HIDE"
662     elif (event.getType() == GraphicalDisplay.SHOW):
663         typeText = "SHOW"
664     elif (event.getType() == GraphicalDisplay.DRAW):
665         typeText = "ADD GRAPHIC"
666     elif (event.getType() == GraphicalDisplay.CLEAR_GRAPHICS):
667         typeText = "CLEAR ALL"
668     elif (event.getType() == GraphicalDisplay.ADD_GRAPHICS):
669         typeText = "ADD GRAPHICS"
670     elif (event.getType() == GraphicalDisplay.CREATE_GROUP):
671         typeText = "ADD GRAPHIC GROUP"
672     
673     gdp = GenericDataPoint()
674     gdp.dt = dt
675     gdp.setField("time", String.valueOf(aTime))
676     gdp.setField("event", str(typeText) + ":{" + s + "}")
677     
678     if (dataSet <> None):
679         dataSet.logDataPoint(gdp)
680
681
682 # This method is called from NEMO and is passed an
683 # event when a movie is displayed on the
684 # screen.
685 # The events are then logged in the output
686 def fromMovie(event):
687 movieDisplay.log(event.getTime(), event.getData())
688
689 if (event.getType() == Movie.STARTED):
690 print event.getTime(), "movie started"
691 elif (event.getType() == Movie.STOPPED):
692 print event.getTime(), "movie stopped"
693 movieDisplay.movieOver()
694 elif (event.getType() == Movie.LOADED):
695 print event.getTime(), "movie loaded"
696 movieDisplay.movieLoaded()
697 elif (event.getType() == Movie.END_OF_MEDIA):
698 print event.getTime(), "movie over"
699 movieDisplay.movieOver()
700 else:
701 print event.getTime(), "movie event [", event.getData(), "]"
702
703
704 # Prompts the user to select a task to run
705 # After each task is run, the script returns to this
706 # menu.
707 def showChoiceScreen():
708     global display
709     global waitingForChoice
710
711     display.clearGraphics(0)
712     display.hideGraphics(0)
713
714     # Calculate center points for each word
715     centerX1 = 0.0/3.0 * 100 + 1.0/60.0 * 100
716     centerX2 = 1.0/3.0 * 100 + 1.0/60.0 * 100
717     centerX3 = 2.0/3.0 * 100 + 1.0/60.0 * 100
718     
719     # Calculate width of each word
720     baseWidth = 1.0/3.0 * 100 - 2.0/60.0 * 100
721     
722     display.addGraphic(0, makeTextXY("Words", "(1) Words", baseWidth, 5, centerX1, 25, 255, 255, 255))
723     display.addGraphic(0, makeTextXY("Images", "(2) Images", baseWidth, 5, centerX2, 25, 255, 255, 255))
724     display.addGraphic(0, makeTextXY("Movies", "(3) Movies", baseWidth, 5, centerX3, 25, 255, 255, 255))
725     display.addGraphic(0, makeTextXY("msg", "Please choose a task", 40, 15, Graphic.CENTER, 75, 255, 255, 255))
726     display.addGraphic(0, makeTextXY("msg2", "Hit 'q' to quit", 40, 5, Graphic.CENTER, 85, 255, 255, 255))
727
728     display.showGraphics(0)
729     
730     waitingForChoice = 1
731
732
733 def startRun(key):
734     global display
735     global task
736     global run
737     global wordDisplay
738     global imageDisplay
739     global dataSet
740     global dt
741     global key
742     
743     display.clearGraphics(0)
744
745     # Starts the task and creates the dataSet
746     task.startRun(str(run))
747     dataSet = task.startDataSet(dt.getName(), 0)
748
749
750     if (key == "1"):
751         # Autostart the scanner
752         scanner.startScanning(0)
753         retVal = None
754         # Start the Words Task
755         retVal = wordDisplay.start()
756     elif (key == "2"):
757         # Autostart the scanner
758         scanner.startScanning(0)
759         retVal = None
760         # Start the Images Task
761         retVal = imageDisplay.start()
762     elif (key == "3"):
763         # Autostart the scanner
764         scanner.startScanning(0)
765         retVal = None
766         # Start the Movie Task
767         retVal = movieDisplay.start()
768         
769     
770     # End the current task and dataSet
771     task.endDataSet(dataSet)
772     task.endRun()
773     
774     dataSet = None
775
776     display.clearGraphics(0)
777
778     run = run + 1
779
780     sleep(2)
781     
782     if (key not in ["q","Q"]):
783         showChoiceScreen()
784     else:
785         retVal = None
786         end(retVal)
787
788
789 # Displays "Experiment Complete" to the
790 # display and ends the experiment
791 def end(text):
792     global task
793     global display
794
795     msg = "Experiment Complete"
796     if (text <> None and len(text) > 0):
797         msg = msg + " : " + text
798     display.clearGraphics(0)
799     sleep(0.5)
800     display.addGraphic(0, makeText(msg, 12.5))
801     display.showGraphics(0)
802     
803     sleep(2.0)
804     
805     task.endExperiment()
806
807
808 # This is a simple method that takes text and its height
809 # and displays it on the screen
810 def makeText(text, height):
811     p = GraphicFactory.createGraphic(GraphicFactory.DRAW_STRING)
812     p.name = "text-graphic"
813     p.description = text
814     p.x = Graphic.CENTER
815     p.y = Graphic.CENTER
816     p.fontWidth = "90"
817     p.fontHeight = str(height)
818     p.red = 255
819     p.blue = 255
820     p.green = 255
821     p.fontName = "Arial"
822     p.fontStyle = p.BOLD
823     p.text = text
824     
825     return p
826
827 # This method is very similar to makeText, but allows
828 # for more control over the text. It allows you to
829 # define the name, description, starting position of
830 # the text (x,y) and the text color (r,g,b)
831 def makeTextXY(name, desc, w, h, x, y, r, g, b):
832     p = GraphicFactory.createGraphic(GraphicFactory.DRAW_STRING)
833     p.name = str(name)
834     p.description = str(desc)
835     p.x = str(x)
836     p.y = str(y)
837     p.fontWidth = str(w)
838     p.fontHeight = str(h)
839     p.red = r
840     p.green = g
841     p.blue = b
842     p.fontName = "Arial"
843     p.fontStyle = p.BOLD
844     p.text = desc
845     
846     return p
847
848 #This method is similar to makeTextXY, but instead
849 # of drawing text, it draws a circle with diameter (d)
850 def makeFilledCircleXY(name, desc, x, y, d, r, g, b):
851     p = GraphicFactory.createGraphic(GraphicFactory.FILL_CIRCLE)
852     p.name = str(name)
853     p.description = desc
854     p.x = str(x)
855     p.y = str(y)
856     p.diameter = str(d)
857     p.red = r
858     p.green = g
859     p.blue = b
860     
861     return p
862
863
864 # This method is the entry point (see task.setStartFunction(...) below).
865 # Initialize the state here in the script, and send a message to clients
866 # telling them to display the initial screen."""
867 def start():
868     global task
869     global dt
870     global dataSet
871     global numClients
872
873     display.showGraphics(0)
874     display.addGraphic(0, makeText("Preloading Images...", "4"))
875     
876     for j in range(len(imageList)):
877         # Send the resource with the given name to the specified client.
878         task.sendResource(0, imageList[j])
879     
880     sleep(2)
881     display.clearGraphics(0)
882     showChoiceScreen()
883
884 #
885 # The following code is always executed.
886 #
887
888 # Create the Task object.
889 task.setExptSize(numClients)
890 task.setStartFunction(start)
891
892 # Set up data types and such
893 dt = task.getDataType(dtName)
894
895 # Set the name of this experiment
896 task.setExperimentName("Release Task")
897
898 # Specify which devices this experiment will use. NEMO provides a method (addDevice)
899 # to create the devices using the following parameters:
900 # - name : the name of the device, which may be viewed by Operators
901 # - class name : the name of the NEMO class for the desired device
902 # - handler method : a reference to the method that will handle incoming data
903 # from this device
904 # The call to this NEMO method returns a Device Handle. This Device Handle can be
905 # used to communicate to the device.
906 #
907 # Note: When specifying the class name of the device, we're using the logical
908 # device, and the Operator at the client location will pick the corresponding
909 # physical device.
910 display = task.addDevice("Display", "nemo.pdi.GraphicalDisplay", fromDisplay)
911 scanner = task.addDevice("Scanner", "nemo.pdi.Scanner", fromScanner)
912 buttonBox = task.addDevice("ButtonBox", "nemo.pdi.ButtonBox", fromButtonBox)
913 movieThing = task.addDevice("Movie", "nemo.pdi.Movie", fromMovie)
914
915 # Grabs all files located in the folder of the given name ie "\testimages"
916 imageList = task.getResourceList("testimages")
917
918 # Create an instance of the Class we defined above.
919 wordDisplay = Words(task, display, dataSet, task.getResourcePath(wordDataFile).getAbsolutePath())
920 # Create an instance of the Class we defined above.
921 imageDisplay = Images(task, display, dataSet, imageList)
922 # Create an instance of the Class we defined above.
923 movieDisplay = Movies(task, display, dataSet, task.getResourcePath('testmovies.config').getAbsolutePath())
924