--- title: "Eliad Wannum’s BBS" id: 71935 type: "computer_media" slug: "eliad-wannums-bbs" url: "http://localhost/computer_media/eliad-wannums-bbs/" markdown_url: "http://localhost/computer_media/eliad-wannums-bbs.md" published_at: "2026-10-20T14:54:25+00:00" modified_at: "2026-10-20T14:54:25+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/10/EPW_BBS.png" excerpt: "Single-line bulletin board that answers calls through a 2050 modem, with a 40-message base, sysop chat, quick scan, time online and printed call logging." post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "Eliad P. Wannum" slug: "eliad-p-wannum" taxonomy: "indiv" url: "http://localhost/indiv/eliad-p-wannum/" - name: "Paul Holmgren" slug: "paul-holmgren" taxonomy: "indiv" url: "http://localhost/indiv/paul-holmgren/" genre: - name: "BBS" slug: "bbs" taxonomy: "genre" url: "http://localhost/type/bbs/" media_type: "Program" programmers: - name: "Paul Holmgren" slug: "paul-holmgren" taxonomy: "indiv" url: "http://localhost/indiv/paul-holmgren/" - name: "Eliad P. Wannum" slug: "eliad-p-wannum" taxonomy: "indiv" url: "http://localhost/indiv/eliad-p-wannum/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Eliad%20Wannums%20BBS%20%28198x%29%28Holmgren%2C%20Paul%3B%20Wannum%2C%20Eliad%20P.%29%28TS2068%29%28US%29%28Program%29.zip" tsrun_member: "Eliad Wannums BBS (198x)(Holmgren, Paul; Wannum, Eliad P.)(TS2068)(US)(Program)/EPW_BBS.tap" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2026/10/EPW_BBS.png" - url: "http://localhost/wp-content/uploads/2026/10/EPW-BBS.jpg" related_content: - id: 51899 title: "ISTUG-BBS" type: "computer_media" url: "http://localhost/computer_media/istug-bbs/" - id: 64705 title: "BBSes" type: "computer_media" url: "http://localhost/computer_media/bbses/" media_type_tags: "BBS" --- # Eliad Wannum’s BBS Runs a dial-up bulletin board on an unexpanded TS2068 with a 2050 modem and a 2040 printer. Callers see a logon screen and bulletin, give their name, and choose from a menu: Chat, Goodbye, Leave a message, Quick scan, Read a message, Time on, and Users list. The message base holds 40 messages of up to 535 characters each, and it can be saved to and loaded from tape as a `DATA` array. Calls, messages read and left, and chat requests are logged on the printer. Pressing `NOT` on the keyboard gives the sysop an editor for checking and setting the clock, deleting, reading and leaving messages, hanging up and saving the message base. The bulletin credits “Sysop: ELIAD P. WANNUM” and “Mad Programmer: Paul Holmgren,” and the idle screen shows “The E.P.M. BBS” with “© PEH SOFTWARE: 9-27-86”. The program is a customized copy of ISTUG-BBS, reworded and branded for this board. ## Program Analysis ### Program Structure - Line 0: a REM holding machine code for the serial routines, called at `26715` (status), `rcv=26724` (receive a character) and `xmt=26759` (wait until ready to transmit) - Lines 20–120: send newline, send string, beep, and the sysop and carrier check - Lines 130–250: idle screen, wait for a call, answer, and ask the caller about line feeds - Lines 260–360: main menu - Lines 390–870: message header formatting, read, leave and quick scan - Lines 880–1000: chat mode - Lines 1010–1250: logon, bulletin, caller name, users list and hang-up - Lines 1260–1330: clock and time-online formatting - Lines 1340–1510: screen text in `DATA` - Lines 1520–1710: sysop editor - Lines 1820–1940: initialization, optional message-base load, and setting the clock ### Hardware I/O Data goes to the modem on port 115 with `OUT 115`, and port 119 (`mc`) is used for control and status. Before each character is sent the program calls the transmit-ready routine, and every incoming character is read with `CHR$ USR rcv`. Line 90 treats `IN mc<128` as carrier loss and hangs up. The logon screen gives the settings as full duplex, 7-bit words, even parity and one stop bit. ### Message Storage Messages are stored in `m$(41,600)`. Columns 1–32 hold the TO: field, 33–64 hold From: and the caller’s name, and the body starts at column 65. Row 41 holds the 14-character date and time stamp for each message (`d$(y*14-13 TO y*14)`), so the stamps are saved with the array. While a message is being entered, Backspace (code 8) is honored and Ctrl-C (code 3) ends it. ### Notable Techniques - Line numbers are kept in variables (`menu`, `read`, `chat`, `quit`) and used in computed `GO TO` and `GO SUB` statements. - The variable `beep` (60) is both the line of the beep subroutine and the constant 60 in the hour and minute arithmetic. Similarly, `sm` (41) is both a `GO SUB` target that falls through to line 50 and the index of the date row. - The time of day is kept in the `FRAMES` system variable (23672–23674), which the sysop sets by POKEing `(hr*3600+min*60)*60`. - `SGN PI`, `NOT PI` and `VAL "n"` are used for small constants to save memory. - `ON ERR GO TO` traps errors during a call, sends “A bug has Bit you” and returns to the menu. ### Potential Issues - The time display at line 1320 uses `mo`, `dy` and `yr`, which are set only by the editor’s E (establish time) option. The sysop therefore has to set the time before going online, or the routine fails as soon as the idle loop at line 170 calls it. - The sysop delete option (line 1580) does not check that the message number is between 1 and 40. - Lines 900 and 1060 start loops with `FOR x=SGN x`, which works only while `x` already holds a positive value. ## Source Code ``` 0 REM CODE FLASH w NEW O<>CODE FLASH w NEW >=CODE FLASH w NEW ( POKE FLASH sO FLASH w NEW >=CODE FLASH w NEW ( POKE y OPEN #s<>CODE FLASH w NEW >=CODE FLASH w NEW ( POKE <> 10 GO TO VAL "1820" 20 REM send a nl= NEW LINE 30 POKE 23692,255: PRINT : RANDOMIZE USR xmt: OUT 115,nlv: RETURN 40 REM PRINT TO caller 50 GO SUB nl: PRINT p$;: FOR x=SGN PI TO LEN p$: RANDOMIZE USR xmt: OUT 115,CODE p$(x): NEXT x: RETURN 60 REM BEEP 70 FOR x=9 TO 2 STEP -SGN PI: BEEP .2,15: NEXT x: RETURN 80 REM test FOR sysop access 90 IF IN mc<128 THEN GO TO VAL "1250" 100 IF INKEY$="c" OR INKEY$="C" THEN GO TO chat 110 IF INKEY$="NOT " THEN GO TO edit 120 GO TO ret 130 REM CLOSE # modem 140 GO SUB VAL "1770" 150 OUT mc,34: OUT mc,ed 160 REM test FOR IN call 170 GO SUB VAL "1290": PRINT AT 17,27;T$(2): LET ret=VAL "180": GO TO VAL "110" 180 IF IN mc=5 THEN GO TO 170 190 OUT mc,2: OUT mc,34: PAUSE ret 200 REM start/set on LINE time 210 ON ERR GO TO 1250: OUT mc,64: OUT mc,123: OUT mc,55: GO SUB beep: LET temp=hr*beep+min 220 LET nlv=CODE l$: LET p$="Hello"+l$+"Hello, Is this 2 lines Y/N >": GO SUB sm 230 LET c$=CHR$ USR rcv: IF c$="y" OR c$="Y" THEN GO TO VAL "1020" 240 IF c$="n" OR c$="N" THEN LET nlv=10: GO TO VAL "1020" 250 GO TO 230 260 REM menu 270 RESTORE VAL "1350": ON ERR GO TO VAL "1720": GO SUB cls: GO SUB 1160 280 LET p$="(C,G,L,Q,R,T,U)? ": GO SUB sm: LET c$=CHR$ USR rcv: PRINT c$: GO SUB nl 290 IF c$="c" OR c$="C" THEN GO TO chat 300 IF c$="g" OR c$="G" THEN GO TO quit 310 IF c$="l" OR c$="L" THEN GO TO leave 320 IF c$="q" OR c$="Q" THEN GO TO VAL "840" 330 IF c$="r" OR c$="R" THEN GO SUB nl: GO TO read 340 IF c$="t" OR c$="T" THEN GO SUB VAL "1290": GO SUB sm: GO TO VAL "280" 350 IF c$="u" OR c$="U" THEN GO TO VAL "1190" 360 GO TO VAL "280" 370 REM CLS SCREEN$ ,12=FF 380 CLS : OUT 115,12: RETURN 390 REM FORMAT & READ header 400 LET p1=32: LET p2=64: LET c$=m$(y, TO p2): FOR x=5 TO p2 410 IF c$(x)=l$ AND x<=32 THEN LET p1=x: LET x=39 420 IF c$(x)=l$ AND (x>32) AND (x<=64) THEN LET p2=x: LET X=64 430 NEXT x: LET p$="Message :"+STR$ y+" "+d$(y*14-13 TO y*14)+l$+c$( TO p1)+c$(33 TO p2): RETURN 440 REM READ mess 450 LET p$="Message 1 to 40, Menu=0 >? ": GO SUB sm: LET c$=" ": ON ERR GO TO menu 460 FOR x=SGN x TO PI: LET c$(x)=CHR$ USR rcv: IF c$(2)=l$ THEN LET c$=c$(SGN PI): GO TO VAL "500" 470 IF c$(PI)=l$ THEN LET c$=c$( TO 2): GO TO VAL "500" 480 IF (c$(x)<"0") OR (c$(x)>"9") THEN GO TO VAL "450" 490 NEXT x: IF LEN c$>2 THEN GO TO read 500 GO SUB nl: LET y=VAL c$: IF NOT y THEN GO TO menu 510 IF m$(y,1)=" " THEN GO TO VAL "1760" 520 GO SUB 390: LET p$=p$+m$(y,65 TO ) 530 GO SUB cls: PRINT ''"Working": FOR x=SGN PI TO LEN p$: LET c=CODE p$(x): IF c=3 THEN GO TO VAL "560" 540 RANDOMIZE USR xmt: OUT 115,c 550 NEXT x: LET x=x-SGN PI 560 GO SUB nl: PRINT p$( TO x): LPRINT "Read mess. "+STR$ y: GO TO VAL "450" 570 REM con= CONTINUE 580 GO SUB nl: LET p$="Press when ready": GO SUB sm 590 IF CHR$ USR rcv=l$ THEN GO TO ret 600 GO TO VAL "590" 610 REM leave message 620 GO SUB CLS: LET p$="Is this message for Sysop Y/N>": GO SUB sm: LET c$=CHR$ USR rcv: IF c$="y" OR c$="Y" THEN GO TO VAL "1800" 630 GO SUB nl: FOR y=SGN PI TO VAL "40" 640 IF m$(y,1)=" " THEN GO TO VAL "660" 650 NEXT y: GO TO VAL "1740" 660 IF ed THEN GO TO VAL "1670" 670 LPRINT "Left mess. #";y 680 LET p$="Who Gets Mess. "+STR$ y+"?": GO SUB sm: GO SUB nl: LET m$(y)="TO: ": FOR x=5 TO 31 690 LET m$(y,x)=CHR$ USR rcv: IF m$(y,x)=CHR$ 8 THEN LET x=x-SGN PI: GO TO 690 700 IF m$(y,x)=l$ THEN GO TO VAL "720" 710 PRINT m$(y,x);: NEXT x: LET m$(y,x)=l$ 720 LET m$(y,33 TO )="From: "+n$: LET p$="Input Message (535 chars max).. to save...": GO SUB sm: GO SUB nl 730 LET ret=VAL "780": FOR x=CODE "A" TO VAL "600" 740 LET c=USR rcv: IF c=8 THEN LET x=x-SGN x: GO TO VAL "740" 750 IF x<65 THEN GO TO VAL "720" 760 LET m$(y,x)=CHR$ c: PRINT m$(y,x);: IF c=INT PI THEN GO TO VAL "790" 770 GO TO 90 780 NEXT x: LET x=VAL "600" 790 IF ed THEN LET ed=x 800 LET p$="Message"+(" full and" AND x>=600)+" saved.": GO SUB sm: GO SUB 830: IF ed THEN GO TO VAL "1810" 810 GO TO VAL "870" 820 REM FORMAT date/time 830 GO SUB 1290: LET d$(y*14-13 TO y*14)=p$: RETURN 840 REM Quick scan 850 LET ret=VAL "860": FOR y=SGN PI TO 40: IF m$(y,1)<>" " THEN GO SUB 390: GO SUB sm: IF NOT ed THEN GO TO 90 860 NEXT Y: IF ed THEN LET ed=NOT PI: GO TO VAL "1710" 870 LET ret=menu: GO TO con 880 REM chat 890 LET p$="Paging sysop....": GO SUB sm 900 FOR x=SGN x TO VAL "144": IF INKEY$="" THEN PRINT ".";: RANDOMIZE USR xmt: OUT 115,46: BEEP .1,15: NEXT x: LET p$="Sorry, all we found were cobwebs": GO SUB sm: LPRINT "Tried Chat": PAUSE con: GO TO menu 910 GO SUB cls: LET p$=N$+"entering chat mode": GO SUB sm: GO SUB nl: POKE 23658,ed: PRINT '"SYMBL SHIFT/NOT TO LEAVE CHAT" 920 IF INKEY$="NOT " THEN GO TO edit 930 LET rcv1=ed: LET xmt1=ed 940 LET x=USR 26715: LET Xmt1=x AND (x=1 OR x=3): LET Rcv1=x AND (x=2 OR x=3) 950 IF Rcv1 THEN LET c=USR rcv: PRINT CHR$ c;: IF c=CODE l$ THEN PRINT '">"; 960 IF Xmt1 AND INKEY$<>"" THEN GO TO 980 970 GO TO 920 980 IF Xmt1 THEN LET c$=INKEY$: PRINT c$;: OUT 115,CODE c$: FOR x=NOT PI TO PI: NEXT x: IF c$=l$ THEN RANDOMIZE USR xmt: OUT 115,62 990 IF INKEY$<>"" THEN GO TO 990 1000 GO TO 920 1010 REM send logon SCREEN$ 1020 RESTORE VAL "1380": GO SUB cls: GO SUB VAL "1160": LET ret=VAL "1040": GO TO con 1030 REM send bulletin 1040 RESTORE VAL "1410": GO SUB cls: GO SUB VAL "1160" 1050 REM INPUT callers name 1060 LET p$="Who's calling?"+l$: GO SUB sm: LET N$=" ": RANDOMIZE USR xmt: OUT 115,5: GO SUB beep: FOR x=SGN x TO LEN n$ 1070 LET n$(x)=CHR$ USR rcv: IF n$(x)=CHR$ 8 THEN LET x=x-SGN PI: GO TO 1070 1080 IF x": GO SUB sm: LET c$=CHR$ USR rcv 1130 IF c$="n" OR c$="N" THEN GO TO 1060 1140 GO SUB nl: GO SUB 1290: LPRINT N$'p$( TO 14): GO TO menu 1150 REM send SCREEN$ DATA 1160 READ y: LET ret=VAL "1170": FOR y=SGN PI TO y: READ p$: GO SUB sm: GO TO 90 1170 NEXT y: RETURN 1180 REM user LIST 1190 RESTORE VAL "1440": GO SUB cls: GO SUB VAL "1160": LET ret=menu: GO TO con 1200 REM quit bbs 1210 GO SUB cls 1220 RESTORE VAL "1500": GO SUB VAL "1160" 1230 LET C$=CHR$ USR rcv: IF c$="n" OR c$="N" THEN GO TO menu 1240 READ p$: GO SUB sm: GO SUB VAL "1290": GO SUB sm: LPRINT p$'': OUT mc,64: OUT mc,0 1250 OUT mc,0: GO TO VAL "140" 1260 REM timer 1270 LET time=VAL "INT ((PEEK 23672+256*PEEK 23673+65536*PEEK 23674)/3600)": LET hr=INT (time/beep): LET min=INT (time-hr*beep): IF hr>=24 THEN LET hr=NOT PI: LET dy=dy+SGN PI: GO SUB VAL "1910" 1280 RETURN 1290 GO SUB 1270: LET time=INT ((hr*beep+min)-temp) 1300 LET p1=INT (time/beep): LET p2=INT (time-(p1*beep)): IF p1hat","oodby","eave a Message" 1360 DATA "uick Scan messages","ead message","ime on","sers list","" 1370 REM logon DATA 1380 DATA 15," WELCOME TO ELIAD WANNUM's BBS","-------------------------------- ","Settings:","DUPLEX: FULL WORD SIZE: 7","PARITY: EVEN STOP BITS: 1","" 1390 DATA "","We are operating on an unex-","panded Timex 2068, a 2050 modem","and a 2040 printer.","","Tell us what you think about","this BBS","","Open OCCASIONALLY" 1400 REM Bull DATA 1410 DATA 8,"Sysop: ELIAD P. WANNUM","Mad Programmer: Paul Holmgren","","**** >>> -Bullentin- <<< **** " 1420 DATA "","Keep your Modem's warm and stay","tuned to the E.P.M. BBs","" 1430 REM USR DATA 1440 DATA 8,"" 1450 DATA "" 1460 DATA "" 1470 DATA "" 1480 DATA "","If we missed you please Leave","Sysop a mess. and you will be","added to our list." 1490 REM quit DATA 1500 DATA 8,"","The ELIAD P. WANNUM","","Users Group hopes you enjoyed" 1510 DATA "","our little Bulletin Board.","","Are you ready to leave Y/N >","Goodby. Hanging up now" 1520 REM edit 1530 ON ERR RESET 1540 LET p$="Commander Sysop taking Control, Please Stand By": GO SUB sm 1550 CLS : PRINT "SYSOP EDITOR"''"C heck Time"'"D elete a mess."'"E stablish correct time"'"H ang up"'"L eave a mess."'"M ain Menu"'"Q uick Scan Mess."'"R ead Mess."'"S ave messages"''"(C,D,E,H,L,M,Q,R,S)" 1560 POKE VAL "23658",VAL "8": PAUSE ed: LET c$=INKEY$ 1570 IF c$="C" THEN GO SUB VAL "1290": PRINT p$( TO 14): GO TO VAL "1710" 1580 IF c$="D" THEN INPUT "DELETE Mess. #?: ";x: PRINT "Mess. # ";x;" deleted.": LET m$(x)="": GO TO VAL "1710" 1590 IF c$="E" THEN GO SUB VAL "1900" 1600 IF c$="H" THEN GO TO quit 1610 IF c$="L" THEN LET ed=nl: GO TO VAL "630" 1620 IF c$="M" THEN GO TO menu 1630 IF c$="Q" THEN LET ed=nl: GO TO VAL "840" 1640 IF c$="R" THEN INPUT " READ Mess. #?: ";y: CLS : GO SUB VAL "390": PRINT p$'m$(y,CODE "A" TO ): GO TO VAL "1710" 1650 IF c$="S" THEN LET m$(sm)=d$: SAVE "TSBBSmbase" DATA m$() 1660 GO TO VAL "1550" 1670 CLS : LET ed=NOT PI: INPUT " SYMBL SHIFT/NOT TO STOP :"'"Mess. TO ? ";p$: LET m$(y)="To :"+p$+l$: LET m$(y,VAL "33" TO )="From : Sysop ELIAD"+l$: GO SUB VAL "830": GO SUB VAL "390": PRINT P$: LET p$="" 1680 INPUT LINE c$: IF c$="NOT " THEN LET p$=p$+CHR$ PI: GO TO VAL "1700" 1690 LET p$=p$+c$+l$: PRINT c$: IF LEN p$<=VAL "535" THEN GO TO VAL "1680" 1700 LET m$(y,CODE "A" TO )=p$: PRINT 1710 PRINT " NEXT ?": PAUSE ed: GO TO VAL "1550" 1720 REM error trapped messages 1730 ON ERR RESET : LET p$="Sorry "+N$+" A bug has Bit you,": GO SUB sm: GO SUB beep: GO TO menu: REM ?=control G= BEEP 1740 IF ed THEN PRINT "I'm full, delete something first": LET ED=NOT X: GO TO VAL "1710" 1750 LET p$="Message base full right now. Please try later": GO SUB sm: GO TO con 1760 LET ret=read: LET p$="Sorry no message "+STR$ y+". Try again": GO SUB sm: GO SUB nl: GO TO con 1770 REM idle SCREEN$ 1780 CLS : PRINT AT VAL "7",VAL "7";"The E.P.M. BBS";AT VAL "10",VAL "6";"Scanning Phone Line."'''''''"* PEH SOFTWARE: 9-27-86": RETURN 1790 REM LPRINT sysop mess 1800 GO SUB cls: LET y=sm: LET m$(y)="": LET ed=y: GO TO VAL "720" 1810 LPRINT n$;m$(sm,65 TO ed): LET ed=NOT PI: GO TO menu 1820 REM OPEN # 40 mess. base 1830 PAPER NOT PI: BORDER NOT PI: INK VAL "9": CLS 1840 PRINT '" NOT from most modes will GO TO SYSOP edit menu." 1850 LET rcv=VAL "26724": LET xmt=VAL "26759": DIM T$(2,5): LET temp=PI: LET nlv=VAL "13": LET mc=VAL "119" 1860 LET nl=VAL "30": LET sm=VAL "41": LET beep=VAL "60": LET menu=VAL "270": LET cls=VAL "380": LET read=VAL "450": LET con=VAL "580": LET leave=VAL "620": LET chat=VAL "890": LET edit=VAL "1530": LET quit=VAL "1210": LET l$=CHR$ 13: DIM m$(VAL "41",VAL "600"): LET ed=NOT PI 1870 INPUT "Add a Message base? ";p$: IF p$="y" OR p$="Y" THEN PRINT "Start MESSAGE BASE tape.": LOAD "" DATA m$() 1880 LET d$=m$(sm): GO TO edit 1890 REM FORMAT & POKE clock 1900 INPUT "Month 1-12 ";mo,"Day 1-31 ";dy,"Hour 00-23 ";hr,"Minute ";min,"Year 86 ";yr 1910 LET x=VAL "(hr*3600+min*60)*60": LET y=INT (x/65536): POKE 23674,y 1920 LET p1=x-y*65536: LET x=INT (p1/256): POKE 23673,x: POKE 23672,p1-x*256: RETURN 1930 REM SAVE 1940 CLEAR : SAVE "BBS" LINE VAL "1820": GO TO VAL "1820" ```