Tinyboard

Products: TINYBOARD
Developer(s): Lucy Gordon, Randy Gordon
Date: 1986
Type: Program
Platform(s):

A bulletin board system for the Timex/Sinclair 2068 and the Timex/Westridge 2050 modem. T/S Tinyboard waits in auto-answer mode, picks up the line when it rings, and asks the caller for a full name. Callers get a menu to Read messages, Leave a message (up to 900 characters, ended with CTRL-C), page the sysop for Chat, see their connect Time, or say Goodbye. The message base holds 20 messages of up to 1,000 characters, and each caller’s name is sent to the printer.

At start-up the program asks whether to load a saved message base and a logon bulletin from tape. Pressing NOT (SYMBOL SHIFT-S) from most modes drops into a sysop editor, which can read, delete and write messages and save the message base to tape. Chat mode is a two-way terminal between sysop and caller.

The REM and title screen read “T/S Tinyboard by FLASHWARE © 1986, Randy/Lucy Gordon, Timex-Sinclair Users Group of Cincinnati, Oh.”, with a revision date of 01/21/86. The T/S Tinyboard BBS article gives the authors’ notes, credits the auto-answer routine to Randy Kuhn, and prints a later revision by Mark Fisher of CATS.

Program Analysis

Structure

  • Lines 1000–1090: auto-answer, waiting on IN 119 and taking the line with OUT 119,2 and OUT 119,34.
  • Lines 2000–2070: set up the modem’s USART, zero the frame counter as an online timer, send the logon bulletin, ask for the caller’s name and run the main menu.
  • Lines 3000–3040 read messages, 4000–4070 leave one, 5000–5130 hang up and go back to auto-answer, 7000–7162 chat, 8500–8599 the sysop editor.
  • Lines 9000–9540: initialise, load the optional message base and bulletin, name every routine and POKE three machine-code routines.

Machine Code

Three short routines are POKEd from DATA: a status read at 65000 (IN port 119, bits 0–1), a receive routine at 65100 that waits for a character on port 115 and echoes it back, and a send-ready wait at 65200. All three return early if bit 7 of port 119 shows the carrier has gone. BASIC then sends each character with RANDOMIZE USR output: OUT 115,code.

Notable Techniques

  • Every routine has a named line-number variable (LET read=3000, LET quit=5000 and so on), so the program reads GO TO read and GO SUB logonbull.
  • ON ERR GO TO quit around every input means a dropped call or line noise sends the board back to auto-answer.
  • Connect time comes from the system frame counter (23672–23674), divided by 60.

Potential Issues

  • If every message is deleted, the read loop at line 3015 searches forever for a non-blank message.
  • The name input at line 8010 writes u$(u) with no upper limit, so a name longer than 32 characters causes an error, which the ON ERR treats as a hang-up.

Related Products

Bulletin board software, written by Randy and Lucy Gordon. The original Tinyboard BBS software program provided the ability of an unexpanded TS 2068 to serve as a host system.

Related Articles

T/S TINYBOARD was begun as an experiment in how the MODEM works. The first step in the beginning was to find out about the hardware inside the Westridge MODEM.

Related Content

Image Gallery

