def main():
    # -------------------------------------------------------------------------
    # Load config; establish database connection; ask the user for anything else
    # -------------------------------------------------------------------------

    log.info("Asking user for config filename")
    config = load_config_or_die(
        mandatory=['database_url'],
        defaults=dict(server='localhost', port=DEFAULT_PORT),
        log_config=True  # send to console (beware security of database URLs)
    )
    db = connect_to_db_using_attrdict(config.database_url)

    # Any additional user input required?
    num_pings = ask_user("Number of pings", default=10, type=int, min=1)
    ask_user("Irrelevant: Heads or tails", default='H', options=['H', 'T'])

    # -------------------------------------------------------------------------
    # Set up task and go
    # -------------------------------------------------------------------------

    session = AttrDict(start=datetime.now(),
                       subject=config.subject,
                       session=config.session,
                       num_pings=num_pings)
    insert_and_set_id(db[SESSION_TABLE], session)  # save to database
    log.info("Off we go...")
    task = MyWhiskerTask(config, db, session)
    task.connect(config.server, config.port)
    # noinspection PyUnresolvedReferences
    reactor.run()  # starts Twisted and thus network processing
    log.info("Finished.")

    # -------------------------------------------------------------------------
    # Done. Calculate summaries. Save data from this session to new CSV files.
    # -------------------------------------------------------------------------

    # Retrieve all our trials. (There may also be many others in the database.)
    # NOTE that find() returns an iterator (you get to iterate through it ONCE).
    # Since we want to use this more than once (below), use a list.
    trials = list(db[TRIAL_TABLE].find(session_id=session.id))

    # Calculate some summary measures
    summary = AttrDict(
        session_id=session.id,  # foreign key
        n_pings_received=sum(t.received for t in trials))
    insert_and_set_id(db[SUMMARY_TABLE], summary)  # save to database

    # Save data. (Since the session and summary objects are single objects, we
    # encapsulate them in a list.)
    save_data("session", [session],
              timestamp=session.start,
              taskname=TASKNAME_SHORT)
    save_data("trial",
              trials,
              timestamp=session.start,
              taskname=TASKNAME_SHORT)
    save_data("summary", [summary],
              timestamp=session.start,
              taskname=TASKNAME_SHORT)
    def shutdown():
        log.info("Storing Data")
        # -------------------------------------------------------------------------
        # Done. Calculate summaries. Save data from this session to new CSV files.
        # -------------------------------------------------------------------------

        # Retrieve all our trials. (There may also be many others in the database.)
        # NOTE that find() returns an iterator (you get to iterate through it ONCE).
        # Since we want to use this more than once (below), use a list.
        trials = list(db[TRIAL_TABLE].find(session_id=session.id))

        # Calculate some summary measures
        summary = AttrDict(
            session_id=session.id,  # foreign key
            date=datetime.utcnow(),
            trials=len(trials),
            trials_rewarded=sum(t.rewarded for t in trials),
        )
        insert_and_set_id(db[SUMMARY_TABLE], summary)  # save to database

        # Save data. (Since the session and summary objects are single objects, we
        # encapsulate them in a list.)
        save_data("session", [session], timestamp=session.start,
                  taskname=TASKNAME_SHORT,directory=save_location)
        save_data("trial", trials, timestamp=session.start,
                  taskname=TASKNAME_SHORT,directory=save_location)
        save_data("summary", [summary], timestamp=session.start,
                  taskname=TASKNAME_SHORT,directory=save_location)
