The user-level documentation I found on EXDOS mentioned that a disk channel was automatically closed after a read or write operation, so it seemed like EXDOS would not be able to support streamed i/o. I was reading user-level documentation which was concerned with loadng and saving entire files rather than random access so it could be I was unlucky to look at the wrong place.
I'm not sure what you mean here, where did you find this information and in what kind of context?
Would something like this be able to be efficiently implemented using just EXDOS?
while ((c = fgetc(in)) != EOF)
fputc(process(c), out);
For this kind of common code to be efficient, the implementation has to cache several disk sectors in memory so that individual reads and writes go to memory rather than disk. Most z80 disk implementations have been as simple as possible and perform very badly under C without assistance which is why z88dk is trying to supply disk i.o in a layered manner so that these simple systems can sit on top of a caching mechanism.
Well, that code is not so nice anyway, since you need to issue "system calls" (or whatever we want to name them) all the time character by character, even on a modern OS on decent hardware it will be much slower than doing more bytes on the I/O by your code already. Just to mention that I had to write a log analyzer/"converter" software in C on UNIX and it was much slower using the scheme above. Anyway, that's true that still some may want to try to optimize these somewhat at least on the compiler/OS level.
Regarding your question about the implementation of this in EXDOS. Really, EXDOS is "only" an EXOS_ROM extension for EXOS. Thus, for "generic" file I/O you still use EXOS function calls (like open channel, read channel, check channel status), whatever the file is located on a disk or eg on tape. It's another question that internally, EXDOS will get the request by EXOS if it should be handled. But you even don't need to know there is something like "EXDOS" in the system for basic file I/O, those are just files, and open channels like any other similar entities (or even devices, just think about DISPLAY: or SOUND: ...). However, if you need something "special" over the "generic file I/O", like change directory, create directory whatever, that's not handled by EXOS, and then you need to "talk" with EXDOS then, since it's implementation specific and not generic (eg no "directory" notion of SOUND: device, or on the tape ...). But please note, that's more like my feelings about the structure of EXOS/EXDOS than "official specification"
In my opinion the code above can be done with opening two (file) channels with EXOS one for reading and one for writing. The "read character from channel" EXOS call (function 5) can be used to read a character, and "write character to channel" EXOS call (function 7) to write, to replace fgetc() and fputc(). What I am not sure about: the EOF check. According to the specification of the EXOS calls (see the URL later), "read character from channel" call will wait till a character is available for reading. Well, that's a reasonable thing with eg keyboard channel open, but with file, I don't know what happens if you hit the end of the file. Anyway, there is an EXOS call to check the channel status too: function 9, which can also return with the "end-of-file" state for you (if function 5 won't return with 0 read characters in case of EOF, that must be checked, or some other guy should tell the truth here who is more familiar with the EXOS internals than me). EXDOS internally has buffers, so what I can guess that it won't access the disk all the time if you read byte by byte only. However of course there is a price that you issue an EXOS call byte by byte still, but as I mentioned it's even problem on a decent OS running on modern hardware ...
Again, in this simple example it's not important at all that the file open (and then read, written, whatever) refers for a file in the "realm" of the EXDOS, or not, it's handled by EXOS, and it will talk with EXDOS if needed (however if you really want you can use EXDOS directly anyway even for generic file I/O only ...).
About EXOS calls:
http://ep.homeserver.hu/Dokumentacio/Konyvek/EXOS_2.1_technikal_information/exos/kernel/Ch11.htmlTo be honest, I feel a problem (I mean to use EXOS) with this though. If you read the page at the URL above, you will find that file names can be used to open channels can be maximum of 28 bytes long. It does not feel a problem too much, as with FAT (no VFAT whatever) the 8+3 file name length seems to be OK. But consider the situation that you want to open a file "deeply" in a directory structure like A:\LONGDIR.1\LONGDIR.2\.....\FINAL.TXT so the file name (with full path I mean, what you pass to the EXOS open channel function) can be longer than 28 characters then, which is a no-no then. If I remember correctly I've already asked this on this forum, and the response was something similar that: "it's not so common to use absolute long paths on the EP anyway, just change directory first and access files there without the path information then".
EXOS "channel" operations btw is more like (in my opinion) open() read() etc calls common in C language with "int" typed file descriptors (fd) with the major difference that with EXOS, you must specify a channel number you want even at open(), while open() would "choose" an fd for you (the lowest unused one). It's somewhat also similar that in case of UNIX you can use C code like open("/dev/...", ...) to open a device instead of a "real file" (or maybe CON, PRN in case of DOS-style stuffs?) just that on EXOS would be something like KEYBOARD: and DISPLAY: names.
We don't replace the underlying system, only add to it. So eg, a cpm system can still do file i/o by calling the bdos directly but the c standard i/o is also available to use.
By the way CP/M, EP also has a CP/M compatibility system, named "IS-DOS". It's an interesting stuff (though I've never used too much), in theory it supports even MSX-DOS stuffs (??), and beyond the CP/M (not v3 ...) the disk filling system in the background is still EXDOS, so unlike "original" CP/M systems (using their own file systems, often not even compatible with each other) IS-DOS - with the help of EXDOS - uses FAT12. So IS-DOS is not an "official" CP/M version from Digital Research with only a CBIOS created for the EP keeping BDOS (as far as I know!) but a system developed for the EP with the goal to be compatible with CP/M though (again, as far as I know).
Ok, is there any documentation on what is returned from a port read of $b6? The only doc I've found so far is this:
http://gafz.enterpriseforever.com/Dokumentacio/Konyvek/EXOS_2.1_technikal_information/exos/keyboard/Ch3.html#3.7
which is using the EXOS keyboard driver to read the joystick. The bits are obviously moved because when you read the internal joystick those bits do not correspond to the keys read from $b5.
Reading the external joysticks also uses the $B5 port (like the keyboard) to select what you want to scan, but after the selection is made, you must read port $B6 (unlike the keyboard, where you can read the state on $B5), and bit 0 will carry the state of the selected line. The "selection" itself (numbers are the values written to $B5), and if I recall correctly: 0 = fire, 1 = up, 2 = down, 3 = left, 4 = right, for external joy-1, and for kbd sel 5-9 the same series of assignments for external joy-2. Or something similar. I've never tried to use external joystick(s) in my programs though ... The interesting point here that other machines usually have the joystick as some kind of inputs and you can read a byte, with bits assigned to the fire and direction. On the EP however, as you can see, you must "scan" the joystick somewhat similar as with the keyboard. Maybe you can use a common routine to scan kbd and joystick (and save some CPU cycles?) that you write 0 to $B5, read $B5 to get the state of keys in kbd matrix row #0, and also read $B6 and check bit 0 of the result for joy-1 fire. Then write 1 to $B5, read $B5 to get the state of keys in kbd matrix row #1, but also read $B6 then and check bit 0 of the result for joy-1 direction "up". And so on. Thus you can save to "walk" on 0...9 writes to $B5 twice then (one run is for the kbd, one is for joysticks). As far as I know, for real not only bit 0 can be used (from value read on port $B6) but maybe bits 1, 2 too, thus you can in theory connect "tons of" joysticks to the EP128 with many lines, extra buttons, etc. I am really not sure on this though. I guess, mostly used (though I have no external joysticks at all) "official" (??) solutions uses only bit 0, hopefully on the way I've described above (or maybe not, hmm).
By the way:
https://enterpriseforever.com/hardver/dave/msg27102/#msg27102Unfortunately, it's in Hungarian, so I am not sure how useful it is for you (and what result you'll get with google translator or something like that). But here it is:
https://translate.google.com/translate?sl=hu&tl=en&js=y&prev=_t&hl=hu&ie=UTF-8&u=https%3A%2F%2Fenterpriseforever.com%2Fhardver%2Fdave%2Fmsg27102%2F%23msg27102&edit-text=Joysticks - again - are something I am not so experienced with ...
Another interesting thing, that mouse also works like this (well, the "official" EP mouse is said to be "terrible" - I don't know it personally - so I talk about the "common" solution instead, often named as "boxsoft mouse". It also uses control port lines to read mouse data (originally an MSX-mouse like protocol serialized to one bit transfer with a "shift" signal produced on a line on the serial port .... or something like that). It has some problem though that there is a conflict between external joystick and a mouse then. There is an on-going project (also can be found on the forum) to create a hardware solution for more modern (PS/2?) mouses with some modification to avoid the mentioned conflict.
Yes it is - that's why I'm sort of staggering around to figure out the best way to do this I'm sure the best way will evolve over time.
I don't mind.. the more info the better. Once I have something preliminary ready I'm sure it will be easier to point out how to improve things.
Indeed.