mirror of
https://github.com/autc04/Retro68.git
synced 2025-02-17 11:31:00 +00:00
LaunchAPPL: serial connection
This commit is contained in:
parent
bdf4685d82
commit
bafd53f2ae
@ -1,5 +1,10 @@
|
||||
add_subdirectory(Common)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES Retro.*)
|
||||
add_subdirectory(Server)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES RetroCarbon)
|
||||
else()
|
||||
add_subdirectory(Server)
|
||||
endif()
|
||||
else()
|
||||
add_subdirectory(Client)
|
||||
endif()
|
||||
|
@ -4,6 +4,7 @@ set(LAUNCHMETHODS
|
||||
Executor.h Executor.cc
|
||||
MiniVMac.h MiniVMac.cc
|
||||
SSH.h SSH.cc
|
||||
Serial.h Serial.cc
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
@ -28,7 +29,7 @@ add_executable(LaunchAPPL
|
||||
|
||||
|
||||
target_include_directories(LaunchAPPL PRIVATE ${CMAKE_INSTALL_PREFIX}/include ${Boost_INCLUDE_DIR})
|
||||
target_link_libraries(LaunchAPPL ResourceFiles ${Boost_LIBRARIES})
|
||||
target_link_libraries(LaunchAPPL ResourceFiles LaunchAPPLCommon ${Boost_LIBRARIES})
|
||||
|
||||
if(APPLE)
|
||||
find_library(APPLICATIONSERVICES_FW ApplicationServices)
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "Executor.h"
|
||||
#include "MiniVMac.h"
|
||||
#include "SSH.h"
|
||||
#include "Serial.h"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
namespace fs = boost::filesystem;
|
||||
@ -42,7 +43,8 @@ static void RegisterLaunchMethods()
|
||||
new Carbon(),
|
||||
#endif
|
||||
new Executor(), new MiniVMac(),
|
||||
new SSH()
|
||||
new SSH(),
|
||||
new Serial()
|
||||
// #### Add new `LaunchMethod`s here.
|
||||
};
|
||||
|
||||
|
168
LaunchAPPL/Client/Serial.cc
Normal file
168
LaunchAPPL/Client/Serial.cc
Normal file
@ -0,0 +1,168 @@
|
||||
#include "Serial.h"
|
||||
#include "Launcher.h"
|
||||
#include "Utilities.h"
|
||||
#include "Stream.h"
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <poll.h>
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
||||
|
||||
class SerialStream : public Stream
|
||||
{
|
||||
static const long kReadBufferSize = 4096;
|
||||
uint8_t readBuffer[kReadBufferSize];
|
||||
public:
|
||||
int fd;
|
||||
|
||||
virtual void write(const void* p, size_t n) override;
|
||||
|
||||
void wait();
|
||||
|
||||
SerialStream(po::variables_map &options);
|
||||
~SerialStream();
|
||||
};
|
||||
|
||||
class SerialLauncher : public Launcher
|
||||
{
|
||||
SerialStream stream;
|
||||
public:
|
||||
SerialLauncher(po::variables_map& options);
|
||||
virtual ~SerialLauncher();
|
||||
|
||||
virtual bool Go(int timeout = 0);
|
||||
|
||||
private:
|
||||
void write(const void *p, size_t n) { stream.write(p, n); }
|
||||
ssize_t read(void * p, size_t n);
|
||||
};
|
||||
|
||||
|
||||
SerialStream::SerialStream(po::variables_map &options)
|
||||
{
|
||||
std::string port = options["serial-port"].as<std::string>();
|
||||
fd = open(port.c_str(), O_RDWR | O_NOCTTY | O_NDELAY );
|
||||
if(fd < 0)
|
||||
throw std::runtime_error("Cannot open serial port.\n");
|
||||
|
||||
struct termios tios;
|
||||
tcgetattr(fd,&tios);
|
||||
|
||||
tios.c_cflag = B19200 | CRTSCTS | CS8 | CLOCAL | CREAD;
|
||||
tios.c_iflag = 0;//IGNPAR | ICRNL;
|
||||
tios.c_lflag = 0;
|
||||
tios.c_oflag = 0;
|
||||
tios.c_cc[VTIME] = 0; /* inter-character timer unused */
|
||||
tios.c_cc[VMIN] = 1; /* blocking read until 5 chars received */
|
||||
tcsetattr(fd,TCSANOW,&tios);
|
||||
usleep(500000);
|
||||
}
|
||||
SerialStream::~SerialStream()
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void SerialStream::write(const void* p, size_t n)
|
||||
{
|
||||
while(n)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLOUT;
|
||||
pfd.revents = 0;
|
||||
poll(&pfd, 1, 1000);
|
||||
if(pfd.revents & POLLOUT)
|
||||
{
|
||||
ssize_t written = ::write(fd, p, n);
|
||||
if(written > 0)
|
||||
{
|
||||
p = (const void*) ( (const char*)p + written );
|
||||
n -= written;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SerialStream::wait()
|
||||
{
|
||||
struct pollfd pfd;
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLIN;
|
||||
pfd.revents = 0;
|
||||
poll(&pfd, 1, 1000);
|
||||
if(pfd.revents & POLLIN)
|
||||
{
|
||||
ssize_t n = ::read(fd, readBuffer, kReadBufferSize);
|
||||
if(n > 0)
|
||||
{
|
||||
onReceive(readBuffer, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SerialLauncher::SerialLauncher(po::variables_map &options)
|
||||
: Launcher(options), stream(options)
|
||||
{
|
||||
}
|
||||
|
||||
SerialLauncher::~SerialLauncher()
|
||||
{
|
||||
}
|
||||
|
||||
ssize_t SerialLauncher::read(void *p, size_t n)
|
||||
{
|
||||
ssize_t available = stream.read(p, n);
|
||||
while(!available)
|
||||
{
|
||||
stream.wait();
|
||||
available = stream.read(p, n);
|
||||
}
|
||||
return available;
|
||||
}
|
||||
|
||||
bool SerialLauncher::Go(int timeout)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
{
|
||||
std::ostringstream rsrcOut;
|
||||
app.resources.writeFork(rsrcOut);
|
||||
std::string rsrc = rsrcOut.str();
|
||||
std::string& data = app.data;
|
||||
|
||||
tmp = htonl(data.size());
|
||||
write(&tmp, 4);
|
||||
tmp = htonl(rsrc.size());
|
||||
write(&tmp, 4);
|
||||
|
||||
write(data.data(), data.size());
|
||||
write(rsrc.data(), rsrc.size());
|
||||
}
|
||||
|
||||
read(&tmp, 4);
|
||||
tmp = ntohl(tmp);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Serial::GetOptions(options_description &desc)
|
||||
{
|
||||
desc.add_options()
|
||||
("serial-port", po::value<std::string>()->default_value("/dev/ttyUSB0"), "serial port to use")
|
||||
;
|
||||
}
|
||||
|
||||
bool Serial::CheckOptions(variables_map &options)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<Launcher> Serial::MakeLauncher(variables_map &options)
|
||||
{
|
||||
return std::unique_ptr<Launcher>(new SerialLauncher(options));
|
||||
}
|
16
LaunchAPPL/Client/Serial.h
Normal file
16
LaunchAPPL/Client/Serial.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef SERIAL_H
|
||||
#define SERIAL_H
|
||||
|
||||
#include "LaunchMethod.h"
|
||||
|
||||
class Serial : public LaunchMethod
|
||||
{
|
||||
public:
|
||||
virtual std::string GetName() { return "serial"; }
|
||||
virtual void GetOptions(options_description& desc);
|
||||
virtual bool CheckOptions(variables_map& options);
|
||||
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
};
|
||||
|
||||
#endif // EXECUTOR_H
|
5
LaunchAPPL/Common/CMakeLists.txt
Normal file
5
LaunchAPPL/Common/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
add_library(LaunchAPPLCommon
|
||||
Stream.h
|
||||
Stream.cc
|
||||
)
|
||||
target_include_directories(LaunchAPPLCommon PUBLIC .)
|
50
LaunchAPPL/Common/Stream.cc
Normal file
50
LaunchAPPL/Common/Stream.cc
Normal file
@ -0,0 +1,50 @@
|
||||
#include "Stream.h"
|
||||
#include <string.h>
|
||||
|
||||
Stream::Stream()
|
||||
{
|
||||
}
|
||||
|
||||
Stream::~Stream()
|
||||
{
|
||||
}
|
||||
|
||||
void Stream::onReceive(const uint8_t* p, size_t n)
|
||||
{
|
||||
if(buffer_.empty())
|
||||
{
|
||||
size_t consumed = listener_ ? listener_->onReceive(p,n) : 0;
|
||||
if(consumed < n)
|
||||
buffer_.insert(buffer_.end(), p + consumed, p + n);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer_.insert(buffer_.end(), p, p+n);
|
||||
}
|
||||
|
||||
while(!buffer_.empty())
|
||||
{
|
||||
size_t consumed = listener_ ? listener_->onReceive(buffer_.data(), buffer_.size()) : 0;
|
||||
buffer_.erase(buffer_.begin(), buffer_.begin()+consumed);
|
||||
|
||||
if(!consumed)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
long Stream::read(void *p, size_t n)
|
||||
{
|
||||
if(buffer_.size() <= n)
|
||||
{
|
||||
size_t bufsiz = buffer_.size();
|
||||
memcpy(p, buffer_.data(), buffer_.size());
|
||||
buffer_.clear();
|
||||
return bufsiz;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(p, buffer_.data(), n);
|
||||
buffer_.erase(buffer_.begin(), buffer_.begin()+n);
|
||||
return n;
|
||||
}
|
||||
}
|
26
LaunchAPPL/Common/Stream.h
Normal file
26
LaunchAPPL/Common/Stream.h
Normal file
@ -0,0 +1,26 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <vector>
|
||||
|
||||
class StreamListener
|
||||
{
|
||||
public:
|
||||
virtual size_t onReceive(const uint8_t* p, size_t n) = 0;
|
||||
};
|
||||
|
||||
class Stream
|
||||
{
|
||||
StreamListener *listener_;
|
||||
std::vector<uint8_t> buffer_;
|
||||
public:
|
||||
Stream();
|
||||
virtual ~Stream();
|
||||
|
||||
void setListener(StreamListener *l) { listener_ = l; }
|
||||
|
||||
virtual void write(const void* p, size_t n) = 0;
|
||||
long read(void *p, size_t n);
|
||||
|
||||
protected:
|
||||
void onReceive(const uint8_t* p, size_t n);
|
||||
};
|
@ -1 +1,2 @@
|
||||
add_application(LaunchAPPLServer CONSOLE main.cc)
|
||||
target_link_libraries(LaunchAPPLServer LaunchAPPLCommon)
|
||||
|
@ -1,38 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
class Block
|
||||
{
|
||||
uint8_t *begin_ = nullptr;
|
||||
uint8_t *end_ = nullptr;
|
||||
public:
|
||||
Block() = default;
|
||||
Block(uint8_t *p, size_t len) : begin_(p), end_(p+len) {}
|
||||
Block(uint8_t *b, uint8_t *e) : begin_(b), end_(e) {}
|
||||
|
||||
uint8_t * begin() { return begin_; }
|
||||
const uint8_t * begin() const { return begin_; }
|
||||
uint8_t * end() { return end_; }
|
||||
const uint8_t * end() const { return end_; }
|
||||
|
||||
size_t size() const { return end_ - begin_; }
|
||||
};
|
||||
|
||||
class StreamListener
|
||||
{
|
||||
public:
|
||||
virtual void onReceive(const Block& b) = 0;
|
||||
};
|
||||
|
||||
class Stream
|
||||
{
|
||||
StreamListener *listener_;
|
||||
public:
|
||||
void setListener(StreamListener *l) { listener_ = l; }
|
||||
|
||||
virtual void send(const Block& b) = 0;
|
||||
|
||||
protected:
|
||||
void onReceive(const Block& b)
|
||||
{ if(listener_) listener_->onReceive(b); }
|
||||
};
|
@ -5,7 +5,8 @@
|
||||
#include <Events.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Stream.h"
|
||||
#include <Stream.h>
|
||||
#include <Processes.h>
|
||||
|
||||
class MacSerialStream : public Stream
|
||||
{
|
||||
@ -16,12 +17,14 @@ class MacSerialStream : public Stream
|
||||
|
||||
short outRefNum, inRefNum;
|
||||
public:
|
||||
virtual void send(const Block& b) override;
|
||||
virtual void write(const void* p, size_t n) override;
|
||||
|
||||
void idle();
|
||||
|
||||
MacSerialStream();
|
||||
~MacSerialStream();
|
||||
|
||||
void close();
|
||||
};
|
||||
|
||||
MacSerialStream::MacSerialStream()
|
||||
@ -40,30 +43,38 @@ MacSerialStream::MacSerialStream()
|
||||
SerReset(outRefNum, baud19200 | data8 | noParity | stop10);
|
||||
}
|
||||
|
||||
MacSerialStream::~MacSerialStream()
|
||||
void MacSerialStream::close()
|
||||
{
|
||||
if(inRefNum == 0)
|
||||
return;
|
||||
SerSetBuf(inRefNum, NULL, 0);
|
||||
|
||||
CloseDriver(inRefNum);
|
||||
CloseDriver(outRefNum);
|
||||
inRefNum = outRefNum = 0;
|
||||
}
|
||||
|
||||
void MacSerialStream::send(const Block& b)
|
||||
MacSerialStream::~MacSerialStream()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void MacSerialStream::write(const void* p, size_t n)
|
||||
{
|
||||
ParamBlockRec pb;
|
||||
memset(&pb, 0, sizeof(pb));
|
||||
pb.ioParam.ioRefNum = outRefNum;
|
||||
pb.ioParam.ioBuffer = (Ptr)b.begin();
|
||||
pb.ioParam.ioReqCount = b.size();
|
||||
pb.ioParam.ioBuffer = (Ptr)p;
|
||||
pb.ioParam.ioReqCount = n;
|
||||
OSErr err = PBWriteSync(&pb);
|
||||
|
||||
}
|
||||
|
||||
void MacSerialStream::idle()
|
||||
{
|
||||
long count = 0;
|
||||
SerGetBuf(inRefNum, &count);
|
||||
|
||||
if(count)
|
||||
printf("sergetbuf -> %ld\n", count);
|
||||
while(count > 0)
|
||||
{
|
||||
long count1 = count > kReadBufferSize ? kReadBufferSize : count;
|
||||
@ -77,18 +88,102 @@ void MacSerialStream::idle()
|
||||
return;
|
||||
count -= count1;
|
||||
|
||||
onReceive(Block((uint8_t*)readBuffer, count1));
|
||||
printf("onReceive: %ld\n", count1);
|
||||
onReceive((uint8_t*)readBuffer, count1);
|
||||
Delay(20,nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
class DumpToConsole : public StreamListener
|
||||
{
|
||||
public:
|
||||
void onReceive(const Block& b)
|
||||
size_t onReceive(const uint8_t* p, size_t n)
|
||||
{
|
||||
for(uint8_t c : b)
|
||||
putchar(c);
|
||||
for(int i = 0; i < n; i++)
|
||||
putchar(p[i]);
|
||||
return n;
|
||||
}
|
||||
};*/
|
||||
|
||||
class Listener : public StreamListener
|
||||
{
|
||||
uint32_t size;
|
||||
short refNum;
|
||||
public:
|
||||
enum class State
|
||||
{
|
||||
dataSize,
|
||||
data,
|
||||
rsrcSize,
|
||||
rsrc,
|
||||
launch,
|
||||
stop
|
||||
};
|
||||
State state = State::dataSize;
|
||||
|
||||
|
||||
size_t onReceive(const uint8_t* p, size_t n)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case State::dataSize:
|
||||
{
|
||||
if(n < 4)
|
||||
return 0;
|
||||
size = *(const uint32_t*)p;
|
||||
|
||||
printf("Data Size: %u\n", size);
|
||||
|
||||
FSDelete("\pRetro68App", 0);
|
||||
Create("\pRetro68App", 0, '????', 'APPL');
|
||||
OpenDF("\pRetro68App", 0, &refNum);
|
||||
state = State::data;
|
||||
return 4 + onReceive(p+4, n-4);
|
||||
}
|
||||
|
||||
case State::data:
|
||||
{
|
||||
long count = n < size ? n : size;
|
||||
|
||||
FSWrite(refNum, &count, p);
|
||||
if(count < size)
|
||||
return count;
|
||||
FSClose(refNum);
|
||||
state = State::rsrcSize;
|
||||
return count;
|
||||
}
|
||||
|
||||
case State::rsrcSize:
|
||||
{
|
||||
if(n < 4)
|
||||
return 0;
|
||||
size = *(const uint32_t*)p;
|
||||
|
||||
printf("Rsrc Size: %u\n", size);
|
||||
|
||||
OpenRF("\pRetro68App", 0, &refNum);
|
||||
state = State::rsrc;
|
||||
return 4;
|
||||
}
|
||||
|
||||
case State::rsrc:
|
||||
{
|
||||
long count = n < size ? n : size;
|
||||
|
||||
FSWrite(refNum, &count, p);
|
||||
if(count < size)
|
||||
{
|
||||
size -= count;
|
||||
return count;
|
||||
}
|
||||
FSClose(refNum);
|
||||
|
||||
|
||||
state = State::launch;
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -101,11 +196,35 @@ int main()
|
||||
|
||||
{
|
||||
MacSerialStream stream;
|
||||
DumpToConsole listener;
|
||||
Listener listener;
|
||||
stream.setListener(&listener);
|
||||
|
||||
while(!Button())
|
||||
{
|
||||
stream.idle();
|
||||
|
||||
if(listener.state == Listener::State::launch)
|
||||
{
|
||||
stream.close();
|
||||
{
|
||||
LaunchParamBlockRec lpb;
|
||||
memset(&lpb, 0, sizeof(lpb));
|
||||
|
||||
lpb.reserved1 = (unsigned long) "\pRetro68App";
|
||||
lpb.reserved2 = 0;
|
||||
lpb.launchBlockID = extendedBlock;
|
||||
lpb.launchEPBLength = 6;
|
||||
lpb.launchFileFlags = 0;
|
||||
lpb.launchControlFlags = 0xC000;
|
||||
|
||||
printf("Launching...\n");
|
||||
OSErr err = LaunchApplication(&lpb);
|
||||
printf("Still here after launch (err = %d). Press Enter to exit.\n", (int)err);
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user