libMeatloaf/lib/meatloaf/iec_pipe.h
2024-01-08 11:58:15 -06:00

153 lines
5.3 KiB
C++

#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 */