def main():
    # -------------------------------------------------------------------------
    # Load config; establish database connection; ask the user for anything else
    # -------------------------------------------------------------------------

    log.info("Asking user for config filename")
    config = load_config_or_die(
        mandatory=['database_url'],
        defaults=dict(server='localhost', port=DEFAULT_PORT),
        log_config=True  # send to console (beware security of database URLs)
    )
    db = connect_to_db_using_attrdict(config.database_url)

    # Any additional user input required?
    num_pings = ask_user("Number of pings", default=10, type=int, min=1)
    ask_user("Irrelevant: Heads or tails", default='H', options=['H', 'T'])

    # -------------------------------------------------------------------------
    # Set up task and go
    # -------------------------------------------------------------------------

    session = AttrDict(start=datetime.now(),
                       subject=config.subject,
                       session=config.session,
                       num_pings=num_pings)
    insert_and_set_id(db[SESSION_TABLE], session)  # save to database
    log.info("Off we go...")
    task = MyWhiskerTask(config, db, session)
    task.connect(config.server, config.port)
    # noinspection PyUnresolvedReferences
    reactor.run()  # starts Twisted and thus network processing
    log.info("Finished.")

    # -------------------------------------------------------------------------
    # Done. Calculate summaries. Save data from this session to new CSV files.
    # -------------------------------------------------------------------------

    # Retrieve all our trials. (There may also be many others in the database.)
    # NOTE that find() returns an iterator (you get to iterate through it ONCE).
    # Since we want to use this more than once (below), use a list.
    trials = list(db[TRIAL_TABLE].find(session_id=session.id))

    # Calculate some summary measures
    summary = AttrDict(
        session_id=session.id,  # foreign key
        n_pings_received=sum(t.received for t in trials)
    )
    insert_and_set_id(db[SUMMARY_TABLE], summary)  # save to database

    # Save data. (Since the session and summary objects are single objects, we
    # encapsulate them in a list.)
    save_data("session", [session], timestamp=session.start,
              taskname=TASKNAME_SHORT)
    save_data("trial", trials, timestamp=session.start,
              taskname=TASKNAME_SHORT)
    save_data("summary", [summary], timestamp=session.start,
              taskname=TASKNAME_SHORT)
 def incoming_event(self, event, timestamp=None):
     """An event has arrived from the Whisker server."""
     # timestamp is the Whisker server's clock time in ms; we want real time
     now = datetime.utcnow()
     print("Event: {e} (timestamp {t}, real time {n})".format(
         e=event, t=timestamp, n=now.isoformat()))
     # We could do lots of things at this point. But let's keep it simple:
     if event == "EndOfTask":
         # noinspection PyUnresolvedReferences
         reactor.stop()  # stops Twisted and thus network processing
     else:
         trial = AttrDict(
             session_id=self.session.id,  # important foreign key
             trial_num=self.trial_num,
             event="Ping!",
             received=True,  # now we're just making things up...
             when=now,
         )
         insert_and_set_id(self.db[TRIAL_TABLE], trial)  # save to database
         self.trial_num += 1
         log.info("{} pings received so far".format(self.trial_num))
 def incoming_event(self, event, timestamp=None):
     """An event has arrived from the Whisker server."""
     # timestamp is the Whisker server's clock time in ms; we want real time
     now = datetime.utcnow()
     print("Event: {e} (timestamp {t}, real time {n})".format(
         e=event, t=timestamp, n=now.isoformat()))
     # We could do lots of things at this point. But let's keep it simple:
     if event == "EndOfTask":
         # noinspection PyUnresolvedReferences
         reactor.stop()  # stops Twisted and thus network processing
     else:
         trial = AttrDict(
             session_id=self.session.id,  # important foreign key
             trial_num=self.trial_num,
             event="Ping!",
             received=True,  # now we're just making things up...
             when=now,
         )
         insert_and_set_id(self.db[TRIAL_TABLE], trial)  # save to database
         self.trial_num += 1
         log.info("{} pings received so far".format(self.trial_num))
