#ifndef MEATLIB_FILESYSTEM_IEC_PIPE #define MEATLIB_FILESYSTEM_IEC_PIPE #include "meat_buffer.h" #include "wrappers/iec_buffer.h" /* This is the main IEC named channel abstraction. Meatloaf keeps an array/map of these as long as they're alive and removes them when channel is closed - each named channel is connected to one file - it allows pusing data to/from remote file - when ATN is received the transfer stops and will be seamlesly resumed on next call to send/receive - resuming transfer is possible as long as this channel is open Example usage: // c64 requests a remote file "http://address/file.prg" auto newPipe = new iecPipe(); newPipe->establish("http://address/file.prg", std::ios_base::openmode::_S_in, iec); // store the pipe in your table of channels ..... // start transfer newPipe->readFile(); // this method returns only when either happened: // 1) the file was read wholly so you have to call newPipe->finish() and remove it from your table of channles // 2) ATN was pulled, so if reading from this channel is later requested again, you fetch it from // your table of channels and call: // storedPipe->readFile() // you can readFile() as many times as needed, and it will do what you expect (resume from where it was interrupted) // as long as it stays open and not EOF. _S_out == C64 -> IEC -> file _S_in == file -> IEC -> C64 */ class iecPipe { Meat::iostream* fileStream = nullptr; oiecstream iecStream; std::ios_base::openmode mode; public: // you call this once, when C64 requested to open the stream bool establish(std::string filename, std::ios_base::openmode m, systemBus* i) { if(fileStream != nullptr) return false; mode = m; iecStream.open(i); fileStream = new Meat::iostream(filename.c_str(), mode); } // this stream is disposed of, nothing more will happen with it! void finish() { if(fileStream != nullptr) delete fileStream; fileStream = nullptr; iecStream.close(); // will push last byte and send EOI (if hasn't been closed yet) } bool seek(std::streampos p) { if(mode == std::ios_base::openmode::_S_in) { // we are LOADing, so we need to seek within the source file input stream (get buffer): fileStream->seekg(p); // our iec stream put buffer can potentially contain more bytes ready for read, but since we are // seeking, we need to flush them, so they don't get sent to C64 as if they were read from file iecStream.flushpbuff(); } else if(mode == std::ios_base::openmode::_S_out) { // we are SAVE-ing, so, we need to seek within the destination file output stream (put buffer): fileStream->seekp(p); //iecStream.flushgbuff() - not sure if it will be required } return false; } // LOAD - push file bytes (fileStream.get) to C64 (iecStream.write) void readFile() { // this pipe wasn't itialized or wasn't meant for reading if(fileStream == nullptr || mode != std::ios_base::openmode::_S_in) return; // push bytes from file to C64 as long as they're available (eying ATN) while(!fileStream->eof() && !fileStream->bad() && !(IEC.flags bitand ATN_PULLED)) { // If this is a socket stream, it might send NDA ("I have no data for you, but keep asking"), so lte's check it! (*fileStream).checkNda(); if((*fileStream).nda()) { // JAIME: So you told me there's a way to signal "no data available on IEC", here's the place // to send it: // TODO } else { // let's try to get and send next byte to IEC char nextChar; //(*fileStream).get(nextChar); fileStream->get(nextChar); // EOF could be set after this get, so if(!fileStream->eof()) { iecStream.write(&nextChar, 1); Debug_printf("%.2X ", nextChar); } } } // the loop exited, it might be because: // - ATN was pulled? if(IEC.flags bitand ATN_PULLED) { // JAIME: anything needs to happen here? } // - read whole? Send EOI! else if(fileStream->eof()) iecStream.close(); // - error occured? else if(fileStream->bad()) { // JAIME: can we somehow signal an error here? } } // SAVE - pull C64 bytes (iecStream.get) to remote file (fileStream.put) void writeFile() { // this pipe wasn't itialized or wasn't meant for writing if(fileStream == nullptr || mode != std::ios_base::openmode::_S_out) return; // push bytes from C64 to file as long as they're available (eying ATN) while(!fileStream->bad() && !(IEC.flags bitand ATN_PULLED)) { char nextChar; //iecStream.get(nextChar); TODO if(!iecStream.eof()) { //(*fileStream).put('a'); fileStream->put(nextChar); } } // so here either the C64 stopped sending bytes to write or the outpt stream died // nothing to see here, move along! } }; #endif /* MEATLIB_FILESYSTEM_IEC_PIPE */