REM >2-CRf REM REM 2-CRf: Two-Stimulus Conditioned Reinforcement REM ------------------------------- REM by Rudolf Cardinal progname$="2-CRf" version_date$="15-Mar-2000" debug% = 0 :REM debugging? shortens all the times REM See CRf for earlier notes. REM REM CRf lever -> p(0.5) -> REM houselight off, CS+ stimulus light on for 0.5 s REM lights back to normal, dipper up for 0.3 s REM NCRf lever -> p(0.5) -> REM houselight off, CS- stimulus light on for 5s REM lights back to normal, and a fast double-click REM (clicker on - wait 0.3 s - clicker off sounded wrong) REM REM QUESTIONS: REM * the CS+/CS- are counterbalanced L/R from the previous phase. REM If I counterbalance this fully, L/R lever could produce L/R light. REM Alternative is to have the lever produce the light above it. Which is preferable? REM * Spoke to BJE, 9 Nov 99. "Anything opposite for rats is hard" - definitely go for each REM lever producing the light located above it. REM Is good, because it's easy programming too. REM THINGS TO DO REM ============ REM Reconsider lever selection code; REM introduce L/R stimulus light choice (set cr_stimulus%() and ncr_stimulus%() to leftlight()%/rightlight()%) REM REVISION HISTORY REM ================ REM Aside from the really obvious changes, REM - cannot initiate an NCR except in wait state REM - both CR and NCR first latencies are allowed even if box not in wait state (e.g. press CR lever for first time during NCR) REM REM 10 Dec 99 - cannot believe this, but the rat name wasn't recorded in the comma-delimited output. Is now. REM 15 Mar 2000 - added session numbers to the record REM STATES OF THE BOX REM ================= REM whichlever: all lights off but levers out REM waits for 3 presses on a lever within a certain time REM makes that lever the CR, the other the NCR REM REM start: waits for a nosepoke (implies rat is central) REM REM Waiting phase: houselight on REM other lights off REM dipper down REM ... until a lever is pressed. REM REM Finished: all lights off, levers retracted, REM wait for someone to come! REM ================================== REM Libraries REM ================================== PROCinit :REM Arachnid init PROCkill_all :REM Arachnid init LIBRARY ".ProgLibs.Filename" LIBRARY ".ProgLibs.DateTime" LIBRARY ".ProgLibs.Ascii" LIBRARY ".ProgLibs.Arachnid" LIBRARY ".ProgLibs.BoxConst" PROCcombined_boxes REM ================================== REM Constants REM ================================== gentimer% = 0 * nboxes% bintimer% = 1 * nboxes% inftimer% = 2 * nboxes% + 1 :REM only one of these! ticktimer% = 2 * nboxes% + 2 :REM only the one... nbins% = 6 :REM number of bins to count in bintime% = 30000 :REM each bin is 5 min -- so 30 min session (6 x 5 min) cr1_time% = 50 :REM 0.5 sec -- applies to CR and NCR cr2_time% = 30 :REM 0.3 sec -- applies to CR and NCR random_ratio = 0.5 :REM Reinforcer occurs on 50% of CR lever presses leverchoice% = 3 :REM press lever 3 times to make it the CR lever leverchoicetime% = 100 :REM ... within 100 csec ... consecutively yes%=1 : no%=0 left%=1 : right%=2 infusing% = 1: diffusing% = 2 inf_time% = 12500 :REM 125s of infusion diff_time% = 6000 :REM 60s of diffusion ticktime% = 100 : REM update clocks once every second not_watching% = 0 whichlever_state% = 1 :REM before we begin start_state% = 2 :REM start on next nosepoke wait_state% = 3 :REM main hanging around state cr_state% = 4 :REM during CR ncr_state% = 5 :REM during NCR (wasn't used in CRf task) finished_state% = 6 :REM all done IF debug% = 1 THEN bintime% = 1000 inf_time% = 500: diff_time% = 500 ENDIF quit$="quit"+CHR$13 quitcount% = 1 REM ================================== REM Variable assignments REM ================================== inftimer_status%=no% DIM cr_lever%(nboxes%) :REM which lever is the CR? DIM ncr_lever%(nboxes%) :REM ... so the other one is ... DIM cr_stimulus%(nboxes%) :REM which light is the CS+? DIM ncr_stimulus%(nboxes%) :REM which light is the CS-? DIM lever$(nboxes%) :REM a human-friendly version DIM leftcount%(nboxes%) :REM used for initial lever choice DIM rightcount%(nboxes%) DIM watching%(nboxes%) DIM counting%(nboxes%) DIM start_time%(nboxes%) :REM start of *this* nosepoke DIM state%(nboxes%) :REM what phase is the box in? DIM finished%(nboxes%) :REM all done? DIM bin1_start%(nboxes%) :REM time at start of bin 1 DIM bin%(nboxes%) :REM which bin is the box in? 0 => before, :REM nbins%+1 => done REM *** Monitored aspects DIM box_name$(nboxes%) :REM what's the rat called?# DIM session_number%(nboxes%) :REM 15 Mar 2000 DIM start_time$(nboxes%) :REM time of starting poke DIM end_time$(nboxes%) DIM cr_responses%(nboxes%,nbins%), ncr_responses%(nboxes%,nbins%) REM count of CR/NCR responses DIM cr_reinf_count%(nboxes%,nbins%), ncr_reinf_count%(nboxes%,nbins%) REM count of secondary reinforcers (CS+/CR) and NCR (CS-) presentations, respectively DIM cr_total%(nboxes%), ncr_total%(nboxes%), cr_reinf_total%(nboxes%), ncr_reinf_total%(nboxes%) DIM wait_pokestotal%(nboxes%), cr_pokestotal%(nboxes%), ncr_pokestotal%(nboxes%) DIM wait_durtotal%(nboxes%), cr_durtotal%(nboxes%), ncr_durtotal%(nboxes%) DIM wait_pokes%(nboxes%,nbins%), cr_pokes%(nboxes%,nbins%), ncr_pokes%(nboxes%,nbins%) DIM wait_pokedur%(nboxes%,nbins%), cr_pokedur%(nboxes%,nbins%), ncr_pokedur%(nboxes%,nbins%) DIM poke_latency%(nboxes%), cr_latency%(nboxes%), ncr_latency%(nboxes%) REM time from start of bin 1 until first whatever. Initialized to -1. REM *** final records; boxes are re-used but data is copied here records% = nboxes% * 10 :REM allows 10 'goes' per box max. rec% = 0 :REM number of records begun DIM boxrec%(nboxes%) :REM so you know which record it *will* be DIM rec_box_name$(records%) DIM rec_session_number%(records%) :REM 15 Mar 2000 DIM rec_box_number%(records%) DIM rec_start_time$(records%) DIM rec_end_time$(records%) DIM rec_lever$(records%) DIM rec_cr_responses%(records%,nbins%), rec_ncr_responses%(records%,nbins%) DIM rec_cr_reinf_count%(records%,nbins%), rec_ncr_reinf_count%(records%,nbins%) DIM rec_cr_total%(records%),rec_ncr_total%(records%),rec_cr_reinf_total%(records%),rec_ncr_reinf_total%(records%) DIM rec_wait_pokestotal%(records%), rec_cr_pokestotal%(records%), rec_ncr_pokestotal%(records%) DIM rec_wait_durtotal%(records%), rec_cr_durtotal%(records%), rec_ncr_durtotal%(records%) DIM rec_wait_pokes%(records%,nbins%),rec_cr_pokes%(records%,nbins%),rec_ncr_pokes%(records%,nbins%) DIM rec_wait_pokedur%(records%,nbins%),rec_cr_pokedur%(records%,nbins%),rec_ncr_pokedur%(records%,nbins%) DIM rec_poke_latency%(records%), rec_cr_latency%(records%), rec_ncr_latency%(records%) REM ================================= REM Initialize screen REM ================================= MODE 12:CLS dummy=RND(-TIME): REM seed random number generator PRINT progname$;", by Rudolf Cardinal, ";version_date$; IF debug%=1 THEN COLOUR 3:PRINT" -- debugging!":COLOUR7 ELSE PRINT ENDIF PRINT INPUT LINE "What's today's experiment called? " exp_title$ PRINT OSCLI("CAT") PRINT datafile$ = FNget_filename("DATA FILE - enter filename (no spaces etc.)") logfile$ = FNget_filename("TEXT LOG - enter filename (no spaces etc.)") date_time$ = FNdate_time_code PRINT PRINT "And the rats... (NB no commas!)" FOR i% = 1 TO nboxes% PRINT " Rat in box ";i%;": "; INPUT LINE "" box_name$(i%) INPUT " Session: " session_number%(i%) PRINT NEXT REM ========================================== REM Go! REM ========================================== PROCstart PROCpipe_keybd(0,0,0,"FNkeyboard_handler(",0,E%) PROCwait(E%): *AE END REM ============================================ REM ******************************************** REM ============================================ DEF PROCstart REM when we're ready, initialise and go PRINT"Ready to run, press a key to start..." IF GET PROCdisplay_startup *FX 229,1 REM that disables the Escape key (*FX229,0 to enable) FOR box% = 1 TO nboxes% PROCstart_the_box(box%) NEXT REM ... and start the clock display PROCpipe_timer(ticktimer%,ticktime%,ticktime%,"FNtick_tick_tick(",1,E%) ENDPROC DEF PROCstart_the_box(box%) REM clear the boxes to the null state REM the following stay off throughout the program PROCswitch_off(traylight%(box%), E%) rec% += 1 IF rec%>records% THEN PRINT"Disastrous error -- too many goes. Bug." boxrec%(box%) = rec% :REM this box will be stored as record number rec% bin%(box%) = 0 FOR bint% = 1 TO nbins% cr_responses%(box%,bint%)=0 ncr_responses%(box%,bint%)=0 cr_reinf_count%(box%,bint%)=0 ncr_reinf_count%(box%,bint%)=0 wait_pokes%(box%,bint%)=0:cr_pokes%(box%,bint%)=0:ncr_pokes%(box%,bint%)=0 wait_pokedur%(box%,bint%)=0:cr_pokedur%(box%,bint%)=0:ncr_pokedur%(box%,bint%)=0 NEXT cr_total%(box%)=0: ncr_total%(box%)=0: cr_reinf_total%(box%)=0: ncr_reinf_total%(box%)=0 wait_pokestotal%(box%)=0:cr_pokestotal%(box%)=0:ncr_pokestotal%(box%)=0 wait_durtotal%(box%)=0:cr_durtotal%(box%)=0:ncr_durtotal%(box%)=0 finished%(box%) = no% watching%(box%) = not_watching% counting%(box%) = no% poke_latency%(box%) = -1: cr_latency%(box%) = -1: ncr_latency%(box%) = -1 PROCset_whichlever(box%) PROCdisplay_box(box%) ENDPROC DEF FNtimeout(box%,R%) IF R%=0 =0 leftcount%(box%) = leverchoice% rightcount%(box%) = leverchoice% =0 DEF FNpick_lever_l(box%,R%) IF R%=0 =0 IF state%(box%) <> whichlever_state% THEN =0 leftcount%(box%) -= 1: rightcount%(box%) = leverchoice% IF leftcount%(box%) <= 0 THEN PROCstart_box(box%,leftlever%(box%)) ELSE PROCpipe_timer(box%,leverchoicetime%,0,"FNtimeout(",box%,E%) ENDIF =0 DEF FNpick_lever_r(box%,R%) IF R%=0 =0 IF state%(box%) <> whichlever_state% THEN =0 rightcount%(box%) -= 1: leftcount%(box%) = leverchoice% IF rightcount%(box%) <= 0 THEN PROCstart_box(box%,rightlever%(box%)) ELSE PROCpipe_timer(box%,leverchoicetime%,0,"FNtimeout(",box%,E%) ENDIF =0 DEF PROCstart_box(box%,cr%) PROCkill_switch(leftlever%(box%),E%) PROCkill_switch(rightlever%(box%),E%) :REM don't know if that's needed, but there were some funny problems cr_lever%(box%) = cr% CASE cr_lever%(box%) OF WHEN leftlever%(box%): cr_stimulus%(box%) = leftlight%(box%) ncr_lever%(box%) = rightlever%(box%) ncr_stimulus%(box%) = rightlight%(box%) lever$(box%) = "L" WHEN rightlever%(box%): cr_stimulus%(box%) = rightlight%(box%) ncr_lever%(box%) = leftlever%(box%) ncr_stimulus%(box%) = leftlight%(box%) lever$(box%) = "R" ENDCASE bin%(box%) = 0 : REM before bin 1 has started PROCpipe_switch(cr_lever%(box%),On,1,"FNcr_lever(",box%,E%) PROCpipe_switch(ncr_lever%(box%),On,1,"FNncr_lever(",box%,E%) PROCset_start(box%) IF FNswitch(nosepoke%(box%),E%)=On THEN PROCenter_magazine(box%) REM if the rat's already in, let's get going! PROCdisplay_box(box%) ENDPROC REM ***************************************************************** REM Levers REM ***************************************************************** DEF FNcr_lever(box%,R%) IF R%=0 =0 REM These levers are piped *throughout*. Therefore this function must REM only initiate a CR response if the box was in the "wait" state. REM But lever presses are counted if the box is in wait, cr or ncr states. REM IF (state%(box%)<>wait_state% AND state%(box%)<>cr_state% AND state%(box%)<>ncr_state%) THEN =0 cr_responses%(box%,bin%(box%)) += 1 PROCfirst_cr(box%) IF state%(box%) <> wait_state% THEN =0 REM don't want to initiate one CR during another one! IF RND(1) < random_ratio THEN PROCstop_counting(box%) :REM only stop if actually doing something! cr_reinf_count%(box%,bin%(box%)) += 1 PROCset_cr1(box%) PROCpipe_timer(box%,cr1_time%,0,"FNcr_halfway(",box%,E%) PROCstart_counting(box%) PROCdisplay_state(box%) ELSE PROCdisplay_box(box%) ENDIF =0 DEF FNcr_halfway(box%,R%) IF R%=0 =0 PROCset_cr2(box%) PROCpipe_timer(box%,cr2_time%,0,"FNcr_done(",box%,E%) =0 DEF FNcr_done(box%,R%) IF R%=0 =0 REM end of CR consequence PROCstop_counting(box%) IF finished%(box%)=yes% THEN PROCset_finished(box%):=0 :REM on the offchance that a CR is executing as the box finishes. PROCset_wait(box%) PROCdisplay_box(box%) =0 DEF FNncr_lever(box%,R%) IF R%=0 =0 REM See comments above (under FNcr_lever) IF (state%(box%)<>wait_state% AND state%(box%)<>cr_state% AND state%(box%)<>ncr_state%) THEN =0 ncr_responses%(box%,bin%(box%)) += 1 PROCfirst_ncr(box%) IF state%(box%) <> wait_state% THEN =0 IF RND(1) < random_ratio THEN PROCstop_counting(box%) :REM only stop if actually doing something! ncr_reinf_count%(box%,bin%(box%)) += 1 PROCset_ncr1(box%) PROCpipe_timer(box%,cr1_time%,0,"FNncr_halfway(",box%,E%) PROCstart_counting(box%) PROCdisplay_state(box%) ELSE PROCdisplay_box(box%) ENDIF =0 DEF FNncr_halfway(box%,R%) IF R%=0 =0 PROCset_ncr2(box%) PROCpipe_timer(box%,cr2_time%,0,"FNncr_done(",box%,E%) =0 DEF FNncr_done(box%,R%) IF R%=0 =0 REM end of NCR consequence PROCstop_counting(box%) IF finished%(box%)=yes% THEN PROCset_finished(box%):=0 :REM on the offchance that a NCR is executing as the box finishes. PROCset_wait(box%) PROCdisplay_box(box%) =0 DEF PROCfirst_cr(box%) IF cr_latency%(box%)=-1 THEN cr_latency%(box%)=TIME-bin1_start%(box%) ENDPROC DEF PROCfirst_ncr(box%) IF ncr_latency%(box%)=-1 THEN ncr_latency%(box%)=TIME-bin1_start%(box%) ENDPROC REM ***************************************************************** REM Nosepokes REM ***************************************************************** DEF PROCstart_counting(box%) counting%(box%) = yes% IF FNswitch(nosepoke%(box%),E%)=On THEN PROCenter_magazine(box%) REM as the event is scheduled on a transition, it'll get lost if REM the switch is active at startup, without this extra check. ENDPROC DEF PROCstop_counting(box%) IF watching%(box%) <> not_watching% THEN PROCleave_magazine(box%) counting%(box%) = no% ENDPROC DEF FNmagazine_changed(box%,R%) IF R%=0 =0 IF counting%(box%)=no% AND state%(box%)<>start_state% THEN =0 IF FNswitch(nosepoke%(box%),E%)=On THEN PROCenter_magazine(box%) ELSE PROCleave_magazine(box%) ENDIF =0 DEF PROCenter_magazine(box%) CASE state%(box%) OF WHEN wait_state%: start_time%(box%)=TIME:watching%(box%)=state%(box%) wait_pokes%(box%,bin%(box%)) += 1 PROCfirst_poke(box%) WHEN cr_state%: start_time%(box%)=TIME:watching%(box%)=state%(box%) cr_pokes%(box%,bin%(box%)) += 1 PROCfirst_poke(box%) WHEN ncr_state%: start_time%(box%)=TIME:watching%(box%)=state%(box%) ncr_pokes%(box%,bin%(box%)) += 1 PROCfirst_poke(box%) WHEN start_state%: REM rat central, can go start_time$(box%)=TIME$ bin1_start%(box%) = TIME bin%(box%) = 1 PROCpipe_timer(bintimer%+box%,bintime%,0,"FNbintimeout(",box%,E%) PROCset_wait(box%) PROCdisplay_box(box%) WHEN finished_state%: ENDCASE PROCdisplay_switch(box%) ENDPROC DEF PROCfirst_poke(box%) REM only comes here from wait/cr/ncr states REM which are only entered *after* bin 1 has been started by PROCstart_box REM so the following is safe. REM I don't believe TIME-bin1_start will ever be -1. A risk, but hey ;-) IF poke_latency%(box%)=-1 THEN poke_latency%(box%)=TIME-bin1_start%(box%) ENDPROC DEF PROCleave_magazine(box%) CASE watching%(box%) OF WHEN wait_state%: wait_pokedur%(box%,bin%(box%))+=TIME-start_time%(box%) WHEN cr_state%: cr_pokedur%(box%,bin%(box%))+=TIME-start_time%(box%) WHEN ncr_state%: ncr_pokedur%(box%,bin%(box%))+=TIME-start_time%(box%) WHEN not_watching%: ENDCASE watching%(box%) = not_watching% PROCdisplay_switch(box%) ENDPROC REM ***************************************************************** REM States of the box REM ***************************************************************** DEF PROCset_whichlever(box%) PROCswitch_off(houselight%(box%),E%) PROCswitch_off(leftlight%(box%),E%) PROCswitch_off(rightlight%(box%),E%) PROCswitch_off(clicker%(box%),E%) PROCswitch_off(dipper%(box%),E%) PROCswitch_on(leftlevercontrol%(box%),E%) PROCswitch_on(rightlevercontrol%(box%),E%) state%(box%) = whichlever_state% lever$(box%) = "?" leftcount%(box%) = leverchoice% rightcount%(box%) = leverchoice% :REM this state terminates when one lever is pressed leverchoice% times :REM (consecutively) by the experimenter within leverchoicetime% PROCpipe_switch(leftlever%(box%),On,1,"FNpick_lever_l(",box%,E%) PROCpipe_switch(rightlever%(box%),On,1,"FNpick_lever_r(",box%,E%) PROCpipe_switch(nosepoke%(box%),Over,1,"FNmagazine_changed(",box%,E%) ENDPROC DEF PROCset_start(box%) PROCswitch_off(houselight%(box%),E%) PROCswitch_off(cr_stimulus%(box%),E%) PROCswitch_off(ncr_stimulus%(box%),E%) PROCswitch_off(clicker%(box%),E%) PROCswitch_off(dipper%(box%),E%) PROCswitch_off(leftlevercontrol%(box%),E%) PROCswitch_off(rightlevercontrol%(box%),E%) state%(box%) = start_state% ENDPROC DEF PROCset_wait(box%) state%(box%) = wait_state% PROCswitch_on(houselight%(box%),E%) PROCswitch_off(cr_stimulus%(box%),E%) PROCswitch_off(ncr_stimulus%(box%),E%) PROCswitch_off(clicker%(box%),E%) PROCswitch_off(dipper%(box%),E%) PROCswitch_on(leftlevercontrol%(box%),E%) PROCswitch_on(rightlevercontrol%(box%),E%) PROCstart_counting(box%) ENDPROC DEF PROCset_cr1(box%) PROCswitch_off(houselight%(box%),E%) PROCswitch_on(cr_stimulus%(box%),E%) PROCswitch_off(ncr_stimulus%(box%),E%) PROCswitch_off(clicker%(box%),E%) PROCswitch_off(dipper%(box%),E%) PROCswitch_on(leftlevercontrol%(box%),E%) PROCswitch_on(rightlevercontrol%(box%),E%) state%(box%) = cr_state% ENDPROC DEF PROCset_cr2(box%) PROCswitch_on(houselight%(box%),E%) PROCswitch_off(cr_stimulus%(box%),E%) PROCswitch_off(ncr_stimulus%(box%),E%) PROCswitch_off(clicker%(box%),E%) PROCswitch_on(dipper%(box%),E%) PROCswitch_on(leftlevercontrol%(box%),E%) PROCswitch_on(rightlevercontrol%(box%),E%) state%(box%) = cr_state% :REM still ENDPROC DEF PROCset_ncr1(box%) PROCswitch_off(houselight%(box%),E%) PROCswitch_off(cr_stimulus%(box%),E%) PROCswitch_on(ncr_stimulus%(box%),E%) PROCswitch_off(clicker%(box%),E%) PROCswitch_off(dipper%(box%),E%) PROCswitch_on(leftlevercontrol%(box%),E%) PROCswitch_on(rightlevercontrol%(box%),E%) state%(box%) = ncr_state% ENDPROC DEF PROCset_ncr2(box%) PROCswitch_on(houselight%(box%),E%) PROCswitch_off(cr_stimulus%(box%),E%) PROCswitch_off(ncr_stimulus%(box%),E%) PROCfast_pellet(clicker%(box%),1) REM If you wanted clicker on - 0.3 s - clicker off, REM would have used PROCswitch_on(clicker%(box%),E%) REM but that sounded wrong. PROCswitch_off(dipper%(box%),E%) PROCswitch_on(leftlevercontrol%(box%),E%) PROCswitch_on(rightlevercontrol%(box%),E%) state%(box%) = ncr_state% :REM still ENDPROC DEF PROCset_finished(box%) PROCswitch_off(houselight%(box%),E%) PROCswitch_off(leftlevercontrol%(box%),E%) PROCswitch_off(rightlevercontrol%(box%),E%) PROCswitch_off(dipper%(box%),E%) state%(box%) = finished_state% ENDPROC REM ***************************************************************** REM Count everything in (5-minute) bins REM ***************************************************************** DEF FNbintimeout(box%,R%) IF R%=0 =0 REM Bin time has elapsed. Move to next bin. REM This does *not* take account of any CR/NCR currently in progress REM (e.g. by waiting for it to finish). This introduces a maximum pseudo- REM bin timing inaccuracy of the duration of the CR or NCR consequence. REM If the final timeout occurs during a CR/NCR, it'll be interrupted REM Important that counting is stopped during the transition! PROCstop_counting(box%) bin%(box%) += 1 cr_total%(box%) += cr_responses%(box%,bin%(box%)-1) ncr_total%(box%) += ncr_responses%(box%,bin%(box%)-1) cr_reinf_total%(box%) += cr_reinf_count%(box%,bin%(box%)-1) ncr_reinf_total%(box%) += ncr_reinf_count%(box%,bin%(box%)-1) wait_durtotal%(box%) += wait_pokedur%(box%,bin%(box%)-1) cr_durtotal%(box%) += cr_pokedur%(box%,bin%(box%)-1) ncr_durtotal%(box%) += ncr_pokedur%(box%,bin%(box%)-1) wait_pokestotal%(box%) += wait_pokes%(box%,bin%(box%)-1) cr_pokestotal%(box%) += cr_pokes%(box%,bin%(box%)-1) ncr_pokestotal%(box%) += ncr_pokes%(box%,bin%(box%)-1) IF bin%(box%) > nbins% THEN PROCfinish(box%) ELSE PROCpipe_timer(bintimer%+box%,bintime%,0,"FNbintimeout(",box%,E%) PROCstart_counting(box%) PROCdisplay_box(box%) ENDIF =0 REM *********************************************************** REM Finishing up and all display code REM *********************************************************** DEF PROCfinish(box%) PROCkill_switch(leftlever%(box%),E%) PROCkill_switch(rightlever%(box%),E%) PROCkill_switch(nosepoke%(box%),E%) PROCset_finished(box%) PROCdisplay_box(box%) end_time$(box%)=TIME$ PROCcopy_to_record(box%,boxrec%(box%)) REM "multiple goes" technique: if and only if a box is restarted REM before all boxes are finished, the program continues. REM So the check below is still valid. REM don't call display_box as trial% now too big REM I'm scared that if I start reporting for a box before they've REM all finished, the other three will be inaccurately timed for REM the last session. Hence this check. finished%(box%) = yes% FOR i% = 1 TO nboxes% IF finished%(i%) <> yes% THEN ENDPROC NEXT PROCkill_all :REM get rid of the keyboard handler! (and inftimer...) *FX229,0 REM re-enable Escape key VDU 2 :REM turn on printer CLS OSCLI("SPOOL "+logfile$) :REM output to logfile PRINT"**********************************************************" PRINT"Results from !";progname$;" on ";TIME$ PRINT"Experiment: ";exp_title$ PRINT"Date/time code: ";date_time$ PRINT"Log filename: ";logfile$ PRINT"Data filename: ";datafile$ PRINT"Using ";nbins%;" bins of ";bintime%/6000;" min each." PRINT"**********************************************************"' FOR i% = 1 TO rec% PROCfinal_output(i%) NEXT OSCLI("SPOOL") OSCLI("SETTYPE "+logfile$+" TEXT") VDU 3 :REM printer off, close file REM Now output raw data for importing into Access/Excel REM Times in seconds REM Note that @% doesn't affect result of STR$(), so there is a lot of REM exponential notation for small numbers. Hope Access can cope. ch% = OPENOUT(datafile$) PROCprint_string(ch%,"PROGNAME,SESSION_ID,RAT,SESSION_NUMBER,BOX,BINTIME,CR_LEVER,CR_LATENCY,") PROCprint_line(ch%,"NCR_LATENCY,BIN,CR,NCR,CR_REINF,NCR_REINF,CR_POKES,CR_POKETIME,NCR_POKES,NCR_POKETIME,WAIT_POKES,WAIT_POKETIME") FOR i% = 1 TO rec% d1$=progname$+","+date_time$+"-"+STR$(i%)+","+rec_box_name$(i%)+","+STR$(rec_session_number%(i%))+"," d1$ = d1$ + STR$(rec_box_number%(i%))+","+STR$(bintime%/100)+","+rec_lever$(i%)+","+STR$(rec_cr_latency%(i%)/100)+","+STR$(rec_ncr_latency%(i%)/100) FOR j% = 1 TO nbins% PROCprint_string(ch%,d1$) PROCprint_string(ch%, "," + STR$(j%) +","+ STR$(rec_cr_responses%(i%,j%)) +","+ STR$(rec_ncr_responses%(i%,j%)) ) PROCprint_string(ch%, "," + STR$(rec_cr_reinf_count%(i%,j%)) +","+ STR$(rec_ncr_reinf_count%(i%,j%)) ) PROCprint_string(ch%, "," + STR$(rec_cr_pokes%(i%,j%)) +","+ STR$(rec_cr_pokedur%(i%,j%)/100) ) PROCprint_string(ch%, "," + STR$(rec_ncr_pokes%(i%,j%)) +","+ STR$(rec_ncr_pokedur%(i%,j%)/100) ) PROCprint_line(ch%, "," + STR$(rec_wait_pokes%(i%,j%)) +","+ STR$(rec_wait_pokedur%(i%,j%)/100) ) NEXT NEXT CLOSE#ch% PRINT'"Finished at ";TIME$ PRINT"If you want that again, use PROCfinal_output(record number)."'' FOR i% = 1 TO rec% PRINT"Record ";i%;": box ";rec_box_number%(i%);" (";rec_box_name$(i%);"): CR ";rec_cr_total%(i%);", NCR ";rec_ncr_total%(i%) NEXT ENDPROC DEF PROCcopy_to_record(box%,rec%) REM oh, for a language with classes rec_box_name$(rec%) = box_name$(box%) rec_session_number%(rec%) = session_number%(box%) rec_box_number%(rec%) = box% rec_start_time$(rec%) = start_time$(box%) rec_end_time$(rec%) = end_time$(box%) rec_lever$(rec%) = lever$(box%) FOR bint% = 1 TO nbins% rec_cr_responses%(rec%,bint%) = cr_responses%(box%,bint%) rec_ncr_responses%(rec%,bint%) = ncr_responses%(box%,bint%) rec_cr_reinf_count%(rec%,bint%) = cr_reinf_count%(box%,bint%) rec_ncr_reinf_count%(rec%,bint%) = ncr_reinf_count%(box%,bint%) rec_wait_pokes%(rec%,bint%) = wait_pokes%(box%,bint%) rec_cr_pokes%(rec%,bint%) = cr_pokes%(box%,bint%) rec_ncr_pokes%(rec%,bint%) = ncr_pokes%(box%,bint%) rec_wait_pokedur%(rec%,bint%) = wait_pokedur%(box%,bint%) rec_cr_pokedur%(rec%,bint%) = cr_pokedur%(box%,bint%) rec_ncr_pokedur%(rec%,bint%) = ncr_pokedur%(box%,bint%) NEXT rec_cr_total%(rec%) = cr_total%(box%) rec_ncr_total%(rec%) = ncr_total%(box%) rec_cr_reinf_total%(rec%) = cr_reinf_total%(box%) rec_ncr_reinf_total%(rec%) = ncr_reinf_total%(box%) rec_wait_pokestotal%(rec%) = wait_pokestotal%(box%) rec_cr_pokestotal%(rec%) = cr_pokestotal%(box%) rec_wait_durtotal%(rec%) = wait_durtotal%(box%) rec_cr_durtotal%(rec%) = cr_durtotal%(box%) rec_poke_latency%(rec%) = poke_latency%(box%) rec_cr_latency%(rec%) = cr_latency%(box%) rec_ncr_latency%(rec%) = ncr_latency%(box%) ENDPROC DEF PROCdisplay_startup CLS PRINT progname$;", by Rudolf Cardinal, ";version_date$; IF debug%=1 THEN COLOUR 3:PRINT" -- debugging!":COLOUR7 ELSE PRINT ENDIF PRINT PRINT"Experiment: ";:COLOUR 1:PRINTexp_title$:COLOUR 7 PRINT"Number of bins: ";nbins%;" (of ";bintime%/6000;" min each)" PRINT"Started at: ";TIME$ PRINT PRINT"- Times shown below are in seconds. System accuracy is 1cs." PRINT"- First line: current bin. Second line: sum of completed bins." PRINT"- Type 'quit' and press Return to abort in an emergency. Case-sensitive." PRINT"- Press for an infusion timer (infusion: ";inf_time%/100;"s, wait: ";diff_time%/100;"s)." PRINT"- You may RESTART a box by typing its number when it is in the" PRINT" Finished state. Program will end when all boxes have finished." PRINT PRINT"Box Rec LR Bin State In? CR# NCR# CR NCR wait CR-time ";:COLOUR 2:PRINT"Time left":COLOUR 7 PRINT" rnf# rnf# time" PRINT"-----------------------------------------------------------------------------" REM 0 1 2 3 4 5 6 7 8 display_firstline%=VPOS ENDPROC DEF PROCdisplay_box(box%) line% = FNdisplay_line(box%) PRINTTAB(0,line%);box%; PRINTTAB(4,line%);boxrec%(box%); PRINTTAB(8,line%);lever$(box%); PRINTTAB(11,line%);bin%(box%); IF bin%(box%) <= nbins% THEN PRINTTAB(29,line%);SPC(50); PRINTTAB(29,line%);cr_responses%(box%,bin%(box%)); PRINTTAB(34,line%);ncr_responses%(box%,bin%(box%)); PRINTTAB(40,line%);cr_reinf_count%(box%,bin%(box%)); PRINTTAB(46,line%);ncr_reinf_count%(box%,bin%(box%)); PRINTTAB(52,line%);wait_pokedur%(box%,bin%(box%))/100; PRINTTAB(58,line%);cr_pokedur%(box%,bin%(box%))/100; ENDIF PRINTTAB(29,line%+1);SPC(50); PRINTTAB(29,line%+1);cr_total%(box%); PRINTTAB(34,line%+1);ncr_total%(box%); PRINTTAB(40,line%+1);cr_reinf_total%(box%); PRINTTAB(46,line%+1);ncr_reinf_total%(box%); PRINTTAB(52,line%+1);wait_durtotal%(box%)/100; PRINTTAB(58,line%+1);cr_durtotal%(box%)/100; PROCdisplay_state(box%) PROCdisplay_switch(box%) ENDPROC DEF PROCdisplay_state(box%) line% = FNdisplay_line(box%) PRINTTAB(15,line%); CASE state%(box%) OF WHEN whichlever_state%: COLOUR 3:PRINT"R or L?";:COLOUR 7 WHEN start_state%: COLOUR 1:PRINT"Poke? ";:COLOUR 7 WHEN finished_state%: COLOUR 3:PRINT"* Done.";:COLOUR 7 WHEN wait_state%: PRINT"Waiting"; WHEN cr_state%: PRINT"CR "; WHEN ncr_state%: PRINT"NCR "; ENDCASE ENDPROC DEF PROCdisplay_switch(box%) IF box%=0 THEN PRINT"some berk is calling for box 0" line% = FNdisplay_line(box%) PRINTTAB(24,line%); CASE FNswitch(nosepoke%(box%),E%) OF WHEN On: PRINT"*"; WHEN Off: PRINT" "; ENDCASE ENDPROC DEF FNtick_tick_tick(junk%,R%) IF R%=0 =0 LOCAL i% COLOUR 2 FOR i% = 1 TO nboxes% PRINTTAB(68,FNdisplay_line(i%)); IF (state%(i%)=wait_state% OR state%(i%)=cr_state%) THEN PRINT FNtimeleft(i%); ELSE PRINT" "; ENDIF NEXT COLOUR 7 =0 DEF FNdisplay_line(box%) = display_firstline% + (box%-1)*3 DEF PROCfinal_output(r%) LOCAL npt%, npc% PRINT"=====================================================================" PRINT"Record #";r% PRINT"Box ";rec_box_number%(r%);" - ";rec_box_name$(r%);" (CR = ";rec_lever$(r%);")" PRINT"Session number: ";rec_session_number%(r%) PRINT"Started at: ";rec_start_time$(r%) PRINT"Finished at: ";rec_end_time$(r%) PRINT"=====================================================================" PRINT"*** The bottom line: total CR# = ";rec_cr_total%(r%);", NCR# = ";rec_ncr_total%(r%) PRINT"*** Latencies from session start (-0.01=never): CRpress ";rec_cr_latency%(r%)/100;" s, NCRpress = ";rec_ncr_latency%(r%)/100;" s" REM PRINTTAB(7);"First nosepoke ";rec_poke_latency%(r%)/100; REM commented out as always 0, stupid. Nosepoke starts the session! npt%=0:npc%=0 FOR b% = 1 TO nbins% npt% += rec_cr_pokedur%(r%,b%) npt% += rec_wait_pokedur%(r%,b%) npc% += rec_cr_pokes%(r%,b%) npc% += rec_wait_pokes%(r%,b%) NEXT PRINT"*** Total nosepoke time = ";npt%/100;" s; total nosepoke count = ";npc% PRINT PRINT"Total number of CR presentations : ";rec_cr_reinf_total%(r%) PRINT"Total number of NCR presentations: ";rec_ncr_reinf_total%(r%) FOR b% = 1 TO nbins% PRINT" BIN ";b%;":" PRINTTAB(7); "CR lever responses: ";rec_cr_responses%(r%,b%); PRINTTAB(40);"NCR lever responses: ";rec_ncr_responses%(r%,b%) PRINTTAB(7); "- CR reinforcers delivered: ";rec_cr_reinf_count%(r%,b%) PRINTTAB(7); "- NCR reinforcers delivered: ";rec_ncr_reinf_count%(r%,b%) PRINTTAB(7); "- CR period: nosepoke count = ";rec_cr_pokes%(r%,b%); PRINT "; duration = ";rec_cr_pokedur%(r%,b%)/100;" sec" PRINTTAB(7); "- Wait period: nosepoke count = ";rec_wait_pokes%(r%,b%); PRINT "; duration = ";rec_wait_pokedur%(r%,b%)/100;" sec" NEXT PRINT PRINT REM0 1 2 3 4 5 6 ENDPROC REM *********************************************************** REM Restarting a box REM *********************************************************** DEF FNkeyboard_handler(P%,R%) IF R%=0 =0 LOCAL b% key% = GET IF key%=ASC(MID$(quit$,quitcount%,1)) THEN quitcount% += 1 IF quitcount% > LEN(quit$) THEN PROCabort_program ELSE quitcount% = 1 :REM restart the 'counter' ENDIF IF key%=32 THEN PROCinftimer:=0 IF key%>=ASC("1") AND key%<=ASC("9") THEN b%=key%-ASC("0") ELSE =0 IF b%>nboxes% THEN =0 IF finished%(b%)=no% THEN =0 :REM Piss orff! We're the Judean People's Front! IF rec%=records% THEN =0 :REM too many already, don't start another PROCstart_the_box(b%) =0 DEF PROCinftimer IF inftimer_status% <> no% THEN ENDPROC inftimer_status% = infusing% VDU 7 COLOUR 5:PRINTTAB(65,0);"Infusing... ":COLOUR 7 PROCpipe_timer(inftimer%,inf_time%,0,"FNinftimer2(",1,E%) ENDPROC DEF FNinftimer2(junk%,R%) IF R%=0 =0 inftimer_status% = diffusing% VDU 7 :REM beep COLOUR 5:PRINTTAB(65,0);"Diffusing...":COLOUR 7 PROCpipe_timer(inftimer%,diff_time%,0,"FNinftimer3(",1,E%) =0 DEF FNinftimer3(junk%,R%) IF R%=0 =0 inftimer_status% = no% VDU 7 PRINTTAB(65,0);" " =0 DEF FNtimeleft(box%) LOCAL t%,m%,s%,t$ t% = bin1_start%(box%) + (nbins%*bintime%) - TIME m%=(t%/100) DIV 60 s%=(t%/100) MOD 60 t$="" IF m%<10 THEN t$+=" " t$+=STR$(m%)+":" IF s%<10 THEN t$+="0" t$+=STR$(s%) =t$ DEF PROCabort_program PROCkill_all CLS PRINT"Program aborted by user at ";TIME$ *FX229,0 REM enable Escape key again END ENDPROC