Source Code

    1 REM  T/S Tinyboard by                FLASHWARE \* 1986      Randy/Lucy Gordon Timex-SinclairUsers Group of Cincinnati, Oh.  
   10 GO TO 9000
 1000 REM autoans
 1001 OUT 119,34
 1002 OUT 119,0
 1010 REM ansloop
 1015 LET a=IN 119
 1016 IF CODE INKEY$=195 THEN GO TO edit
 1020 IF a=5 THEN GO TO ansloop
 1066 FOR x=1 TO 5: BEEP .1,40: NEXT x
 1070 OUT 119,2
 1080 OUT 119,34
 1090 PAUSE 300
 2000 REM warmstart
 2001 FOR x=1 TO 3: BEEP .1,x: NEXT x: OUT 119,64: OUT 119,123: OUT 119,55: POKE 23674,0: POKE 23673,0: POKE 23672,0: REM set online timer
 2002 REM menu
 2003 PAUSE 120: CLS : GO SUB logonbull: LET x=IN 115: LET p$="Full name: ": FOR x=1 TO LEN p$: RANDOMIZE USR output: OUT 115,CODE p$(x): PRINT p$(x);: NEXT x: GO SUB inname: LPRINT u$
 2004 LET y=0: REM set message number to read
 2005 REM inputcom
 2006 RESTORE 2007
 2007 DATA "T/S TINYBOARD MAIN MENU","<R>ead messages","<L>eave message","<C>hat mode","<T>ime on","<G>oodbye"," ","Choice?:"
 2008 RANDOMIZE USR output: OUT 115,13: PRINT 
 2020 FOR p=1 TO 8: PRINT : RANDOMIZE USR output: OUT 115,13: READ p$: FOR x=1 TO LEN p$: POKE 23692,255: PRINT p$(x);: RANDOMIZE USR output: OUT 115,CODE p$(x): NEXT x
 2035 NEXT p
 2036 ON ERR GO TO quit: LET c$=CHR$ USR input: PRINT c$: PRINT 
 2040 IF c$="r" OR c$="R" THEN FOR x=1 TO 2: RANDOMIZE USR output: OUT 115,13: NEXT x: GO TO read
 2041 IF c$="t" OR c$="T" THEN GO SUB timer: LET p$="Connect time ": LET p$=p$+x$: RANDOMIZE USR output: OUT 115,13: PRINT : FOR x=1 TO LEN p$: PRINT p$(x);: RANDOMIZE USR output: OUT 115,CODE p$(x): NEXT x: GO TO 2006
 2045 IF c$="c" OR c$="C" THEN GO TO chat
 2047 IF c$="g" OR c$="G" THEN PAUSE 30: GO TO quit
 2050 IF c$="l" OR c$="L" THEN GO TO leave
 2070 GO TO inputcom
 3000 REM read messages
 3015 LET y=y+1: IF y>20 THEN LET y=1
 3018 IF m$(y,1)=" " THEN GO TO read
 3019 PRINT AT 21,0;"                                ": PRINT AT 21,0;y: LET c$=SCREEN$ (21,0): LET c$=c$+SCREEN$ (21,1): LET p$="MESSAGE NUMBER: "+c$: RANDOMIZE USR output: OUT 115,13: FOR x=1 TO LEN p$: RANDOMIZE USR output: OUT 115,CODE p$(x): PRINT p$(x);: NEXT x: PRINT : RANDOMIZE USR output: OUT 115,13
 3024 FOR v=1 TO 1000: POKE 23692,255
 3025 IF CODE m$(y,v)=3 THEN LET v=1000: NEXT v: GO TO inputcom
 3030 PRINT m$(y,v);: RANDOMIZE USR output: OUT 115,CODE m$(y,v)
 3031 IF v>64 THEN NEXT v
 3032 IF (v>32 AND CODE m$(y,v)=13) THEN LET v=64: RANDOMIZE USR output: OUT 115,13
 3033 IF (v<32 AND CODE m$(y,v)=13) THEN LET v=32
 3035 NEXT v
 3036 RANDOMIZE USR output: OUT 115,13: PRINT 
 3040 GO TO inputcom
 4000 REM leave message
 4010 LET y1=y1+1: IF y1>20 THEN LET y1=1
 4011 DIM l$(1000): LET m$(y1)=l$
 4012 RANDOMIZE USR output: OUT 115,13: LET p$="Who gets message?: ": FOR x=1 TO LEN p$: RANDOMIZE USR output: OUT 115,CODE p$(x): PRINT p$(x);: NEXT x: ON ERR GO TO quit: LET m$(y1,1 TO 4)="TO: ": FOR x=5 TO 32: LET m$(y1,x)=CHR$ USR input: PRINT m$(y1,x);
 4013 IF CODE m$(y1,x)=13 THEN LET x=32
 4014 NEXT x
 4015 LET m$(y1,33 TO 38)="FROM: ": LET m$(y1,39 TO 64)=u$
 4018 RANDOMIZE USR output: OUT 115,13: PRINT : LET p$="Input message (900 chars max)..<CTRL C> to save...": PRINT : RANDOMIZE USR output: OUT 115,13
 4019 FOR x=1 TO LEN p$: RANDOMIZE USR output: OUT 115,CODE p$(x): PRINT p$(x);: NEXT x: FOR x=1 TO 2: RANDOMIZE USR output: OUT 115,13: PRINT : NEXT x
 4020 ON ERR GO TO quit: FOR v=65 TO 1000: POKE 23692,255: LET m1=USR input: REM ctrl C=03h=ETX
 4050 LET m$(y1,v)=CHR$ m1: PRINT m$(y1,v);: IF m1=3 THEN LET v=1000: NEXT v: GO TO inputcom
 4055 NEXT v
 4070 GO TO inputcom
 5000 REM quit message base
 5001 ON ERR RESET 
 5100 RANDOMIZE USR output: OUT 115,13
 5105 CLS : PAUSE 10
 5110 LET p$="Thank you for calling the       T/S TINYBOARD....               Hang up now!!!"
 5115 PAUSE 30: CLS : RANDOMIZE USR output: OUT 115,28: RANDOMIZE USR output: OUT 115,31
 5120 FOR x=1 TO LEN p$: RANDOMIZE USR output: OUT 115,CODE p$(x): PRINT p$(x);: NEXT x
 5121 PAUSE 120
 5125 OUT 119,64: OUT 119,0: OUT 119,0
 5130 PAUSE 60: CLS : FOR x=60 TO 1 STEP -5: BEEP .1,x: NEXT x: GO TO autoans
 6000 REM logonbull
 6001 PAUSE 30: FOR x=1 TO 30: RANDOMIZE USR output: OUT 115,0: NEXT x
 6002 IF IN 119<128 THEN GO TO quit
 6005 RANDOMIZE USR output: OUT 115,28: RANDOMIZE USR output: OUT 115,31
 6008 RANDOMIZE USR 65200: OUT 115,28
 6010 FOR x=1 TO 10: RANDOMIZE USR 65200: OUT 115,13: PRINT : NEXT x
 6020 FOR x=1 TO LEN t$: POKE 23692,255: PRINT t$(x);: RANDOMIZE USR 65200: OUT 115,CODE t$(x): NEXT x
 6030 FOR x=1 TO 5: RANDOMIZE USR 65200: OUT 115,13: PRINT : NEXT x
 6040 RETURN 
 7000 REM chat
 7001 ON ERR GO TO quit
 7005 PRINT : RANDOMIZE USR 65200: OUT 115,13: LET p$="Paging sysop...................": FOR x=1 TO 10: BEEP .1,1: NEXT x: FOR x=1 TO LEN p$: POKE 23692,255: PRINT p$(x);: RANDOMIZE USR 65200: OUT 115,CODE p$(x): NEXT x: PRINT : RANDOMIZE USR 65200: OUT 115,13
 7006 FOR x=1 TO 128: IF INKEY$="" THEN PRINT ".";: RANDOMIZE USR 65200: OUT 115,46: BEEP .1,10: NEXT x: LET p$="The sysop is not available.....": FOR x=1 TO 10: BEEP .1,1: NEXT x: FOR x=1 TO LEN p$: POKE 23692,255: PRINT p$(x);: RANDOMIZE USR 65200: OUT 115,CODE p$(x): NEXT x: PRINT : RANDOMIZE USR 65200: OUT 115,13: GO TO inputcom
 7008 RANDOMIZE USR 65200: OUT 115,13: LET p$="You are now in chat mode:": FOR x=1 TO 10: BEEP .1,1: NEXT x: FOR x=1 TO LEN p$: POKE 23692,255: PRINT p$(x);: RANDOMIZE USR 65200: OUT 115,CODE p$(x): NEXT x: PRINT : RANDOMIZE USR 65200: OUT 115,13
 7009 CLS : PRINT "You are in chat mode with       ";u$: PRINT : PRINT "SYMBL SHIFT/NOT to escape..."
 7010 IF CODE INKEY$=195 THEN GO TO inputcom: REM 195=NOT
 7011 POKE 23692,255
 7020 LET RxRDY=0: LET TxRDY=0
 7100 LET a=USR 65000: LET TxRDY=1 AND (a=1 OR a=3): LET RxRDY=1 AND (a=2 OR a=3)
 7130 IF RxRDY THEN LET k=USR 65100: PRINT CHR$ k;: IF k=13 THEN PRINT ">";
 7140 IF TxRDY AND INKEY$<>"" THEN GO SUB 7160
 7150 GO TO 7010
 7160 IF TxRDY THEN LET i$=INKEY$: PRINT i$;: OUT 115,CODE i$: FOR x=1 TO 5: NEXT x: IF CODE i$=13 THEN PRINT ">";
 7161 IF INKEY$<>"" THEN GO TO 7161
 7162 RETURN 
 8000 REM inname
 8001 DIM u$(32): LET u=1
 8002 RANDOMIZE USR output: OUT 115,5
 8005 ON ERR GO TO quit: LET v$=CHR$ USR input: PRINT v$;
 8010 LET u$(u)=v$ AND u<32: LET u=u+1
 8011 IF CODE v$=13 THEN RETURN 
 8100 GO TO 8005
 8500 REM edit
 8510 PRINT AT 0,0;"SYSOP EDITOR";AT 2,0;"<R>ead messages";AT 4,0;"<D>elete messages";AT 6,0;"<L>eave messages";AT 8,0;"<Q>uit editor";AT 10,0;"<S>ave message base"
 8520 LET i$=INKEY$
 8525 IF i$="" THEN GO TO 8520
 8526 IF i$="s" OR i$="S" THEN GO TO 9999
 8530 IF i$="r" OR i$="R" THEN INPUT ;"message #?: ";x: PRINT "Message # ";x: PRINT m$(x): PAUSE 0: GO TO edit
 8540 IF i$="d" OR i$="D" THEN INPUT ;"message #?: ";x: PRINT "Message # ";x;" deleted.": LET m$(x)=l$: PAUSE 0: GO TO edit
 8550 IF i$="l" OR i$="L" THEN LET y1=y1+1: PRINT "Message # ";y1: PRINT : FOR x=1 TO 1000: PAUSE 0: LET m$(y1,x)=INKEY$: PRINT m$(y1,x);
 8554 IF i$="l" OR i$="L" THEN IF CODE INKEY$=195 THEN LET m$(y1,x)=CHR$ 3: GO TO edit: REM 195=NOT
 8560 IF i$="l" OR i$="L" THEN NEXT x: PAUSE 0: GO TO edit
 8570 IF i$="q" OR i$="Q" THEN GO TO quit
 8599 CLS : GO TO edit
 9000 REM init
 9001 REM 20 meesage base
 9004 PAPER 0: BORDER 0: INK 7: CLS 
 9005 CLEAR 64999: GO SUB 9500
 9006 DIM y(1,1): LET y1=0: DIM l$(1000): DIM m$(20,1000): LET m$(1)="No messages found..."+CHR$ 3: FOR x=1 TO 3: BEEP .1,25: NEXT x: PRINT "Do you wish to load a message   base?": INPUT x$: IF x$="y" OR x$="Y" THEN PRINT "Start MESSAGE BASE tape...      ( 2 Part LOAD... )": LOAD "" DATA m$(): LOAD "" DATA y(): LET y1=y(1,1)
 9007 LET t$="T/S Tinyboard                   FLASHWARE <c> 1985": FOR x=1 TO 3: BEEP .1,25: NEXT x: PRINT "Do you wish to load a logon     bulletin?": INPUT x$: IF x$="y" OR x$="Y" THEN PRINT "Start LOGON BULLETIN tape...    ( with data as t$ )": LOAD "" DATA t$()
 9008 PRINT : PRINT "<NOT> from most modes will exit to SYSOP control mode.": BEEP .1,35: BEEP .1,35: PAUSE 180
 9009 LET y=0: LET edit=8500: LET timer=9990
 9010 LET chat=7000: LET menu=2002: LET warmstart=2000: LET logonbull=6000: LET statchk=65000: LET input=65100: LET output=65200: LET ansloop=1010: LET inputcom=2005: LET autoans=1000: LET read=3000: LET leave=4000: LET quit=5000
 9011 LET inname=8000
 9012 PRINT "Now going to AUTOANSWER MODE": FOR x=1 TO 3: BEEP .1,10: NEXT x: PAUSE 180: CLS 
 9100 GO TO quit
 9500 REM code
 9510 RESTORE 9515: FOR x=65000 TO 65008: READ x1: POKE x,x1: NEXT x
 9515 DATA 175,219,119,230,3,79,6,0,201
 9520 RESTORE 9525: FOR x=65100 TO 65132: READ x1: POKE x,x1: NEXT x
 9525 DATA 219,119,230,128,200,175,219,119,230,2,40,244,219,115,6,0,79,219,119,230,128,200,175,219,119,230,1,40,244,121,211,115,201
 9530 RESTORE 9535: FOR x=65200 TO 65212: READ x1: POKE x,x1: NEXT x
 9535 DATA 219,119,230,128,200,175,219,119,230,1,40,244,201
 9540 RETURN 
 9990 REM timer
 9992 DIM x$(5): LET time=INT ((PEEK 23672+256*PEEK 23673+256*256*PEEK 23674)/60): LET hr=INT (time/60/60): LET min=INT ((time-(hr*60*60))/60): PRINT AT 21,0;"0" AND hr<10;hr;":";"0" AND min<10;min: FOR x=1 TO 5: LET x$(x)=SCREEN$ (21,x-1): NEXT x
 9993 RETURN 
 9995 INK 7: BORDER 0: PAPER 0: CLS : PRINT AT 3,10;"T/S Tinyboard";AT 14,8;"FLASHWARE \* 1986": CIRCLE 123,110,20: PLOT 127,133: DRAW 20,0: DRAW -5,-20: DRAW -15,0: DRAW -5,-10: DRAW -8,0: DRAW -6,-17: DRAW 0,23: DRAW 6,0: DRAW 4,9: DRAW 6,0: DRAW 2,15: BEEP .2,10: BEEP .2,5: BEEP .2,2: PAUSE 4: BEEP .2,10: BEEP .2,5: BEEP .2,2: PAUSE 8: BEEP .2,10: BEEP .2,5: BEEP .2,2: BEEP .2,5: BEEP .2,10: BEEP .2,10
 9996 GO TO 10
 9997 SAVE "tinyboard" LINE 9995: REM  T/S Tinyboard/Flashware \* 1986 rev. date 01/21/86
 9998 STOP 
 9999 SAVE "messbase" DATA m$(): LET y(1,1)=y1: SAVE "msgcntr" DATA y(): GO TO edit

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.