tschak909 Posted January 22, 2020 Author Share Posted January 22, 2020 4 minutes ago, GreyHobbit said: I noticed that Pimoroni in the UK are selling these ESP32 development boards: https://shop.pimoroni.com/products/tinypico Should FujiNet run on one of these? Geoff From what I see there, it should work. You'll need the pin spreadsheet showing what pins should go where. https://docs.google.com/spreadsheets/d/1qEPPM3-gqzfHsogJYuVXqhbvSSsgxdQMb_KGfpoV9KI/edit#gid=351591914 -Thom 1 Quote Link to comment Share on other sites More sharing options...
mozzwald Posted January 22, 2020 Share Posted January 22, 2020 42 minutes ago, GreyHobbit said: I noticed that Pimoroni in the UK are selling these ESP32 development boards: https://shop.pimoroni.com/products/tinypico Should FujiNet run on one of these? Geoff I haven't seen this one before. It is small which is nice, but it has fewer available gpio than the espressif modules. It may have enough but I have not verified. The module does not have a RF shield and the price is 26 USD which is way too expensive. That said, if it has enough gpio available someone could build their own FujiNet with it. It is pretty cool though, tiny and has battery support builtin 1 Quote Link to comment Share on other sites More sharing options...
mozzwald Posted January 23, 2020 Share Posted January 23, 2020 3 hours ago, mozzwald said: I haven't seen this one before. It is small which is nice, but it has fewer available gpio than the espressif modules. It may have enough but I have not verified. The module does not have a RF shield and the price is 26 USD which is way too expensive. That said, if it has enough gpio available someone could build their own FujiNet with it. It is pretty cool though, tiny and has battery support builtin 4 hours ago, GreyHobbit said: I noticed that Pimoroni in the UK are selling these ESP32 development boards: https://shop.pimoroni.com/products/tinypico Should FujiNet run on one of these? Geoff This board is missing GPIO 16 & 17 which are needed for SIO UART communication. Unfortunately, this board won't work as a FujiNet 1 Quote Link to comment Share on other sites More sharing options...
tschak909 Posted January 23, 2020 Author Share Posted January 23, 2020 16 minutes ago, mozzwald said: This board is missing GPIO 16 & 17 which are needed for SIO UART communication. Unfortunately, this board won't work as a FujiNet oops, sorry. Ok, from now on, I am bowing out of the hardware questions. -Thom 1 Quote Link to comment Share on other sites More sharing options...
GreyHobbit Posted January 23, 2020 Share Posted January 23, 2020 19 hours ago, mozzwald said: This board is missing GPIO 16 & 17 which are needed for SIO UART communication. Unfortunately, this board won't work as a FujiNet Just missing those two vital GPIOs. Thanks for checking. It is tiny though, it looks like it's not far off being able to fit into an SIO plug! Quote Link to comment Share on other sites More sharing options...
damosan Posted January 23, 2020 Share Posted January 23, 2020 Quick question - is it possible to get a 1.0 NodeMCU and run it over USB via an SIO2PC (assuming you install the proper drivers)? My soldering capabilities are limited. D. Quote Link to comment Share on other sites More sharing options...
tschak909 Posted January 24, 2020 Author Share Posted January 24, 2020 I am currently implementing a test called tests/esp32/http-fetch, to demonstrate how to implement a CIO device that would allow the following: RUN"N:HTTP://IRATA.ONLINE/HELLO.BAS" To start, the firmware on the ESP needs to be amended, as you can see in this commit: https://github.com/FujiNetWIFI/atariwifi/commit/2a794a9d790096b820354481c63f7617f4d7a5cf This implements three SIO commands to open, get data, and close the http connection, that will be used by the cio handler in atari-cio/ -Thom 1 Quote Link to comment Share on other sites More sharing options...
tschak909 Posted January 24, 2020 Author Share Posted January 24, 2020 Once the SIO commands are implemented, we can implement the CIO driver. I am doing this in CC65. A custom atari.cfg linker file is used, specifying a fixed start address of $1D00 (putting it right above DOS 2.5 memlo with 2 drives), and the available zero-page usage is scooted towards offset $D0, so that we don't clobber BASIC's internal zero-page variables. Notice also that the SYSCHK and its header bits have been removed, to make the binary smaller. We don't need it. src/atari.cfg FEATURES { STARTADDRESS: default = $1D00; } SYMBOLS { __EXEHDR__: type = import; __AUTOSTART__: type = import; # force inclusion of autostart "trailer" __STACKSIZE__: type = weak, value = $0800; # 2k stack __STARTADDRESS__: type = export, value = %S; __RESERVED_MEMORY__: type = weak, value = $0000; } MEMORY { ZP: file = "", define = yes, start = $00E5, size = $001A; # file header, just $FFFF HEADER: file = %O, start = $0000, size = $0002; # "main program" load chunk MAINHDR: file = %O, start = $0000, size = $0004; MAIN: file = %O, define = yes, start = %S, size = $BC20 - __STACKSIZE__ - __RESERVED_MEMORY__ - %S; TRAILER: file = %O, start = $0000, size = $0006; } SEGMENTS { ZEROPAGE: load = ZP, type = zp; EXTZP: load = ZP, type = zp, optional = yes; EXEHDR: load = HEADER, type = ro; MAINHDR: load = MAINHDR, type = ro; STARTUP: load = MAIN, type = ro, define = yes; LOWBSS: load = MAIN, type = rw, optional = yes; # not zero initialized LOWCODE: load = MAIN, type = ro, define = yes, optional = yes; ONCE: load = MAIN, type = ro, optional = yes; CODE: load = MAIN, type = ro, define = yes; RODATA: load = MAIN, type = ro; DATA: load = MAIN, type = rw; INIT: load = MAIN, type = rw, optional = yes; BSS: load = MAIN, type = bss, define = yes; AUTOSTRT: load = TRAILER, type = ro; } FEATURES { CONDES: type = constructor, label = __CONSTRUCTOR_TABLE__, count = __CONSTRUCTOR_COUNT__, segment = ONCE; CONDES: type = destructor, label = __DESTRUCTOR_TABLE__, count = __DESTRUCTOR_COUNT__, segment = RODATA; CONDES: type = interruptor, label = __INTERRUPTOR_TABLE__, count = __INTERRUPTOR_COUNT__, segment = RODATA, import = __CALLIRQ__; } main.c: We need to set up the handler table (HATABS) to point to individual functions for open, close, get, put, for typical I/O transactions. There is also a pointer to "special" which is used for any other wanted CIO command, think XIO in BASIC for any commands above 16. There is also a cio_init() which I am still learning the semantics of, so can't comment on it too much. Also, because this is a prototype, the handler loads into a fixed position in memory, and pushes MEMLO to a fixed position at the end of the initialized memory segment. /** * http-fetch CIO driver */ #include <atari.h> #include <6502.h> #include <stdio.h> #include <string.h> #include "cio.h" devhdl_t devhdl; unsigned char packet[256]; extern void cio_open(void); extern void cio_close(void); extern void cio_get(void); extern void cio_put(void); extern void cio_status(void); extern void cio_special(void); unsigned char ret; unsigned char err; void cio_init(void) { } void main(void) { unsigned char i; // Populate a devhdl table for our new N: device. devhdl.open = (char *)cio_open-1; devhdl.close = (char *)cio_close-1; devhdl.get = (char *)cio_get-1; devhdl.put = (char *)cio_put-1; devhdl.status = (char *)cio_status-1; devhdl.special = (char *)cio_special-1; devhdl.init = cio_init; // find next hatabs entry for (i=0;i<11;i++) { if (OS.hatabs[i].id==0x00) break; } // And inject our handler table into its slot. OS.hatabs[i].id='N'; // N: device OS.hatabs[i].devhdl=&devhdl; // handler table for N: device. // Manually setting memlo, is there a symbol that can get me actual top of data? OS.memlo=(void *)0x23A0; } You can see, that each function pointer is - 1. This is not a typo. CIO needs it this way, so we have to cast to a char* so that we can back up by one byte. We set up the device handle statically in memory, and then populate HATABS with a pointer to it. Now CIO knows about our N: device. Here's an implementation of cio_close(). Since this has no parameters, we simply just do an SIO call to our created sio_http_close(), and return. CIO proper will take care of freeing the IOCB for us. cio-close.c: /** * CIO Close call */ #include <atari.h> #include <6502.h> #include "sio.h" extern unsigned char err; extern unsigned char ret; void _cio_close(void) { OS.dcb.ddevic=0x70; // Network adapter OS.dcb.dunit=1; OS.dcb.dcomnd=0xE4; // sio_http_close() OS.dcb.dstats=0x00; // no data OS.dcb.dtimlo=0x1f; // Timeout OS.dcb.dbyt=0; OS.dcb.dbuf=NULL; // A packet. OS.dcb.daux1=0; siov(); err=OS.dcb.dstats; } Those sharp-eyed among you will notice that the C call is _cio_close(). This is because CIO expects its return parameters in a specific order which CC65 does not do, so we have to make a small 'shim' of assembler code around the C code, to call the C function, and then put the return values in the registers that CIO expects (the return value in A, the error code in Y), so we make a stubs file which contains the wrappers. cio-stubs.s .include "atari.inc" .import _ret .import _err .import __cio_open, __cio_close, __cio_get, __cio_put, __cio_status, __cio_special .export _cio_open, _cio_close, _cio_get, _cio_put, _cio_status, _cio_special _cio_close: jsr __cio_close lda _ret ldy _err rts _cio_get: jsr __cio_get lda _ret ldy _err rts _cio_open: jsr __cio_open lda _ret ldy _err rts _cio_put: sta _ret jsr __cio_put lda _ret ldy _err rts _cio_special: jsr __cio_special lda _ret ldy _err rts _cio_status: jsr __cio_status lda _ret ldy _err rts Note: In CA65, any function calls from CC65 are prepended with an underscore (_). Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted January 24, 2020 Share Posted January 24, 2020 10 minutes ago, tschak909 said: and the available zero-page usage is scooted towards offset $D0, so that we don't clobber BASIC's internal zero-page variables. This isn't going to work out too well for applications which don't use the FP pack and use the entire upper half of page zero for variables. There are about six page zero locations (IIRC) reserved for CIO handler usage (just as there are ten or so usable by SIO drivers and PBI device handlers). Unless you cache anything else on the way in and restore it on the way out, you will have compatibility issues. Since CC65's runtime probably requires a number of page zero locations just to manage the call stack, it might be worth thinking about straight assembly language. 3 Quote Link to comment Share on other sites More sharing options...
tschak909 Posted January 24, 2020 Author Share Posted January 24, 2020 How far should I move it up? -Thom Quote Link to comment Share on other sites More sharing options...
tschak909 Posted January 24, 2020 Author Share Posted January 24, 2020 (and yes, I am aware of ZIOCB, but I need those to know what IOCB I am working with.) FWIW, this specifies that my zero page usage STARTS at $D0 currently.) -Thom Quote Link to comment Share on other sites More sharing options...
tschak909 Posted January 24, 2020 Author Share Posted January 24, 2020 I know this is freaking out the assembler programmers on this thread. I am doing it this way to make it clearer to demonstrate. Just take a deep breath, and know that I said PROTOTYPE. Stefan Dorndorf ported my earlier CIO work to assembler, to give me a scaffold to work off of, so this will wind up in assembler. This is being done to demonstrate HOW I am adding functionality. 1 Quote Link to comment Share on other sites More sharing options...
tschak909 Posted January 24, 2020 Author Share Posted January 24, 2020 Here is the cio-open() call. cio-open.c /** * CIO Open call */ #include <atari.h> #include <6502.h> #include <string.h> #include "sio.h" extern unsigned char err; extern unsigned char ret; extern unsigned char packet[256]; void _cio_open(void) { char *p=(char *)OS.ziocb.buffer; // remove EOL p[OS.ziocb.buflen-1]=0x00; // Scoot buffer past the N: p+=2; // Copy into packet strcpy(packet,p); // Start setting up DCB. OS.dcb.ddevic=0x70; // Network card OS.dcb.dcomnd=0xE6; OS.dcb.dunit=1; // device unit 1 OS.dcb.dstats=0x80; // Write URL to peripheral OS.dcb.dbuf=&packet; // Packet OS.dcb.dtimlo=0x1F; // Timeout OS.dcb.daux=0; // no aux byte siov(); // Clear buffer memset(&packet,0x00,sizeof(packet)); ret=err=OS.dcb.dstats; } For each call to CIOV, a copy of the IOCB that requested the operation is copied into zero-page (which we reference here as OS.ziocb), which makes it really easy to get the parameters we need. for reference, an IOCB looks like: /* I/O control block */ struct __iocb { unsigned char handler; /* handler index number (0xff free) */ unsigned char drive; /* device number (drive) */ unsigned char command; /* command */ unsigned char status; /* status of last operation */ void* buffer; /* pointer to buffer */ void* put_byte; /* pointer to device's PUT BYTE routine */ unsigned int buflen; /* length of buffer */ unsigned char aux1; /* 1st auxiliary byte */ unsigned char aux2; /* 2nd auxiliary byte */ unsigned char aux3; /* 3rd auxiliary byte */ unsigned char aux4; /* 4th auxiliary byte */ unsigned char aux5; /* 5th auxiliary byte */ unsigned char spare; /* spare byte */ }; A great deal of work is already handled in CIOV, it has figured out from the buffer passed in, that it needs to go to our handler (Because of the N:), and it needs to be routed to the cio_open command, due to the IOCB command being set to IOCB_OPEN. There are lots of other goodies such as the aux bits (notice there are 5 of them! only two are exposed in most high level languages, so if you want to use them, you have to set those values manually) One of the things passed to our open, is a buffer containing the "filename" to open. This includes the device name and colon, so, if we were to execute this command from BASIC: RUN"N:HTTP://IRATA.ONLINE/HELLO.BAS" CIO would execute an OPEN, passing a pointer to the buffer in the IOCB, as well as the length of the above string, (in ICBAL/ICBAH and ICBLL/ICBLH respectively, which our C struct maps to something easier to handle). One thing to note, is that we are basically ignoring aux1, which is used by CIO OPEN to determine what type of open this needs to be, 4 = read, 8 = write, 12 = update, etc... For this particular test, we don't care, but normally, we'd be tweaking SIO parameters based on this value. The buffer that is passed in is terminated with an EOL ($9B) character, that since we're dealing with it in C, we simply remove it by turning it to a null, before copying it into our destination buffer. Also, since we don't care about WHICH N: device we're receiving, we simply scoot the pointer to the buffer past those characters, and set that pointer to the call of our DCB, and set up the other particulars needed to call our function on the ESP, before calling siov(). For now, we are simply returning the dstats returned by the SIO call, back to our program. This basically limits our error messages to something SIO related, so, which means we basically get these error codes: 1 - Everything okay, #FujiNet sent back a COMPLETE, and the computer was happy with any resulting data. 138 - #FujiNet did not respond to command before timeout. 139 - #FujiNet did a NAK on the command frame. 140 - Serial Input Framing error, computer couldn't synchronize to the start/stop bits. 142 - Serial Input overrun - We got too many bits before a stop bit 143 - Checksum error - The checksum of the data frame sent to the computer didn't match what was computed. 144 - Device Done - #FujiNet sent an ERROR in response to a command completing. There is also an ERROR 146, which can be emitted by CIO if a particular CIO operation isn't implemented (e.g. P: does not implement GET, but it does implement PUT) 1 Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted January 24, 2020 Share Posted January 24, 2020 I'm not talking about the ZIOCB. But if everything's going to be coded in assembly language anyway, I'm sure there'll be no problem. 1 Quote Link to comment Share on other sites More sharing options...
tschak909 Posted January 24, 2020 Author Share Posted January 24, 2020 The final bit that we need for this test, is an implementation of the CIO GET routine. Specifically, we only need GETCHR, so we don't need to implement GETREC. With no checks/etc in place, this gives us: /** * CIO Get call */ #include <atari.h> #include <6502.h> #include "sio.h" extern unsigned char err; extern unsigned char ret; extern unsigned char packet[256]; extern void _cio_status(void); unsigned char packetlen; unsigned char* p; void _cio_get_chr(void) { err=1; ret=*p++; packetlen--; } void _cio_get(void) { // If buffer is empty, get next buffer from esp if (packetlen==0) { packetlen=256; OS.dcb.ddevic=0x70; OS.dcb.dunit=1; OS.dcb.dcomnd=0xE5; OS.dcb.dstats=0x40; OS.dcb.dtimlo=0x1f; OS.dcb.dbyt=256; OS.dcb.dbuf=&packet; OS.dcb.daux=0; siov(); err=OS.dcb.dstats; p=&packet[0]; } _cio_get_chr(); } We are relying on the fact that we have pre-initialized the ESP's buffer with nulls, and that we will always return a 256 byte buffer, to simplify things. Also BASIC will do a GETCHR for precisely the amount of bytes it needs for a given pass (it derives this information from header of the program being loaded.) Ideally, there would be some more defensive measures, checking for errors, etc. but I wanted to keep this concise. I did make a couple of small bugs, that I did go back and correct: * Needed to change the EOL substitution code slightly in OPEN. * dbyt for OPEN needed to be set * CLOSE needed to reset the packetlen to 0 to force a buffer re-load. I'm recording a video showing this test, right now. -Thom Quote Link to comment Share on other sites More sharing options...
tschak909 Posted January 24, 2020 Author Share Posted January 24, 2020 #FujiNet #Atari8bit This test shows the possibility of using the N: (network) device for file-level HTTP GET requests. This is implemented using a CIO handler loaded at boot via AUTORUN.SYS. It works well enough to load BASIC programs! 6 Quote Link to comment Share on other sites More sharing options...
+Allan Posted January 25, 2020 Share Posted January 25, 2020 To think that you could write a basic program on a real Atari and immediately send it directly to another real Atari in just a few seconds is mind blowing! Allan 3 Quote Link to comment Share on other sites More sharing options...
tschak909 Posted January 25, 2020 Author Share Posted January 25, 2020 So, I'm getting a very painful introduction to the inconsistent internals of various FMSes, and their handling of CIO filenames. Jeebus. To try and deal with some of this, I created a command, Set Base URL, which can be used as an XIO: XIO 20,#1,0,0,"N:http://35.239.67.240/" Subsequently, you can reference a file at that URL by doing: N:BURIEDBU.COM This seems to help, somewhat, I can load BASIC programs that start at that URL by doing: RUN"N:HELLO.BAS" but I can't load binary load files, in this manner, it just keeps reading past the end of the file, regardless of DUP only specifying a certain number of bytes in the IOCB. I have limited debugging information here, because I don't have access to Altirra's debugger while I'm looking at this, but I do wonder: Is emitting an ERROR 136 important when loading a well formed binary load file? @phaeron @flashjazzcat do you guys have any insight into this? -Thom Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted January 25, 2020 Share Posted January 25, 2020 3 hours ago, tschak909 said: Is emitting an ERROR 136 important when loading a well formed binary load file? Absolutely, since DOS will just keep reading segment headers until it gets EOF. BASIC programs - I guess - have the file length encoded in the header. Quote Link to comment Share on other sites More sharing options...
tschak909 Posted January 25, 2020 Author Share Posted January 25, 2020 Absolutely, since DOS will just keep reading segment headers until it gets EOF. BASIC programs - I guess - have the file length encoded in the header.Yup. Ok. So i will implement a file size SIO call for the ESP.Meanwhile I figured out that disk based SpartaDOS requires CIO drivers to implement XIO 40 for binary load. All of this crazy exercise is being documentedmSent from my SM-G920F using Tapatalk Quote Link to comment Share on other sites More sharing options...
tschak909 Posted January 25, 2020 Author Share Posted January 25, 2020 (edited) As part of research on fleshing out the N: device, I have opened up a page on the wiki detailing filename size limitations in various DOSes. https://github.com/FujiNetWIFI/atariwifi/wiki/N:-Device-Filename-Size-Limitations This is important, as the data in these pages will go a long way to making a compatible file-level sharing mechanism that will work across the N: CIO device. Feel free to read it. If you can add to it, please do. I have opened up access to the Wiki so that other people can help! The page has a testing/recording procedure that you can follow to add your favorite DOS. -Thom Edited January 25, 2020 by tschak909 Quote Link to comment Share on other sites More sharing options...
phaeron Posted January 25, 2020 Share Posted January 25, 2020 You'll also want to implement the Y=$03 success return code when the last data in the file is read. This is documented in section 5 of the OS Manual, on page 79. Quote Link to comment Share on other sites More sharing options...
tschak909 Posted January 25, 2020 Author Share Posted January 25, 2020 (edited) 8 minutes ago, phaeron said: You'll also want to implement the Y=$03 success return code when the last data in the file is read. This is documented in section 5 of the OS Manual, on page 79. Which OS manual, got a link? Also, I have my err variable set to return in Y. so I should return a 3 instead of a 136 on success? -Thom Edited January 25, 2020 by tschak909 Quote Link to comment Share on other sites More sharing options...
phaeron Posted January 25, 2020 Share Posted January 25, 2020 1 hour ago, tschak909 said: Which OS manual, got a link? Also, I have my err variable set to return in Y. so I should return a 3 instead of a 136 on success? -Thom The Operating System User's Manual: https://archive.org/details/bitsavers_atari40080mputerTechnicalReferenceNotes1982_20170986/page/n63/mode/2up You want to return $01 if the entire read was successful and there is still file data remaining, $03 if the entire read was successful and there is no more file data remaining, and $88 if the end of file was reached before the whole read request could be fulfilled. 5 Quote Link to comment Share on other sites More sharing options...
ivop Posted January 25, 2020 Share Posted January 25, 2020 16 hours ago, tschak909 said: RUN"N:HELLO.BAS" Ah, finally, the curl | bash equivalent for the Atari! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.