REM ______________________________________________________ REM Rudolf's library code, for Yogi REM ______________________________________________________ DEF FNrandom_integer(min%,max%) IF min%=max% THEN =min% = min% + RND (max% - min% + 1) - 1 DEF FNdate_time_code LOCAL t$,c$ t$ = TIME$ c$ = MID$ (t$, 5, 2) + MID$ (t$, 8, 3) + MID$ (t$, 14, 2) +"-"+MID$ (t$, 17, 2) + MID$ (t$, 20,2) = c$ REM ======================================================================== DEF FNget_num_param(prompt$, default, min, max) REM ======================================================================== REM Allows default to be outside min-max range LOCAL x%,y%,r$,val PRINTprompt$;" [";default;"]: "; x%=POS:y%=VPOS REPEAT PRINTTAB(x%,y%);SPC(80-x%);TAB(x%,y%); INPUT""r$ IF r$="" THEN =default ELSE val=VAL(r$) UNTIL val>=min AND val<=max =val REM ======================================================================== DEF FNget_str_param(prompt$, default$) REM ======================================================================== LOCAL r$ PRINTprompt$; INPUT""r$ IF r$="" THEN =default$ ELSE =r$ REM ======================================================================== DEF FNask_yes_no(prompt$) REM ======================================================================== REM Returns 1 for yes (rather than -1); 0 for no LOCAL g% PRINTprompt$; REPEAT g%=GET IF g%>=ASC"a" AND g%<=ASC"z" THEN g%-=32 UNTIL g%=ASC"Y" OR g%=ASC"N" VDU g% IF g%=ASC"Y" =1 =0 REM >Arachnid REM Functions to use with Arachnid boxes REM REM Contents: REM FNswitch_number(box%, line%, nboxes%) REM FNswitch_number_2(box%, line%, nboxes%) REM REM PROCsingle_pellet(line%) REM PROCfast_pellet(line%, numpellets%) REM PROCspaced_pellet(line%, numpellets%, timer%, gap%) :REM Unrestricted parameters REM PROCold_spaced_pellet(line%, numpellets%, timer%, gap%) :REM Restricted parameter form REM REM PROCstart_flash_line(line%, timer%, on%, off%) REM PROCstop_flash_line(line%, timer%) REM PROCold_start_flash_line(line%, timer%, on%, off%) REM REM PROCflash_line_number(line%, timer%, on%, off%, count) :REM Unrestricted. REM PROCold_flash_line_number(line%, timer%, on%, off%, count) :REM Restricted. REM REM PROCflash_line_time(line%, timer1%, timer2%, on%, off%, duration%) :REM Unrestricted. REM REM FNfood_mass(pellets%) REM REM *** MULTIPLE PARAMETERS REM Possible, for example: REM PROCpipe_timer(2,200,0,"FNfive_params("+STR$(A)+","+STR$(B)+","+STR$(C)+","+STR$(DOG)+",",ECHIDNA,E%) REM Discovered (and then found in manual, page I-66) after these were written. REM They'd obviously allow a greater range of parameters, REM but these functions work. If it ain't broke... REM REM *** UPDATE: 4 Dec 98 REM Jill found the count=32 limit problematic in PROCflash_line_number. REM The "old_" functions use the single parameter type. REM New versions have been written for unrestricted parameters. REM ======================================================================== DEF FNswitch_number(box%, line%, nboxes%) REM ======================================================================== REM use if boxes are wired REM all houselights/all traylights/... = line%*nboxes% + box% - 1 REM ======================================================================== DEF FNswitch_number_2(box%, line%, nlines%) REM ======================================================================== REM use if boxes are wired REM all box1 wires/all box2 wires/... = (box%-1)*nlines% + line% REM ======================================================================== DEF PROCfast_pellet(line%, numpellets%) REM ======================================================================== REM Dispenses pellets as fast as poss. REM Empirically determined pulse times. REM REM The 'Arachnid' way would be to use timers. REM However, ND found bugs in Arachnid concerned with such timing REM and the 4cs/event delay imposed by a REPEAT...UNTIL mechanism REM doesn't seem to cause problems. LOCAL i%, t% FOR i% = 1 TO numpellets% PROCsingle_pellet(line%) IF i% t%+4 REM don't bother waiting on the last go NEXT ENDPROC REM ======================================================================== DEF PROCspaced_pellet(line%, numpellets%, timer%, gap%) REM ======================================================================== REM Unrestricted parameter version. LOCAL dummy% IF timer%>=256 OR line%>=256 THEN VDU7:PRINT"*** Error: invalid parameters to PROCspaced_pellet" ENDPROC ENDIF dummy%=FNspaced_pellet_2(line%, numpellets%, timer%, gap%, 1) ENDPROC DEF FNspaced_pellet_2(line%, numpellets%, timer%, gap%, R%) IF R%=0 =0 PROCsingle_pellet(line%) IF numpellets%=1 THEN =0 PROCpipe_timer(timer%, gap%, 0, "FNspaced_pellet_2("+STR$(line%)+","+STR$(numpellets%-1)+","+STR$(timer%)+",",gap%,E%) =0 REM ======================================================================== DEF PROCold_spaced_pellet(line%, numpellets%, timer%, gap%) REM ======================================================================== REM Dispenses pellets, with a gap between each pellet. REM Meant to make differences in number of pellets more REM discriminable. (Conditioned reinforcer, too...) IF timer%>=256 OR gap%>=(256*8) OR numpellets%>16 OR line%>=256 THEN VDU7:PRINT"*** Error: invalid parameters to PROCold_spaced_pellet" ENDPROC ENDIF REM allow up to and including 16 pellets, 'cos it takes one off first. PROCsingle_pellet(line%) IF numpellets%=1 THEN ENDPROC REM What we have to do now is to send a few more pellets. REM The receiving function must know at least two of REM (a) timer%, (b) gap%, (c) pellets left to go. REM I choose to implement a recurrent timer, which eliminates REM the need for the receiving function to know gap%. REM Obviously other combinations are possible, but REM I think the best choice, because gap is not restricted to REM byte range while timer% is and I define numpellets% to be. REM (Can't see you wanting to dispense >255 pellets in one go!) REM (Fucking deficient event system, if I may say so.) REM So we have to combine timer% (range 0-255) and pellets_left. REM Can't omit gap%, because then you'd have to use a recurrent timer REM and you can't change their parameters as you go, so you can't REM encode changes in pellets-to-go. So have to set a new timer each REM time, so need to know gap%. REM Can't omit timer%, because either you use a recurrent timer REM and then have to kill it by number, or you re-pipe the timer REM and have to use its number then. REM Can't omit pellets-to-go, because you can't set a timer for a finite REM number of cycles and I don't want to use multiple timer numbers for REM a single pellet dispenser. REM And, by the way, need line%. REM Therefore have to encode all four. timer% is 0-255. line% is 0-255. REM BASIC only allows integers to be 256*256*256*128-1. REM So we're left with 256*128 for gap and numpellets. REM Either 20s/8 pellets, 10s/16 pellets, 5s/32 pellets... REM I choose 20s, 16 pellets. That's 256*8. REM Actually, 15 pellets. REM Recursive code. LOCAL parm% parm% = timer% + line%*256 + gap%*256*256 + (numpellets%-1)*256*256*256*8 PROCpipe_timer(timer%,gap%,0,"FNold_spaced_pellet_2(",parm%,R%) ENDPROC DEF FNold_spaced_pellet_2(parm%,R%) IF R%=0 =0 LOCAL timer%, numpellets%, gap%, line% timer% = parm% MOD 256 line% = (parm% DIV 256) MOD 256 gap% = (parm% DIV (256*256)) MOD (256*8) numpellets% = parm% DIV (256*256*256*8) PROCsingle_pellet(line%) IF numpellets%=1 THEN =0 parm% = timer% + line%*256 + gap%*256*256 + (numpellets%-1)*256*256*256*8 PROCpipe_timer(timer%,gap%,0,"FNold_spaced_pellet_2(",parm%,R%) =0 REM ======================================================================== DEF PROCsingle_pellet(line%) REM ======================================================================== REM plips out a pellet, doesn't wait afterwards REM Empirically determined pulse time. LOCAL t% t% = TIME PROCswitch_on(line%, E%) REPEAT UNTIL TIME > t% + 4 PROCswitch_off(line%, E%) ENDPROC REM ======================================================================== DEF PROCstart_flash_line(line%, timer%, on%, off%) REM ======================================================================== REM Unrestricted version. LOCAL dummy% IF line%>=256 OR timer%>=256 OR on%=0 OR off%=0 THEN VDU7:PRINT"Invalid parameters to PROCstart_flash_line" ENDPROC ENDIF dummy%=FNflash_line_2on(line%, timer%, on%, off%, 1) ENDPROC DEF FNflash_line_2off(line%, timer%, on%, off%, R%) IF R%=0 =0 PROCswitch_off(line%, E%) PROCpipe_timer(timer%, off%, 0, "FNflash_line_2on("+STR$(line%)+","+STR$(timer%)+","+STR$(on%)+",",off%,E%) =0 DEF FNflash_line_2on(line%, timer%, on%, off%, R%) IF R%=0 =0 PROCswitch_on(line%, E%) PROCpipe_timer(timer%, on%, 0, "FNflash_line_2off("+STR$(line%)+","+STR$(timer%)+","+STR$(on%)+",",off%,E%) =0 REM ======================================================================== DEF PROCold_start_flash_line(line%, timer%, on%, off%) REM ======================================================================== REM *** Use: sets the line flashing, using timer%. REM To stop, use PROCstop_flash_line with the same timer number. REM Typically, calling program would set a second timer for this. REM *** Restriction: although it accepts times in cs, this REM function has a temporal resolution of 10cs. REM This is to allow the passing of four parameters through Arachnid. REM *** Restriction: only allows pulse times of up to 1280cs, REM for the same reason on% = on% DIV 10 off% = off% DIV 10 IF line%>=256 OR on%>=128 OR off%>=128 OR timer%>=256 OR on%=0 OR off%=0 THEN VDU7:PRINT"Invalid parameters to PROCold_start_flash_line" ENDPROC ENDIF LOCAL parm% parm% = line% + timer%*256 + on%*256*256 + off%*256*256*128 PROCswitch_on(line%, E%) PROCpipe_timer(timer%, on%*10, 0, "FNold_flash_line_2off(", parm%, E%) ENDPROC DEF FNold_flash_line_2off(parm%, R%) IF R%=0 =0 LOCAL line%,timer%,on%,off% line% = parm% MOD 256 timer% = (parm% DIV 256) MOD 256 on% = (parm% DIV (256*256)) MOD 128 off% = parm% DIV (256*256*128) PROCswitch_off(line%,E%) PROCpipe_timer(timer%, off%*10, 0, "FNold_flash_line_2on(", parm%, E%) =0 DEF FNold_flash_line_2on(parm%, R%) IF R%=0 =0 LOCAL line%,timer%,on%,off% line% = parm% MOD 256 timer% = (parm% DIV 256) MOD 256 on% = (parm% DIV (256*256)) MOD 128 off% = parm% DIV (256*256*128) PROCswitch_on(line%,E%) PROCpipe_timer(timer%, on%*10, 0, "FNold_flash_line_2off(", parm%, E%) =0 REM ======================================================================== DEF PROCstop_flash_line(line%, timer%) REM ======================================================================== PROCkill_timer(timer%,E%) PROCswitch_off(line%,E%) ENDPROC REM ======================================================================== DEF PROCflash_line_number(line%, timer%, on%, off%, count%) REM ======================================================================== REM Unrestricted version. REM You can abort it cleanly using PROCstop_flash_line if necessary. LOCAL dummy% IF line%>=256 OR timer%>=256 OR on%=0 OR off%=0 OR count%=0 THEN VDU7:PRINT"*** Invalid parameters to PROCflash_line_number" ENDPROC ENDIF dummy%=FNflash_line_number_2on(line%, timer%, on%, off%, count%, 1) ENDPROC DEF FNflash_line_number_2on(line%, timer%, on%, off%, count%, R%) IF R%=0 =0 PROCswitch_on(line%, E%) REM counter decrement occurs here: PROCpipe_timer(timer%, on%, 0, "FNflash_line_number_2off("+STR$(line%)+","+STR$(timer%)+","+STR$(on%)+","+STR$(off%)+",",count%-1,E%) =0 DEF FNflash_line_number_2off(line%, timer%, on%, off%, count%, R%) IF R%=0 =0 PROCswitch_off(line%, E%) IF count%=0 =0 :REM endpoint PROCpipe_timer(timer%, off%, 0, "FNflash_line_number_2on("+STR$(line%)+","+STR$(timer%)+","+STR$(on%)+","+STR$(off%)+",",count%,E%) =0 REM ======================================================================== DEF PROCold_flash_line_number(line%, timer%, on%, off%, count%) REM ======================================================================== REM *** If you need to, can use PROCstop_flash_line to abort early. REM *** Restriction: although it accepts times in cs, this REM function has a temporal resolution of 10cs. REM This is to allow the passing of four parameters through Arachnid. REM Takes 8 bits for line, 8 for timer, leaves 15 for on/off/count. REM Count must be odd#, so 5 (up to 32) rather than 3 (up to 8). REM Thus 5 bits each for on/off (up to 32), so 3.2 sec max. on% = on% DIV 10 off% = off% DIV 10 IF line%>=256 OR timer%>=256 OR on%>=32 OR off%>=32 OR count%>32 OR count%=0 THEN VDU7:PRINT"*** Invalid parameters to PROCold_flash_line_number" ENDPROC ENDIF LOCAL parm% parm% = line% + timer%*256 + on%*256*256 + off%*256*256*32 + (count%-1)*256*256*32*32 PROCswitch_on(line%,E%) PROCpipe_timer(timer%, on%*10, 0, "FNold_flash_line_number_2off(", parm%, E%) ENDPROC DEF FNold_flash_line_number_2off(parm%, R%) IF R%=0 =0 LOCAL line%, timer%, count%, on%, off% line% = parm% MOD 256 timer% = (parm% DIV 256) MOD 256 on% = (parm% DIV (256*256)) MOD 32 off% = (parm% DIV (256*256*32)) MOD 32 count% = (parm% DIV (256*256*32*32)) PROCswitch_off(line%,E%) IF count%=0 =0 :REM that's the endpoint PROCpipe_timer(timer%, off%*10, 0, "FNold_flash_line_number_2on(", parm%, E%) =0 DEF FNold_flash_line_number_2on(parm%, R%) IF R%=0 =0 LOCAL line%, timer%, count%, on%, off% line% = parm% MOD 256 timer% = (parm% DIV 256) MOD 256 on% = (parm% DIV (256*256)) MOD 32 off% = (parm% DIV (256*256*32)) MOD 32 count% = (parm% DIV (256*256*32*32)) PROCswitch_on(line%,E%) parm% = line% + timer%*256 + on%*256*256 + off%*256*256*32 + (count%-1)*256*256*32*32 PROCpipe_timer(timer%, on%*10, 0, "FNold_flash_line_number_2off(", parm%, E%) =0 REM ======================================================================== DEF FNfood_mass(pellets%) REM ======================================================================== = pellets%*45/1000 REM a pellet is 45 mg REM ======================================================================== DEF PROCflash_line_time(line%, timer1%, timer2%, on%, off%, duration%) REM ======================================================================== REM calls the other flashing functions to provide the final, most REM useful interface to the flashing code. REM Uses the unrestricted (multiple parameter) versions. IF timer1%=timer2% THEN VDU7:PRINT"*** PROCflash_line_time requires two unique timers" ENDPROC ENDIF REM Other error-checking performed by the sub-functions. PROCstart_flash_line(line%, timer1%, on%, off%) PROCpipe_timer(timer2%, duration%, 0, "FNflash_line_time2("+STR$(line%)+",",timer1%,E%) ENDPROC DEF FNflash_line_time2(line%, timer%, R%) IF R%=0 =0 PROCstop_flash_line(line%, timer%) =0 REM >Filename REM Library of functions to do with simple file handling REM ======================================================================== DEF FNget_filename(prompt$) REM ======================================================================== LOCAL filename$ REPEAT PRINTprompt$; INPUT filename$ UNTIL FNfilename_valid(filename$)=1 =filename$ REM ======================================================================== DEF FNget_filename_default(prompt$,default$) REM ======================================================================== REM Requires UI library. LOCAL filename$ REPEAT filename$ = FNget_str_param(prompt$, default$) UNTIL FNfilename_valid(filename$)=1 =filename$ DEF FNfilename_valid(filename$) LOCAL X,Y IF LEN(filename$)=0 THEN =0 IF LEN(filename$)>8 THEN PRINT "- 8 character maximum for ADFS->PC floppies, I'm afraid." REM I've had a nasty incident with this already and don't want another. =0 ENDIF IF INSTR(filename$," ") <> 0 THEN PRINT "- Dozy today? I said no spaces." =0 ENDIF X = OPENIN(filename$) IF X <> 0 THEN CLOSE#X:PRINT "- File exists, choose another." =0 ENDIF LOCAL Y Y = OPENOUT(filename$) IF Y=0 THEN =0 CLOSE#Y:OSCLI("DELETE "+filename$) REM A bad filename will crash the program, but never mind, REM it's not a crucial stage. Professional programming REM requires an ON ERROR statement. Oh well. REM 29-Jan-99: deleted the file (fed up with clearing up after REM programs that use this function and then are aborted). =1 REM >Ascii REM Library of routines to "print" ASCII to a file REM ======================================================================== DEF PROCprint_line(channel%, string$) REM ======================================================================== PROCprint_string(channel%, string$) BPUT #channel%, 13 :REM finish with a new line. BPUT #channel%, 10 :REM PCs use CR, LF ENDPROC REM ======================================================================== DEF PROCprint_string(channel%, string$) REM ======================================================================== LOCAL i% IF LEN(string$)=0 THEN ENDPROC FOR i%=1 TO LEN(string$) BPUT #channel%, ASC(MID$(string$,i%,1)) NEXT ENDPROC REM ======================================================================== DEF PROCprint_string_visibly(channel%, string$) REM ======================================================================== PROCprint_string(channel%, string$) PRINT string$; ENDPROC REM ======================================================================== DEF PROCprint_line_visibly(channel%, string$) REM ======================================================================== PROCprint_line(channel%, string$) PRINT string$ ENDPROC