def main():
    # -------------------------------------------------------------------------
    # Load config; establish database connection; ask the user for anything else
    # -------------------------------------------------------------------------
    
    log.info("Asking user for config filename")
    config = load_config_or_die(
        mandatory=['database_url','stimuli_presentation_millis','iti_millis','feedback_millis','feedback_flash_millis','timeout_millis','num_trials','max_task_time_millis','stimuli','screen_resolution','pairings'],
        defaults=dict(server='localhost', port=DEFAULT_PORT),
        log_config=True  # send to console (beware security of database URLs)
    )

    log.info("Asking user where to store the data")
    save_location=open_file_dialog()
    if not save_location:
        log.critical("No directory to store given; exiting.")
        sys.exit(1)
    log.info("Storing data is: {}".format(save_location))
 
    # with open("./config.yaml") as infile:
    #     config = AttrDict(yaml.safe_load(infile))
    #     config.port=DEFAULT_PORT

    validate(config)
    db = connect_to_db_using_attrdict(config.database_url)

    # Any additional user input required?
    # ask_user("Irrelevant: Heads or tails", default='H', options=['H', 'T'])

    # -------------------------------------------------------------------------
    # Set up task and go
    # -------------------------------------------------------------------------

    session = AttrDict(start=datetime.now(),
                       subject=config.subject,
                       session=config.session)
    insert_and_set_id(db[SESSION_TABLE], session)  # save to database
    log.info("Off we go...")
    task = VisualDiscriminationTask(config, db, session)
    task.connect(config.server, config.port)
  
    def shutdown():
        log.info("Storing Data")
        # -------------------------------------------------------------------------
        # Done. Calculate summaries. Save data from this session to new CSV files.
        # -------------------------------------------------------------------------

        # Retrieve all our trials. (There may also be many others in the database.)
        # NOTE that find() returns an iterator (you get to iterate through it ONCE).
        # Since we want to use this more than once (below), use a list.
        trials = list(db[TRIAL_TABLE].find(session_id=session.id))

        # Calculate some summary measures
        summary = AttrDict(
            session_id=session.id,  # foreign key
            date=datetime.utcnow(),
            trials=len(trials),
            trials_rewarded=sum(t.rewarded for t in trials),
        )
        insert_and_set_id(db[SUMMARY_TABLE], summary)  # save to database

        # Save data. (Since the session and summary objects are single objects, we
        # encapsulate them in a list.)
        save_data("session", [session], timestamp=session.start,
                  taskname=TASKNAME_SHORT,directory=save_location)
        save_data("trial", trials, timestamp=session.start,
                  taskname=TASKNAME_SHORT,directory=save_location)
        save_data("summary", [summary], timestamp=session.start,
                  taskname=TASKNAME_SHORT,directory=save_location)

    reactor.addSystemEventTrigger('before', 'shutdown', shutdown)
    # noinspection PyUnresolvedReferences
    reactor.run()  # starts Twisted and thus network processing
    log.info("Finished.")
    shutdown()
    def incoming_event(self, event, timestamp=None):
        """An event has arrived from the Whisker server."""
        # timestamp is the Whisker server's clock time in ms; we want real time
        now = datetime.utcnow()
        whisker=self.whisker
        config=self.config
        print("Event: {e} (timestamp {t}, real time {n})".format(
            e=event, t=timestamp, n=now.isoformat()))
        if event=="flash":
            if self.flashCount%2==1:
                pen=Pen(colour=BLACK)
                brush=Brush(colour=BLACK)
                whisker.display_add_obj_rectangle(self.selection_screen.key,"mask",self.flashmask,pen,brush)
            else:
                whisker.display_delete_obj(self.selection_screen.key,"mask")
            self.flashCount+=1
            return
        if self.state=="iti":
            self.set_state("start")
            whisker.display_show_document("screen","start")
            self.checkConditions()
        elif self.state=="start":
            self.selection_screen=self.trial_order[self.trial_num]
            while not self.selection_screen.enabled:
                trial = AttrDict(
                    session_id=self.session.id,  # important foreign key
                    trial_num=self.trial_num,
                    selected="SKIPPED",
                    when=now,
                    stimuli_left=self.selection_screen.stimuli[0].key,
                    stimuli_right=self.selection_screen.stimuli[1].key,
                    rewarded=False,
                )
                insert_and_set_id(self.db[TRIAL_TABLE], trial) 
                self.trial_num+=1
                self.selection_screen=self.trial_order[self.trial_num]
            whisker.display_show_document("screen",self.selection_screen.key)
            self.set_state("selection")
            whisker.timer_set_event("stimuli_selection_timeout",config.stimuli_presentation_millis,0)
        elif self.state=="selection":
            whisker.display_delete_obj("summary","choice")
            whisker.display_add_obj_text("summary","choice",[
                self.state_screen_centre_x,self.state_screen_centre_y+60]
                ,"Selected: "+event,50,None,False,False,0,[255,255,255])
                
            if event=="stimuli_selection_timeout":
                self.set_state("iti")
                whisker.display_blank("screen")
                whisker.timer_set_event("stimuli_selection",config.iti_millis)
                self.correctResponse=False
            else:
                self.set_state("feedback")
                whisker.timer_set_event("feedback",config.feedback_millis,0)
                whisker.timer_set_event("flash",config.feedback_flash_millis,4*3-2)
                self.flashmask=whisker.display_get_object_extent(self.selection_screen.key,event)
                if self.flashmask:
                    pen=Pen(colour=BLACK)
                    brush=Brush(colour=BLACK)
                    whisker.display_add_obj_rectangle(self.selection_screen.key,"mask",self.flashmask,pen,brush)
                    self.flashCount=0

                rewards=False
                for s in self.selection_screen.stimuli:
                    if s.key==event:
                        rewards=s.reward_ratio>=random.random()
                        if "extinction_rate" in s:
                            s.reward_ratio-=s.extinction_rate
                self.correctResponse=rewards
            whisker.timer_clear_event("stimuli_selection_timeout")

            whisker.display_add_obj_text("summary","choice",[
                self.state_screen_centre_x,self.state_screen_centre_y+120]
                ,"Rewarded: "+str(self.correctResponse),50,None,False,False,0,[255,255,255])
            
            trial = AttrDict(
                session_id=self.session.id,  # important foreign key
                trial_num=self.trial_num,
                selected=event, # either time out or the symbol pressed
                when=now,
                stimuli_left=self.selection_screen.stimuli[0].key,
                stimuli_right=self.selection_screen.stimuli[1].key,
                rewarded=self.correctResponse,
            )
            insert_and_set_id(self.db[TRIAL_TABLE], trial)  # save to database
            self.reward_sequence.append(self.correctResponse)
            self.trial_num += 1
            log.info("{} event received so far".format(self.trial_num))

        elif self.state=="feedback":
            whisker.display_blank("screen")
           
            if self.correctResponse:
                self.set_state("collect_reward")
                whisker.line_set_state("tray_lights",True)
                whisker.line_set_event("ir_beam","beam_broken")
            else:
                whisker.line_set_state("house_lights",True)
                self.set_state("timeout")
                whisker.timer_set_event("timeout",config.timeout_millis,0)
                
        elif event=="timeout" or event=="beam_broken":
            if event=="timeout":
                whisker.line_set_state("house_lights",False)
            else:
                whisker.line_set_state("tray_lights",False)
                whisker.line_clear_event("beam_broken")
            self.set_state("iti")
            whisker.timer_set_event("stimuli_selection",config.iti_millis)
        
        if self.trial_num>=self.config.num_trials or event == "task_time_out":
            reactor.stop()  # stops Twisted and thus network processing