Merge pull request #146 from OFFTKP/panda-1

Add /step http server command
This commit is contained in:
wheremyfoodat 2023-07-28 13:51:54 +03:00 committed by GitHub
commit 9a71713b56
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 80 additions and 5 deletions

View file

@ -13,7 +13,7 @@
#include "helpers.hpp"
enum class HttpActionType { None, Screenshot, Key, TogglePause, Reset, LoadRom };
enum class HttpActionType { None, Screenshot, Key, TogglePause, Reset, LoadRom, Step };
class Emulator;
namespace httplib {
@ -46,6 +46,7 @@ class HttpAction {
static std::unique_ptr<HttpAction> createLoadRomAction(DeferredResponseWrapper& response, const std::filesystem::path& path, bool paused);
static std::unique_ptr<HttpAction> createTogglePauseAction();
static std::unique_ptr<HttpAction> createResetAction();
static std::unique_ptr<HttpAction> createStepAction(DeferredResponseWrapper& response, int frames);
};
struct HttpServer {
@ -62,9 +63,11 @@ struct HttpServer {
std::thread httpServerThread;
std::queue<std::unique_ptr<HttpAction>> actionQueue;
std::mutex actionQueueMutex;
std::unique_ptr<HttpAction> currentStepAction {};
std::map<std::string, u32> keyMap;
bool paused = false;
int framesToRun = 0;
void startHttpServer();
void pushAction(std::unique_ptr<HttpAction> action);

View file

@ -55,6 +55,18 @@ class HttpActionLoadRom : public HttpAction {
bool getPaused() const { return paused; }
};
class HttpActionStep : public HttpAction {
DeferredResponseWrapper& response;
int frames;
public:
HttpActionStep(DeferredResponseWrapper& response, int frames)
: HttpAction(HttpActionType::Step), response(response), frames(frames) {}
DeferredResponseWrapper& getResponse() { return response; }
int getFrames() const { return frames; }
};
std::unique_ptr<HttpAction> HttpAction::createScreenshotAction(DeferredResponseWrapper& response) {
return std::make_unique<HttpActionScreenshot>(response);
}
@ -67,6 +79,10 @@ std::unique_ptr<HttpAction> HttpAction::createLoadRomAction(DeferredResponseWrap
return std::make_unique<HttpActionLoadRom>(response, path, paused);
}
std::unique_ptr<HttpAction> HttpAction::createStepAction(DeferredResponseWrapper& response, int frames) {
return std::make_unique<HttpActionStep>(response, frames);
}
HttpServer::HttpServer(Emulator* emulator)
: emulator(emulator), server(std::make_unique<httplib::Server>()), keyMap({
{"A", {HID::Keys::A}},
@ -99,6 +115,7 @@ void HttpServer::pushAction(std::unique_ptr<HttpAction> action) {
}
void HttpServer::startHttpServer() {
server->set_tcp_nodelay(true);
server->Get("/ping", [](const httplib::Request&, httplib::Response& response) { response.set_content("pong", "text/plain"); });
server->Get("/screen", [this](const httplib::Request&, httplib::Response& response) {
@ -135,9 +152,30 @@ void HttpServer::startHttpServer() {
response.set_content(ok ? "ok" : "error", "text/plain");
});
server->Get("/step", [this](const httplib::Request&, httplib::Response& response) {
// TODO: implement /step
response.set_content("ok", "text/plain");
server->Get("/step", [this](const httplib::Request& request, httplib::Response& response) {
auto it = request.params.find("frames");
if (it == request.params.end()) {
response.set_content("error", "text/plain");
return;
}
int frames;
try {
frames = std::stoi(it->second);
} catch (...) {
response.set_content("error", "text/plain");
return;
}
if (frames <= 0) {
response.set_content("error", "text/plain");
return;
}
DeferredResponseWrapper wrapper(response);
std::unique_lock lock(wrapper.mutex);
pushAction(HttpAction::createStepAction(wrapper, frames));
wrapper.cv.wait(lock, [&wrapper] { return wrapper.ready; });
});
server->Get("/status", [this](const httplib::Request&, httplib::Response& response) { response.set_content(status(), "text/plain"); });
@ -171,7 +209,6 @@ void HttpServer::startHttpServer() {
DeferredResponseWrapper wrapper(response);
std::unique_lock lock(wrapper.mutex);
pushAction(HttpAction::createLoadRomAction(wrapper, romPath, paused));
response.set_content("ok", "text/plain");
wrapper.cv.wait(lock, [&wrapper] { return wrapper.ready; });
});
@ -209,6 +246,31 @@ std::string HttpServer::status() {
void HttpServer::processActions() {
std::scoped_lock lock(actionQueueMutex);
if (framesToRun > 0) {
if (!currentStepAction) {
// Should never happen
printf("framesToRun > 0 but no currentStepAction\n");
return;
}
emulator->resume();
framesToRun--;
if (framesToRun == 0) {
paused = true;
emulator->pause();
DeferredResponseWrapper& response = reinterpret_cast<HttpActionStep*>(currentStepAction.get())->getResponse();
response.inner_response.set_content("ok", "text/plain");
std::unique_lock<std::mutex> lock(response.mutex);
response.ready = true;
response.cv.notify_one();
}
// Don't process more actions until we're done stepping
return;
}
HIDService& hid = emulator->kernel.getServiceManager().getHID();
while (!actionQueue.empty()) {
@ -253,6 +315,7 @@ void HttpServer::processActions() {
if (loaded) {
paused = loadRomAction->getPaused();
framesToRun = 0;
if (paused) {
emulator->pause();
} else {
@ -263,11 +326,20 @@ void HttpServer::processActions() {
}
case HttpActionType::TogglePause:
framesToRun = 0;
emulator->togglePause();
paused = !paused;
break;
case HttpActionType::Reset: emulator->reset(Emulator::ReloadOption::Reload); break;
case HttpActionType::Step: {
HttpActionStep* stepAction = static_cast<HttpActionStep*>(action.get());
framesToRun = stepAction->getFrames();
currentStepAction = std::move(action);
break;
}
default: break;
}
}