diff options
| -rw-r--r-- | TODO | 3 | ||||
| -rw-r--r-- | config/Makefile | 10 | ||||
| -rw-r--r-- | config/config.c | 23 | ||||
| -rw-r--r-- | doc/dynamic-screens.txt | 391 | ||||
| -rw-r--r-- | src/cmd.c | 37 | ||||
| -rw-r--r-- | src/irc.c | 40 | ||||
| -rw-r--r-- | src/irc.h | 3 | ||||
| -rw-r--r-- | src/main.c | 6 | ||||
| -rw-r--r-- | src/nio.c | 265 | ||||
| -rw-r--r-- | src/nio.h | 51 | ||||
| -rw-r--r-- | src/screen.c | 10 | ||||
| -rw-r--r-- | src/screen.h | 8 | ||||
| -rw-r--r-- | src/sio.s | 16 |
13 files changed, 554 insertions, 309 deletions
@@ -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); @@ -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; @@ -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(); @@ -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) @@ -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 @@ -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 + @@ -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... */ @@ -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 |
