mirror of
https://github.com/idolpx/libMeatloaf.git
synced 2025-12-06 04:38:49 -05:00
153 lines
5.3 KiB
C++
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 */
|