aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO3
-rw-r--r--config/Makefile10
-rw-r--r--config/config.c23
-rw-r--r--doc/dynamic-screens.txt391
-rw-r--r--src/cmd.c37
-rw-r--r--src/irc.c40
-rw-r--r--src/irc.h3
-rw-r--r--src/main.c6
-rw-r--r--src/nio.c265
-rw-r--r--src/nio.h51
-rw-r--r--src/screen.c10
-rw-r--r--src/screen.h8
-rw-r--r--src/sio.s16
13 files changed, 554 insertions, 309 deletions
diff --git a/TODO b/TODO
index 179fc21..7f84dc2 100644
--- a/TODO
+++ b/TODO
@@ -17,6 +17,9 @@ X Configurable ctcp version response. Not going to do for now. Having
Other stuff:
+- [*] highlight status should not get overwritten with chan text
+ status the next time someone speaks. in general, higher statuses
+ shouldn't get downgraded.
- [*] edit box issues with the 240th character. currently everything seems
to work properly, but you can't type 240 chars (only 239). out of
patience for it right now...
diff --git a/config/Makefile b/config/Makefile
index 6518ea7..15567e9 100644
--- a/config/Makefile
+++ b/config/Makefile
@@ -3,11 +3,7 @@ all: config.xex
#config.xex: config.c exetrailer.s ../src/config.h ../src/config.c
config.xex:
- cl65 -DVERSION='"$(VERSION)"' -Oris -t atari -C ../src/atari.cfg -o config.xex config.c ../src/exehdr.s exetrailer.s ../src/config.c
+ cl65 -DVERSION='"$(VERSION)"' -m config.map -Oris -t atari -C ../src/atari.cfg -o config.xex config.c os2ram.c ../src/exehdr.s exetrailer.s ../src/config.c
-test:
- cl65 -Oris -t atari -C ../src/atari.cfg -o config.xex config.c exetrailer.s ../src/config.c
- cl65 -Oris -t atari -C ../src/atari.cfg -o conftest.xex conftest.c
- cat config.xex conftest.xex > autorun.sys
- cp dos25_sd.atr test.atr
- axe -w autorun.sys test.atr
+clean:
+ rm -f config.xex
diff --git a/config/config.c b/config/config.c
index bd9c1a6..8d09e8e 100644
--- a/config/config.c
+++ b/config/config.c
@@ -10,6 +10,7 @@
#include <peekpoke.h>
#include "../src/config.h"
+#include "os2ram.h"
#ifndef VERSION
#define VERSION "?????"
@@ -44,8 +45,9 @@ char buf[128];
char numbuf[4];
char server[101];
char port[6];
+char use_xl_ram = 1;
-unsigned int *bonus_addrs = 0xf0;
+unsigned int *bonus_addrs = (unsigned int *)0xd4; /* aka FR0 */
char lcgetc(void) {
char c;
@@ -522,6 +524,20 @@ void prompt_server() {
}
}
+void detect_xl(void) {
+ if(!is_xl()) {
+ print("400/800 detected, no extra RAM\n");
+ use_xl_ram = 0;
+ return;
+ }
+
+ use_xl_ram = yn("XL/XE detected, use extra RAM", use_xl_ram);
+ if(!use_xl_ram) return;
+
+ os_to_ram();
+}
+
+
void set_default_config(void) {
memcpy(conf, &defaults, sizeof(conf_t));
}
@@ -536,6 +552,9 @@ void main(void) {
/* loading1.xex left the original DL address at $fe */
if(PEEKW(0xfe)) POKEW(0x0230, PEEKW(0xfe));
+ /* clear the bonus screen addresses in case something left junk there */
+ memset(bonus_addrs, 0, 14);
+
set_default_config();
OS.color2 = conf->colors[0];
@@ -546,6 +565,8 @@ void main(void) {
print("Version " VERSION "\n\n");
detect_dos();
+ // detect_xl(); // not yet
+
if(!load(0))
print("Using built-in default config.\n");
diff --git a/doc/dynamic-screens.txt b/doc/dynamic-screens.txt
new file mode 100644
index 0000000..fada83e
--- /dev/null
+++ b/doc/dynamic-screens.txt
@@ -0,0 +1,391 @@
+Dynamic screen memory for FujiNetChat
+-------------------------------------
+
+This *doesn't exist* yet, even if I speak of it in the present tense
+in this document!
+
+Goals:
+
+- Maximize use of available memory for scrollback. This means variable
+ sized screens, not fixed to a given address (though they *will* be
+ fixed to a given bank in extended RAM).
+
+- Support at least 15 screens. Maybe more. There will be *some* limit,
+ anyway.
+
+- Don't waste memory: if you only use a few screens, you shouldn't have
+ a bunch of memory reserved for the screens you don't use. You'll only
+ pay for what you use.
+
+- Compatible with 48K, 64K (using RAM under OS), 130XE, and at least
+ 256K or 320K upgraded memory. It will be able to use as much RAM as
+ you have, up to some limit (U1MB?).
+
+- *Not* require the 130XE's separate ANTIC access mode. While this
+ might be helpful, there's a large installed base of expanded 800XLs
+ that don't support it. Plus, the ANTIC bit in PORTB is one of the
+ bits that might get repurposed as a bank bit, for machines with
+ loads of RAM.
+
+- Able to use the extra 6.4K you get if you boot without DOS (straight
+ from the FujiNet).
+
+- Able to use 3K of the RAM under the OS in an XL/XE machine. This would
+ be at $D800-$E3FF: the floating point pack and the font. If we could
+ think of a use for another 1K, it's available at $CC00 (the international
+ font).
+
+- A *single* executable that works on all of the above (no special
+ fnchatxe.xex for extended RAM), meaning it has to detect the
+ amount of RAM and which extended banks exist.
+
+- Adding new text to a screen won't require scrolling all the existing
+ text up by moving it in memory, so it'll be *fast*.
+
+- Config options to disable some of the memory. If you're running
+ SpartaDOS, you need a way to tell FujiNetChat not to use the extra
+ RAM under the OS. If you use a ramdisk that only uses some of your
+ extended memory banks, you need a way to tell FujiNetChat to leave
+ those banks alone.
+
+Terms:
+
+Bank - Hopefully you already know the concept of bankswitching. In
+ this document, I number the banks 0 (for the base 64K) through...
+ I suppose up to 255, since I'll use a byte to store the bank
+ number. This means we might support up to 4MB of memory, if
+ such a thing exists for the Atari. An unexpanded 130XE has
+ 5 banks, which I number 0 through 4. A Rambo 800XL has 13
+ banks, numbered 0 to 12.
+
+Chunk - a 40x23 (or smaller) piece of a screen (can be thought of as a
+ "display window"). At any given time, the screen can only be
+ displaying one chunk. Normally, this is the bottom-most one, where
+ new text is printed as it comes in. The top-most chunk of a screen
+ can be fewer than 23 lines (e.g. if there are 30 lines, you get one
+ 23-line chunk and one 7-line one).
+
+End Marker - a "special" line whose pointer is set to point to itself,
+ and whose data is all spaces. This line is shared by all screens, and
+ actually be displayed (e.g. if the screen is less than 23 lines,
+ they are displayed at the bottom, then the rest of the GR.0 lines
+ are all end markers).
+
+Screen - a scrollable (backwards and forwards) area that displays text,
+ like FNChat already uses. In this scheme, each screen will have a
+ pool number, a line count, a scrollback line count (0 = not scrolled
+ up) and a pointer to the first (bottom-most) line. If the pointer
+ points to the End Marker line, that means no lines are assigned to
+ the screen yet (it was just created and hasn't been written to yet).
+ Otherwise, it points to the address of the *bottom-most* line.
+ A null pointer (0) would be an error, and should never exist.
+ Also the screens will have a title and a status, like the current
+ ones do.
+
+Scrollback - as a noun: the part of the screen that's not normally
+ visible. As a verb, the act of making that part visible. Scrolling
+ will generally be done one chunk at a time, though there's no
+ reason there couldn't be a "one line at a time" scrolling mode.
+
+Screen height - the total number of lines in a screen (includes all
+ its chunks). The minimum height of a screen, upon creation, is
+ actually 0: it has no lines until it's written to.
+
+Line - 42 bytes of memory that store 40 characters (one GR.0 line) of
+ text, plus a 2-byte pointer to the next line (in the screen, or in
+ the free line list). Lines in a screen are stored in a linked list
+ (each points to the next), in reverse order of how they're displayed
+ (bottom-most points to the 2nd-to-bottom, etc, and the top one in
+ a screen points to the End Marker). Lines in the free list are also
+ stored as a linked list, associated with the pool, not any screen.
+ A single line cannot cross a 4K boundary, because ANTIC wouldn't
+ be able to display it properly.
+
+Free Line - a line that isn't being used by any screen. All the
+ free lines in a pool are a linked list: initializing the pool
+ sets up the pointers in all the lines. Closing a screen releases
+ all its used lines into the pool's free line list.
+
+Pool - A (possibly non-contiguous( region of memory available for lines.
+ Each pool has a bank number, a count of unused lines, and a linked
+ list of the unused lines in the pool. Pool 0 is in main memory,
+ is always at least 16K, and can be up to 26880 bytes in size (using
+ 4K of under-the-OS RAM for an XL/XE, plus the space from $0700 to $2000
+ if DOS is not booted). The other pools consist of entire banks, 16K
+ apiece, one per bank. Each screen is created in one pool and cannot
+ be moved to another pool.
+
+Initialization:
+
+At startup, FujiNetChat detects the amount of memory (number of
+extended banks) and creates a pool for each bank. Bank 0's pool can
+include extra memory beyond 16K: whatever's not in use by the client,
+or by DOS (if you booted with one, even). Also pool 0 might have some
+of the RAM under the OS on XL/XE (because FujiNetChat doesn't use the
+two 1K ROM fonts or the 2K math pack, so we get 4K "for free"). All other
+pools (1 and up) will be 16K.
+
+At startup, the [server] and [private] screens will be created. Also
+autojoin channels/queries will each get a screen created.
+
+When creating screens, they're assigned to pools in round-robin
+style. Suppose we have 5 banks of memory (0 through 4), with one pool
+each. The first screen is created in bank 0. The second screen will be
+created in bank 1, 3rd in bank 3, etc. After all pools have one screen
+in them, the next screen creation will use pools 0 again (so now
+we have two screens in one pools). This can continue until we reach
+whatever the limit is: 15 screens? 20? Maybe calculated based on the
+number of banks, so we can guarantee that when all memory is in use,
+each screen will have a minimum of 23 lines. With a 130XE, this would
+be a stupid amount of screens: 17 per bank for the 4 extended banks,
+and at least 17 for bank 0 (so 85 of them, that's too many). Maybe
+limit it to 28, which guarantees each screen can be 3 chunks (69
+lines) tall?
+
+The reason for the round-robin creation: Suppose you're only going to
+use 3 screens (server, private, and one channel). It makes more sense
+for each of those 3 to be in its own bank, so each one can grow to
+16K (around 390 lines, or ~17 chunks). If we created them all in bank 0,
+they'd compete with each other for memory, which is silly when there's
+plenty of free RAM in the other (unused) banks.
+
+Writing text to a screen consists of...
+
+- Find a free line in the screen's pool (see below).
+- Fill the line with the new text.
+- Make the line's 'next' pointer point to the screen's 'head' pointed to.
+- Make the screen's 'head' point to the new line.
+
+The lines in a screen are stored as a textbook example of a linked list.
+
+What happens if we're displaying a screen in one bank, and need
+to add text to a screen that's in a different bank? Well, we have
+to bankswitch to write to the new bank. But doing so will make that
+bank replace the screen memory for the screen we were looking at. So,
+bankswitching and writing has to take place during the vertical blank
+interval, when ANTIC is done displaying the screen and no longer
+reading from RAM.
+
+*Careful*, without writing the code I don't yet know if there's enough
+time in one VBLANK to write a huge (up to 510 bytes) IRC message in
+one go. It'll be OK if it takes more than one frame, but not more than
+maybe 4 or 5 (that'll make the app feel sluggish). Assembly optimization
+is a must for this. Also, we don't have to wait for the VBLANK interrupt
+to happen: we can start after the last visible scanline and work through
+until just before the start of the first visible scanline on the next
+frame.
+
+Finding a free line:
+
+- See if there's a free line in the pool (if the head of the free lines
+ list is not null, and/or if the free lines count is not 0).
+- If you find one, add it to the screen (see above), and remove it
+ from the free list (make the pool's free_list point to whatever
+ the line's 'next' pointed to). Also decrement the free lines count for
+ the pool.
+- If there isn't a free line, we have to 'steal' one from another
+ screen in this pool. For now, just take the one with the most
+ lines and steal its top line, and add it to the screen we're writing to.
+ This means the screens "compete" and eat each other :)
+
+'Stealing' means the screens will automatically balance, to some degree.
+If you have 3 active channels in one bank, during busy periods the 3
+screens will tend to be around the same size. If one channel goes quiet,
+the other 2 will steal lines from it until it gets down to 23 lines,
+then they'll start stealing from each other instead. Maybe the minimum
+should be 46 or 69 lines (2 or 3 chunks), to avoid the scenario where
+you leave the Atari connected while you sleep, and 2 busy channels ate
+all the 6+ hour old text in the other, that came in an hour after you
+went to bed?
+
+Closing a screen:
+
+When a screen is closed, its lines are returned to the free lines list
+in the pool. Since they're already a linked list, all that's needed is
+to add the screen's 'head' to the end of the pool's free lines list,
+and add the screen's line count to the pool's free line count.
+
+Displaying the screen:
+
+All the screens share the same display list, which lives in main memory.
+
+The display list has an LMS for every line. The top 23 lines are for
+the screen, the bottom two are the status bar or edit box (always the
+same address; stored in main menory).
+
+The LMS operands get set like so:
+
+Switch to the screen's bank, then...
+
+Starting at the screen's 'head' line, and the last LMS (bottom of
+23-line area of the DL), walk the linked list of lines (which are in
+bottom-first order) and the display list (backwards).
+
+If we're scrolled up, just keep walking as many lines as we're
+scrolled up (e.g. 23 for one chunk).
+
+When we've walked to the first (bottom-most) line to display (which will
+be the 'head' one, if we weren't scrolled back), write its address as
+the current LMS's 16-bit operand, then move on to the next line
+and the next LMS...
+
+Repeat until we hit the end of the screen (the line count), or we
+hit 23 LMSes. At this point, we're done.
+
+Ideally, we'll double-buffer the display list (2 of them, one
+displaying while the other's being rewritten), and switch to the newly
+modified one during the next VBLANK (just update SDLSTL/H and let
+the OS do it). Note that we *don't* have to deal with banking in the
+display list: we can only show one screen at a time, so we don't need
+to bankswitch.
+
+Switching screens, or scrolling back the current screen, will require
+rebuilding the display list. There's no need to rebuild it every
+frame (there'll be a 'dirty' flag that gets set when switching or
+scrolling).
+
+Scrolling the screen up (or down) is just a matter of setting the
+screen's scroll height. It should *never* be set higher than the
+screen's height, and probably the UI will increase by 23 for each
+press of Start+Up. So if we have 30 lines, counting from 1 (top) to 30
+(bottom), we're normally looking at lines 8 to 30. Scrolling up by
+one chunk will show lines 1 to 7 at the bottom, then the rest of the
+display (the top 2/3s or so) will all be the End Marker line, which
+appears blank. At that point, it won't be possible to scroll again:
+We're at 23, adding another 23 would exceed the height of 30 lines,
+so the attempt is just ignored).
+
+
+Memory layouts for typical machine sizes...
+
+- A 48K 800 will only have pool 0, which will be either 16384 bytes
+or ~390 lines (if DOS is booted) or 22784 bytes or ~542 lines without
+DOS. This is enough to have 7 or 8 screens without about 3 chunks
+(69 lines) apiece, which is better than the exising fixed-buffer code
+manages.
+
+- A 64K 800XL/1200XL/65XE/XEGS will only have pool 0, which will be
+either 20480 bytes (~487 lines) with DOS, or 26880 bytes (~640 lines)
+without DOS.
+
+- A 128K 130XE will have pool 0 as the XL does, plus another 4 pools
+of 16K each. That's 2048 lines (with DOS), which could be organized
+as e.g. 10 screens of 200 lines each, or 16 with 128 lines each, or 20
+with 100 lines each.
+
+- A 256K upgraded XL with DOS will have 132K (135168), or about 3200
+lines. For 512K, roughly twice that. To really take advantage of 256K,
+you'll actually have to create enough screens so that all the banks
+are used (16 screens with 16K each except the one in pool 0 gets
+more). 512K will allow 32 screens, each in its own pool, with close
+to 400 lines of scrollback in each (~17 chunks per screen!)
+
+
+Milestones: things that will have to happen to make this a reality.
+
+1. First and foremost, FNChat needs to go on a diet! Lots of stuff
+ to rewrite in asm, to shrink it down. Currently, it's right at
+ 21K, but it's really more because rx_buf, tx_buf, and the font eat
+ another 2K (in the screen memory area, in lieu of an 8th screen),
+ plus all 3 display lists. No point optimizing the existing screen
+ code for size, though, it's going to be replaced. See doc/diet.txt
+ for details/progress on this.
+
+2. Split the code/BSS/etc into high and low segments, so it lives from
+ $2000 to $3FFF (low, 8K) and $8000 to $BFFF (high, 16K). This
+ puts the primary screen memory area right where the XE bankswitching
+ needs it to be, and gives a *total* size of 24K for the client,
+ including the font, display lists, and all buffers (except ones
+ located in very low memory, $400-$6FF; these are the config and the
+ editbox, and can stay where they are).
+
+ The font and buffers have to be moved out of the new screen address
+ space (the banking window at $4000). I'm thinking the font will be
+ just below the bank area at $3A00, 2 512-byte buffers below that
+ at $3600, display lists below that, etc. Leave about 6K for 'low
+ code', the cc65 stack, and the BSS. Everything else will be in a
+ 'high code' (and possibly 'high BSS') segment, from $8000 to $BFFF.
+
+3. Rip out all the existing screen code and replace it with a simplified
+ form of the new scheme. To start with, only 1-5 pools in bank 0, but
+ the display list modification code can be completed. The rest of
+ the code (especially irc.c) is gonna need changes, because it
+ "knows" that there are "always" 7 screens. This stage includes
+ defining new hotkeys for screen numbers above 7, and making the
+ status bar variable sized (show only the number of screens we
+ have enough RAM for, based on the minimum size being 23 or 46
+ lines).
+
+4. Learn more than I currently know about bankswitching (I know the
+ 130XE, but what's the difference between a Rambo and a Compy Shop
+ upgrade? I *think* I know how to detect all the available banks,
+ but what about when the self-test and/or BASIC bits are being
+ used for bank bits instead? Do I want to even try to support
+ the Axlon and Mosaic upgrades for the 800?)
+
+5. Do a version that supports a 130XE (4 extra banks only). Get it
+ well tested, fix the inevitable issues that are going to happen.
+ This version should also still be usable on 48K/64K. This will
+ probably involve adding the memory detection to the config
+ segment (along with copying the OS to RAM if possible). It'll
+ deposit the pools array somewhere in screen memory, and the
+ client will memcpy() that to its pools[] (before scr_init()
+ is called). No point keeping all that startup code in memory
+ the whole time the client runs.
+
+6. Add support for more banks (detection and use).
+
+Rest of the file is C structs that define the stuff above. This is
+just hypothetical code (final implementation may look different).
+
+/* if each pool is 16K, that's 512K, not bad. however, overhead. maybe
+ limit this to something like 20 (128K extended = 16, plus the big
+ pool in main bank, plus the potential smaller pools at $0700 and
+ $d800. */
+#define MAX_POOLS 32
+
+/* with 512K, we get one screen per pool.
+ with 256K, up to 2 screens per pool.
+ with 128K, up to 4.
+ with 64K, we only get 1 large pool and a couple small ones.
+*/
+#define MAX_SCREENS 32
+
+/* 42 bytes per line */
+typedef struct line_s {
+ struct line_s *next;
+ char data[40];
+} line_t;
+
+/* the end marker line is a line_t, but it lives outside of any pool and
+ has a 'next' pointer that points to itself. */
+
+/* sizeof(screen_t) is 33 bytes... */
+typedef struct {
+ char title[25];
+ char status;
+ char pool;
+ int line_count; /* can be above 255 */
+ int scrollback_pos;
+ line_t *line_list; /* head of a linked list */
+} screen_t;
+
+screen_t screens[MAX_SCREENS]; /* array is 1023 bytes */
+
+typedef struct {
+ u16 start; /* 0 = not in use */
+ u16 end;
+ u8 bank; /* probably this is just the PORTB value */
+ line_t *free_list; /* when this is null, the pool has no free lines */
+} pool_t;
+
+/* this array is sizeof(pool) * 9, so 288 bytes */
+/* the code that builds this array (detects extended ram too),
+ will live in the config segment. */
+pool_t pools[MAX_POOLS];
+
+/* this function is responsible for counting the usable lines (the ones
+ that don't cross a 4K boundary) and arranging them in a linked list
+ that includes all the usable ones. I suppose it should bzero() the
+ memory first. */
+void add_pool(u8 bank, u16 start, u16 end);
diff --git a/src/cmd.c b/src/cmd.c
index e0481c5..b7d9e68 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -9,7 +9,7 @@
#include "config.h"
/* A "command" is actually anything the user types, whether or
- not it starts with a /character. */
+ not it starts with a / character. */
char *command, *arg1, *arg2, *arg3;
static char *target;
@@ -88,14 +88,7 @@ static void cmd_chan_text(void) {
/* 0x02 = ^B = enable bold */
scr_print_active("<\x02");
scr_print_active(conf->nick);
- scr_print_active("\x02");
-
- /*
- if(!scr_current) {
- scr_print_active("/");
- scr_print_active(target);
- }
- */
+ scr_putc_active('\x02');
scr_print_active("> ");
scr_print_active(command);
@@ -314,16 +307,18 @@ void cmd_ctcp_ping(char *nick) {
do_ctcp_ping();
}
-static void do_ctcp_info(void) {
- arg2 = "CLIENTINFO";
+static void do_no_arg_ctcp(char *type) {
+ arg2 = type;
arg3 = 0;
send_ctcp();
}
+static void do_ctcp_info(void) {
+ do_no_arg_ctcp("CLIENTINFO");
+}
+
static void do_ctcp_ver(void) {
- arg2 = "VERSION";
- arg3 = 0;
- send_ctcp();
+ do_no_arg_ctcp("VERSION");
}
static void do_ctcp(void) {
@@ -486,29 +481,25 @@ static void cmd_slash(void) {
cmd_remote();
}
-void cmd_command(char *cmd) {
- command = cmd;
+void cmd_execute(void) {
+ if(!*edit_box) return;
+ command = edit_box;
if(scr_current > 1)
target = scr_get_cur_name();
else
target = 0;
- if(cmd[0] == '/' && cmd[1] && cmd[1] != '/')
+ if(command[0] == '/' && command[1] && command[1] != '/')
cmd_slash();
else if(target)
cmd_chan_text();
else if(scr_current == SCR_PRIV || scr_current == SCR_SERVER)
- cmd_send_pm(cmd);
+ cmd_send_pm(command);
else
err_no_scr_target();
}
-void cmd_execute(void) {
- if(!*edit_box) return;
- cmd_command(edit_box);
-}
-
void cmd_rejoin_chans(void) {
char i;
diff --git a/src/irc.c b/src/irc.c
index e4c0184..f31d89c 100644
--- a/src/irc.c
+++ b/src/irc.c
@@ -78,7 +78,7 @@ static void do_pong(void) {
}
static void bold(void) {
- scr_print_active("\x02");
+ scr_putc_active('\x02');
}
static void hilite_bold(void) {
@@ -88,30 +88,28 @@ static void hilite_bold(void) {
static void do_chan_nick(void) {
if(hilite) {
bell();
- // scr_hilite_active();
new_scr_status = SCR_HILITE;
}
hilite_bold();
- scr_print_active("<");
+ scr_putc_active('<');
hilite_bold();
scr_print_active(msg_src);
if(scr_active == SCR_SERVER) {
/* if we don't have a window for it */
- scr_print_active("/");
+ scr_putc_active('/');
scr_print_active(msg_dest);
}
hilite_bold();
- scr_print_active(">");
+ scr_putc_active('>');
hilite_bold();
- scr_print_active(" ");
+ scr_putc_active(' ');
}
static void do_priv_nick(void) {
if(msg_src) {
- scr_print_active("*");
+ scr_putc_active('*');
scr_print_active(msg_src);
scr_print_active("* ");
- // scr_hilite_active();
new_scr_status = SCR_HILITE;
bell();
}
@@ -147,14 +145,14 @@ static void print_ping_time(char *p) {
scr_print_active(" lag: ");
itoa(sec, numbuf, 10);
scr_print_active(numbuf);
- scr_print_active(".");
+ scr_putc_active('.');
itoa(frac, numbuf, 10);
scr_print_active(numbuf);
- scr_print_active(" sec");
+ scr_putc_active('s');
/*
// for debugging:
- scr_print_active(" ");
+ scr_putc_active(' ');
itoa(pingtime, numbuf, 10);
scr_print_active(numbuf);
*/
@@ -203,7 +201,7 @@ static void do_ctcp(int is_notice) {
if(streq_i(ctcp_type, "ACTION")) {
scr_print_active("* ");
scr_print_active(msg_src);
- scr_print_active(" ");
+ scr_putc_active(' ');
scr_print_active(p);
scr_eol_active();
return;
@@ -355,7 +353,7 @@ static void do_mode(void) {
scr_print_active(" sets mode: ");
for(i = 0; i < msg_argcount; i++) {
scr_print_active(msg_args[i]);
- scr_print_active(" ");
+ scr_putc_active(' ');
}
if(msg_text) scr_print_active(msg_text);
scr_eol_active();
@@ -367,18 +365,18 @@ static void do_mode(void) {
static void do_catchall(int arg) {
if(msg_src) {
scr_print_active(msg_src);
- scr_print_active(" ");
+ scr_putc_active(' ');
}
scr_print_active(msg_cmd);
for(; arg < msg_argcount; arg++) {
- scr_print_active(" ");
+ scr_putc_active(' ');
scr_print_active(msg_args[arg]);
}
if(msg_text) {
- scr_print_active(" ");
+ scr_putc_active(' ');
scr_print_active(msg_text);
}
scr_eol_active();
@@ -586,8 +584,10 @@ static void dispatch_msg(void) {
}
if(scr_active != scr_current) {
- scr_status[scr_active] = new_scr_status;
- scr_show_status(scr_current);
+ if(scr_status[scr_active] < new_scr_status) {
+ scr_status[scr_active] = new_scr_status;
+ scr_show_status(scr_current);
+ }
}
}
@@ -756,7 +756,7 @@ int irc_read(void) {
if(!trip) return 1;
last_read_min = minutes;
- err = nstatus(conf->url);
+ err = nstatus();
if(err != 1) {
scr_display(SCR_SERVER);
@@ -779,7 +779,7 @@ int irc_read(void) {
ind_net_rx();
if(rxbuflen > 0) {
- err = nread(conf->url, rx_buf, rxbuflen);
+ err = nread(rx_buf, rxbuflen);
if(err != 1) {
ind_net_down();
print_errnum();
diff --git a/src/irc.h b/src/irc.h
index b0ff260..8ced02d 100644
--- a/src/irc.h
+++ b/src/irc.h
@@ -1,6 +1,3 @@
-/* 0 = no translation (used to use 3, CRLF) */
-#define FNET_TRANSLATION 0
-
#define MAX_IRC_MSG_LEN 512
#define streq(x,y) !strcmp(x,y)
diff --git a/src/main.c b/src/main.c
index 5535343..4a938b9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -78,7 +78,7 @@ void txbuf_send(void) {
tx_buf[txbuflen++] = 0x0a;
ind_net_tx();
- nwrite(conf->url, tx_buf, txbuflen);
+ nwrite(tx_buf, txbuflen);
ind_net_idle();
txbuf_init();
}
@@ -95,7 +95,7 @@ int fn_connect(void) {
scr_print_current(conf->url);
scr_eol_current();
- err = nopen(conf->url, FNET_TRANSLATION);
+ err = nopen();
if(err != SUCCESS) {
scr_print_current("Connection failed: ");
@@ -118,7 +118,7 @@ int fn_connect(void) {
}
void fn_disconnect(void) {
- nclose(conf->url);
+ nclose();
// Restore old PROCEED interrupt.
PIA.pactl &= ~1; // disable interrupts
diff --git a/src/nio.c b/src/nio.c
index 399b06d..9deae3c 100644
--- a/src/nio.c
+++ b/src/nio.c
@@ -2,201 +2,110 @@
* N: I/O
*/
-#include "nio.h"
-#include "sio.h"
+/* "stripped down" version that harcodes some parameters! Don't
+ use this as example code for writing your own fujinet app! */
+
#include <atari.h>
#include <stddef.h>
+#include "nio.h"
+#include "sio.h"
+#include "config.h"
#define TIMEOUT 0x1f /* approx 30 seconds */
-unsigned char nunit(char* devicespec)
-{
- unsigned char unit=1;
-
- // Set unit to 1 unless explicitly specified.
- if (devicespec[1]==':')
- unit=1;
- else if (devicespec[2]==':')
- unit=devicespec[1]-0x30; // convert from alpha to integer.
- else
- unit=1;
-
- return unit;
+#define UNIT 1 /* only support one FujiNet connection! */
+
+/* 0 = no translation (used to use 3, CRLF) */
+#define TRANS 0
+
+static char get_status(void) {
+ if(OS.dcb.dstats != SUCCESS) {
+ // something went wrong
+ // do we need to return extended status?
+ if(OS.dcb.dstats == DERROR) {
+ nstatus();
+ return OS.dvstat[DVSTAT_EXTENDED_ERROR]; // return extended error.
+ }
+ }
+ return OS.dcb.dstats; // Return SIO error or success
}
-unsigned char nopen(char* devicespec, unsigned char trans)
-{
- unsigned char unit=nunit(devicespec);
-
- OS.dcb.ddevic = DFUJI; // Fuji Device Identifier
- OS.dcb.dunit = unit; // Unit number integer 1 through 4
- OS.dcb.dcomnd = 'O'; // Open
- OS.dcb.dstats = DWRITE; // sending to to SIO device
- OS.dcb.dbuf = devicespec; // eg: N:TCP//
- OS.dcb.dtimlo = TIMEOUT; // approximately 30 second timeout
- OS.dcb.dbyt = 256; // max size of our device spec
- OS.dcb.daux1 = OUPDATE; // Read and write
- OS.dcb.daux2 = trans; // CR/LF translation
- siov();
-
- if (OS.dcb.dstats!=SUCCESS)
- {
- // something went wrong
- // do we need to return extended status?
- if (OS.dcb.dstats==DERROR)
- {
- nstatus(devicespec);
- return OS.dvstat[DVSTAT_EXTENDED_ERROR]; // return extended error.
- }
- }
- return OS.dcb.dstats; // Return SIO error or success
+static void set_defaults(void) {
+ OS.dcb.ddevic = DFUJI; // Fuji Device Identifier
+ OS.dcb.dunit = UNIT; // Unit number integer 1 through 4
+ OS.dcb.dtimlo = TIMEOUT; // approximately 30 second timeout
}
-unsigned char nclose(char* devicespec)
-{
- unsigned char unit=nunit(devicespec);
-
- OS.dcb.ddevic = DFUJI;
- OS.dcb.dunit = unit;
- OS.dcb.dcomnd = 'C'; // Close
- OS.dcb.dstats = 0x00;
- OS.dcb.dbuf = NULL;
- OS.dcb.dtimlo = TIMEOUT;
- OS.dcb.dbyt = 0;
- OS.dcb.daux = 0;
- siov();
-
- if (OS.dcb.dstats!=SUCCESS)
- {
- // something went wrong
- // do we need to return extended status?
- if (OS.dcb.dstats==DERROR)
- {
- nstatus(devicespec);
- return OS.dvstat[DVSTAT_EXTENDED_ERROR]; // return extended error.
- }
- }
- return OS.dcb.dstats; // Return SIO error or success.
+char nopen(void) {
+ set_defaults();
+ OS.dcb.dcomnd = 'O'; // Open
+ OS.dcb.dstats = DWRITE; // sending to to SIO device
+ OS.dcb.dbuf = conf->url; // eg: N:TCP//
+ OS.dcb.dbyt = 256; // max size of our device spec
+ OS.dcb.daux1 = OUPDATE; // Read and write
+ OS.dcb.daux2 = TRANS; // CR/LF translation
+ siov();
+
+ return get_status();
}
-unsigned char nstatus(char* devicespec)
-{
- unsigned char unit=nunit(devicespec);
-
- OS.dcb.ddevic = DFUJI;
- OS.dcb.dunit = unit;
- OS.dcb.dcomnd = 'S'; // status
- OS.dcb.dstats = DREAD;
- OS.dcb.dbuf = OS.dvstat;
- OS.dcb.dtimlo = TIMEOUT;
- OS.dcb.dbyt = sizeof(OS.dvstat);
- OS.dcb.daux = 0;
- siov();
-
- return OS.dvstat[DVSTAT_EXTENDED_ERROR]; // return extended status
-}
+char nclose(void) {
+ set_defaults();
+ OS.dcb.dcomnd = 'C'; // Close
+ OS.dcb.dstats = 0x00;
+ OS.dcb.dbuf = NULL;
+ OS.dcb.dbyt = 0;
+ OS.dcb.daux = 0;
+ siov();
-unsigned char nread(char* devicespec, unsigned char* buf, unsigned short len)
-{
- unsigned char unit=nunit(devicespec);
-
- OS.dcb.ddevic = DFUJI;
- OS.dcb.dunit = unit;
- OS.dcb.dcomnd = 'R'; // read
- OS.dcb.dstats = DREAD;
- OS.dcb.dbuf = buf;
- OS.dcb.dtimlo = TIMEOUT;
- OS.dcb.dbyt = OS.dcb.daux = len; // Set the buffer size AND daux with length
- siov();
-
- if (OS.dcb.dstats!=SUCCESS)
- {
- // something went wrong
- // do we need to return extended status?
- if (OS.dcb.dstats==DERROR)
- {
- nstatus(devicespec);
- return OS.dvstat[DVSTAT_EXTENDED_ERROR]; // return extended error.
- }
- }
- return OS.dcb.dstats; // Return SIO error or success.
+ return get_status();
}
-unsigned char nwrite(char* devicespec, unsigned char* buf, unsigned short len)
-{
- unsigned char unit=nunit(devicespec);
-
- OS.dcb.ddevic = DFUJI;
- OS.dcb.dunit = unit;
- OS.dcb.dcomnd = 'W'; // write
- OS.dcb.dstats = DWRITE;
- OS.dcb.dbuf = buf;
- OS.dcb.dtimlo = TIMEOUT;
- OS.dcb.dbyt = OS.dcb.daux = len;
- siov();
-
- if (OS.dcb.dstats!=SUCCESS)
- {
- // something went wrong
- // do we need to return extended status?
- if (OS.dcb.dstats==DERROR)
- {
- nstatus(devicespec);
- return OS.dvstat[DVSTAT_EXTENDED_ERROR]; // return extended error.
- }
- }
- return OS.dcb.dstats; // Return SIO error or success.
+char nstatus(void) {
+ set_defaults();
+ OS.dcb.dcomnd = 'S'; // status
+ OS.dcb.dstats = DREAD;
+ OS.dcb.dbuf = OS.dvstat;
+ OS.dcb.dbyt = sizeof(OS.dvstat);
+ OS.dcb.daux = 0;
+ siov();
+
+ return OS.dvstat[DVSTAT_EXTENDED_ERROR]; // return extended status
}
-/* https://fujinet.online/wiki/?p=SIO-Command-%24FF-Reset-FujiNet */
-unsigned char nreset(void) {
- OS.dcb.ddevic = 0x70;
- OS.dcb.dunit = 1;
- OS.dcb.dcomnd = 0xff; /* reset */
- OS.dcb.dstats = DWRITE;
- OS.dcb.dbuf = 0;
- OS.dcb.dtimlo = TIMEOUT;
- OS.dcb.dbyt = 0;
- OS.dcb.daux = 0;
- siov();
-
- return OS.dvstat[DVSTAT_EXTENDED_ERROR]; // return extended status
+char nread(char *buf, unsigned short len) {
+ set_defaults();
+ OS.dcb.dcomnd = 'R'; // read
+ OS.dcb.dstats = DREAD;
+ OS.dcb.dbuf = buf;
+ OS.dcb.dbyt = OS.dcb.daux = len; // Set the buffer size AND daux with length
+ siov();
+
+ return get_status();
}
+char nwrite(char *buf, unsigned short len) {
+ set_defaults();
+ OS.dcb.dcomnd = 'W'; // write
+ OS.dcb.dstats = DWRITE;
+ OS.dcb.dbuf = buf;
+ OS.dcb.dbyt = OS.dcb.daux = len;
+ siov();
+
+ return get_status();
+}
-/* IRC doesn't need this */
-#if 0
-unsigned char nlogin(char* devicespec, char *login, char *password)
-{
- unsigned char unit=nunit(devicespec);
-
- OS.dcb.ddevic=0x71;
- OS.dcb.dunit=unit;
- OS.dcb.dcomnd=0xFD;
- OS.dcb.dstats=0x80;
- OS.dcb.dbuf=login;
- OS.dcb.dtimlo=0x1f;
- OS.dcb.dbyt=256;
- OS.dcb.daux=0;
- siov();
-
- if (OS.dcb.dstats!=1)
- {
- nstatus(devicespec);
- return OS.dvstat[DVSTAT_EXTENDED_ERROR]; // return ext err
- }
-
- OS.dcb.dcomnd=0xFE;
- OS.dcb.dstats=0x80;
- OS.dcb.dbuf=password;
- siov();
-
- if (OS.dcb.dstats!=1)
- {
- nstatus(devicespec);
- return OS.dvstat[DVSTAT_EXTENDED_ERROR]; // return ext err
- }
-
- return OS.dcb.dstats;
+/* https://fujinet.online/wiki/?p=SIO-Command-%24FF-Reset-FujiNet */
+char nreset(void) {
+ set_defaults();
+ OS.dcb.ddevic = 0x70;
+ OS.dcb.dcomnd = 0xff; /* reset */
+ OS.dcb.dstats = DWRITE;
+ OS.dcb.dbuf = 0;
+ OS.dcb.dbyt = 0;
+ OS.dcb.daux = 0;
+ siov();
+
+ return OS.dvstat[DVSTAT_EXTENDED_ERROR]; // return extended status
}
-#endif
+
diff --git a/src/nio.h b/src/nio.h
index bc63da8..63b4997 100644
--- a/src/nio.h
+++ b/src/nio.h
@@ -22,51 +22,12 @@
#define DVSTAT_PROTOCOL 2
#define DVSTAT_EXTENDED_ERROR 3
-/**
- * Open N: device with devicespec
- * @param devicespec - an N: device spec, e.g. N:TCP://FOO.COM:1234/
- * @param translation mode, 0=none, 1=cr, 2=lf, 3=cr/lf
- * @return error code, or 1 if successful.
- */
-unsigned char nopen(char* devicespec, unsigned char trans);
-
-/**
- * Close N: device with devicespec
- * @param devicespec - an N: device spec to close (the unit number is extracted)
- * @return error code, or 1 if successful.
- */
-unsigned char nclose(char* devicespec);
-
-/**
- * Get status of specific N: device
- * @param devicespec - an N: device spec to status (the unit number is extracted)
- * @return error code, or 1 if successful, DVSTAT is also filled with status info.
- *
- * Format of DVSTAT:
- * OS.dcb.dvstat[0] = # of bytes waiting LO
- * OS.dcb.dvstat[1] = # of bytes waiting HI
- * OS.dcb.dvstat[2] = reserved
- * OS.dcb.dvstat[3] = Error code of last I/O operation. !1 = error.
- */
-unsigned char nstatus(char* devicespec);
-
-/**
- * Read # of bytes from specific N: device.
- * @param devicespec - an N: device spec to read bytes from.
- * @param buf - The buffer to read into, must be at least as big as len.
- * @param len - The # of bytes to read (up to 65535)
- * @return error code, or 1 if successful, buf is filled with data.
- */
-unsigned char nread(char* devicespec, unsigned char* buf, unsigned short len);
-
-/**
- * Write # of bytes to specific N: device.
- * @param devicespec - an N: device spec to write to.
- * @param buf - The buffer to write to device, should be at least as big as len.
- * @param len - The # of bytes to write (up to 65535)
- * @return error code, or 1 if successful, buf is filled with data.
- */
-unsigned char nwrite(char* devicespec, unsigned char* buf, unsigned short len);
+char nopen(void);
+char nclose(void);
+char nstatus(void);
+char nread(char *buf, unsigned short len);
+char nwrite(char *buf, unsigned short len);
+char nreset(void);
/**
* Send username and password credentials
diff --git a/src/screen.c b/src/screen.c
index 2d4436f..258a4a7 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -10,7 +10,7 @@
/* if DOS isn't being used, the config will carve up the $0700-$1fff
area for extra scrollback. */
-unsigned int *bonus_addrs = (unsigned int *)0xf0;
+unsigned int *bonus_addrs = (unsigned int *)0xd4; /* aka FR0 */
char scr_status[MAX_SCREENS];
@@ -188,14 +188,6 @@ void scr_show_status(char s) {
}
}
-/*
-void scr_hilite_active(void) {
- if(scr_active == scr_current) return;
- scr_status[scr_active] = SCR_HILITE;
- scr_show_status(scr_current);
-}
-*/
-
void scr_refresh(void) {
scr_display(scr_current);
}
diff --git a/src/screen.h b/src/screen.h
index 0d3e268..af95690 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -7,9 +7,9 @@
#define SCR_UNUSED 0
#define SCR_INACTIVE 1
-#define SCR_ACTIVE 2
-#define SCR_HILITE 3
-#define SCR_OTHER 4
+#define SCR_OTHER 2
+#define SCR_ACTIVE 3
+#define SCR_HILITE 4
#define SCR_SERVER 0
#define SCR_PRIV 1
@@ -102,8 +102,6 @@ void scr_print_priv(const char *text);
will have to call this. */
void scr_activate(char s);
-void scr_hilite_active(void);
-
char *scr_get_cur_name(void);
/* XXX: this really should be in a utils.c or common.c... */
diff --git a/src/sio.s b/src/sio.s
index 3dd9191..829fbcb 100644
--- a/src/sio.s
+++ b/src/sio.s
@@ -1,17 +1,3 @@
;; Call SIO
-
.export _siov
- .export _rtclr
- .export _cold_start
-
-_siov: JSR $E459
- RTS
-
-_rtclr: LDA #$00
- STA $12
- STA $13
- STA $14
- RTS
-
-_cold_start:
- JMP $E477
+ _siov = $e459