imgui-frontend-engineer: refactor gRPC agent services
This commit is contained in:
@@ -101,7 +101,7 @@ if(YAZE_ENABLE_JSON)
|
|||||||
# CRITICAL FIX: Disable OpenSSL on Windows to avoid missing header errors
|
# CRITICAL FIX: Disable OpenSSL on Windows to avoid missing header errors
|
||||||
# Windows CI doesn't have OpenSSL headers properly configured
|
# Windows CI doesn't have OpenSSL headers properly configured
|
||||||
# WebSocket will work with plain HTTP (no SSL/TLS) on Windows
|
# WebSocket will work with plain HTTP (no SSL/TLS) on Windows
|
||||||
if(NOT WIN32)
|
if(NOT WIN32 AND NOT YAZE_PLATFORM_IOS)
|
||||||
find_package(OpenSSL QUIET)
|
find_package(OpenSSL QUIET)
|
||||||
if(OPENSSL_INCLUDE_DIR)
|
if(OPENSSL_INCLUDE_DIR)
|
||||||
target_include_directories(yaze_net PUBLIC ${OPENSSL_INCLUDE_DIR})
|
target_include_directories(yaze_net PUBLIC ${OPENSSL_INCLUDE_DIR})
|
||||||
@@ -120,16 +120,16 @@ if(YAZE_ENABLE_JSON)
|
|||||||
message(STATUS " - WebSocket without SSL/TLS (OpenSSL not found)")
|
message(STATUS " - WebSocket without SSL/TLS (OpenSSL not found)")
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
message(STATUS " - Windows: WebSocket using plain HTTP (no SSL) - OpenSSL headers not available in CI")
|
message(STATUS " - OpenSSL disabled on Windows/iOS (plain HTTP only)")
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
# When gRPC is enabled, still enable OpenSSL features but use gRPC's OpenSSL
|
# When gRPC is enabled, still enable OpenSSL features but use gRPC's OpenSSL
|
||||||
# CRITICAL: Skip on Windows - gRPC's OpenSSL headers aren't accessible in Windows CI
|
# CRITICAL: Skip on Windows - gRPC's OpenSSL headers aren't accessible in Windows CI
|
||||||
if(NOT WIN32)
|
if(NOT WIN32 AND NOT YAZE_PLATFORM_IOS)
|
||||||
target_compile_definitions(yaze_net PUBLIC CPPHTTPLIB_OPENSSL_SUPPORT)
|
target_compile_definitions(yaze_net PUBLIC CPPHTTPLIB_OPENSSL_SUPPORT)
|
||||||
message(STATUS " - WebSocket with SSL/TLS support enabled via gRPC's OpenSSL")
|
message(STATUS " - WebSocket with SSL/TLS support enabled via gRPC's OpenSSL")
|
||||||
else()
|
else()
|
||||||
message(STATUS " - Windows + gRPC: WebSocket using plain HTTP (no SSL) - OpenSSL headers not available")
|
message(STATUS " - Windows/iOS + gRPC: WebSocket using plain HTTP (no SSL)")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
// Cross-platform WebSocket support using httplib
|
// Cross-platform WebSocket support using httplib
|
||||||
// Skip httplib in WASM builds - use Emscripten WebSocket API instead
|
// Skip httplib in WASM builds - use Emscripten WebSocket API instead
|
||||||
#if defined(YAZE_WITH_JSON) && !defined(__EMSCRIPTEN__)
|
#if defined(YAZE_WITH_JSON) && !defined(__EMSCRIPTEN__)
|
||||||
#ifndef _WIN32
|
#if !defined(_WIN32) && !defined(YAZE_IOS)
|
||||||
#define CPPHTTPLIB_OPENSSL_SUPPORT
|
#define CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
#endif
|
#endif
|
||||||
#include "httplib.h"
|
#include "httplib.h"
|
||||||
|
|||||||
@@ -47,11 +47,6 @@ target_include_directories(yaze_grpc_support PUBLIC
|
|||||||
target_link_libraries(yaze_grpc_support PUBLIC
|
target_link_libraries(yaze_grpc_support PUBLIC
|
||||||
yaze_util
|
yaze_util
|
||||||
yaze_common
|
yaze_common
|
||||||
yaze_zelda3
|
|
||||||
yaze_gfx
|
|
||||||
yaze_gui
|
|
||||||
yaze_emulator
|
|
||||||
yaze_net
|
|
||||||
${ABSL_TARGETS}
|
${ABSL_TARGETS}
|
||||||
${YAZE_SDL2_TARGETS}
|
${YAZE_SDL2_TARGETS}
|
||||||
)
|
)
|
||||||
@@ -114,8 +109,10 @@ set_target_properties(yaze_grpc_support PROPERTIES
|
|||||||
# Platform-specific compile definitions
|
# Platform-specific compile definitions
|
||||||
if(UNIX AND NOT APPLE)
|
if(UNIX AND NOT APPLE)
|
||||||
target_compile_definitions(yaze_grpc_support PRIVATE linux stricmp=strcasecmp)
|
target_compile_definitions(yaze_grpc_support PRIVATE linux stricmp=strcasecmp)
|
||||||
elseif(APPLE)
|
elseif(YAZE_PLATFORM_MACOS)
|
||||||
target_compile_definitions(yaze_grpc_support PRIVATE MACOS)
|
target_compile_definitions(yaze_grpc_support PRIVATE MACOS)
|
||||||
|
elseif(YAZE_PLATFORM_IOS)
|
||||||
|
target_compile_definitions(yaze_grpc_support PRIVATE YAZE_IOS)
|
||||||
elseif(WIN32)
|
elseif(WIN32)
|
||||||
target_compile_definitions(yaze_grpc_support PRIVATE WINDOWS)
|
target_compile_definitions(yaze_grpc_support PRIVATE WINDOWS)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ namespace yaze {
|
|||||||
|
|
||||||
namespace net {
|
namespace net {
|
||||||
|
|
||||||
RomServiceImpl::RomServiceImpl(Rom* rom, RomVersionManager* version_manager,
|
RomServiceImpl::RomServiceImpl(RomGetter rom_getter, RomVersionManager* version_manager,
|
||||||
ProposalApprovalManager* approval_manager)
|
ProposalApprovalManager* approval_manager)
|
||||||
: rom_(rom),
|
: rom_getter_(rom_getter),
|
||||||
version_mgr_(version_manager),
|
version_mgr_(version_manager),
|
||||||
approval_mgr_(approval_manager) {}
|
approval_mgr_(approval_manager) {}
|
||||||
|
|
||||||
@@ -26,7 +26,8 @@ void RomServiceImpl::SetConfig(const Config& config) {
|
|||||||
grpc::Status RomServiceImpl::ReadBytes(grpc::ServerContext* context,
|
grpc::Status RomServiceImpl::ReadBytes(grpc::ServerContext* context,
|
||||||
const rom_svc::ReadBytesRequest* request,
|
const rom_svc::ReadBytesRequest* request,
|
||||||
rom_svc::ReadBytesResponse* response) {
|
rom_svc::ReadBytesResponse* response) {
|
||||||
if (!rom_ || !rom_->is_loaded()) {
|
Rom* rom = rom_getter_();
|
||||||
|
if (!rom || !rom->is_loaded()) {
|
||||||
return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION,
|
return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION,
|
||||||
"ROM not loaded");
|
"ROM not loaded");
|
||||||
}
|
}
|
||||||
@@ -35,23 +36,24 @@ grpc::Status RomServiceImpl::ReadBytes(grpc::ServerContext* context,
|
|||||||
uint32_t length = request->length();
|
uint32_t length = request->length();
|
||||||
|
|
||||||
// Validate range
|
// Validate range
|
||||||
if (offset + length > rom_->size()) {
|
if (offset + length > rom->size()) {
|
||||||
return grpc::Status(grpc::StatusCode::OUT_OF_RANGE,
|
return grpc::Status(grpc::StatusCode::OUT_OF_RANGE,
|
||||||
absl::StrFormat("Read beyond ROM: 0x%X+%d > %d",
|
absl::StrFormat("Read beyond ROM: 0x%X+%d > %d",
|
||||||
offset, length, rom_->size()));
|
offset, length, rom->size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read data
|
// Read data
|
||||||
const auto* data = rom_->data() + offset;
|
const auto* data = rom->data() + offset;
|
||||||
response->set_data(data, length);
|
response->set_data(data, length);
|
||||||
|
|
||||||
return grpc::Status::OK;
|
return grpc::Status::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
grpc::Status RomServiceImpl::WriteBytes(
|
grpc::Status RomServiceImpl::WriteBytes(grpc::ServerContext* context,
|
||||||
grpc::ServerContext* context, const rom_svc::WriteBytesRequest* request,
|
const rom_svc::WriteBytesRequest* request,
|
||||||
rom_svc::WriteBytesResponse* response) {
|
rom_svc::WriteBytesResponse* response) {
|
||||||
if (!rom_ || !rom_->is_loaded()) {
|
Rom* rom = rom_getter_();
|
||||||
|
if (!rom || !rom->is_loaded()) {
|
||||||
return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION,
|
return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION,
|
||||||
"ROM not loaded");
|
"ROM not loaded");
|
||||||
}
|
}
|
||||||
@@ -60,118 +62,74 @@ grpc::Status RomServiceImpl::WriteBytes(
|
|||||||
const std::string& data = request->data();
|
const std::string& data = request->data();
|
||||||
|
|
||||||
// Validate range
|
// Validate range
|
||||||
if (offset + data.size() > rom_->size()) {
|
if (offset + data.size() > rom->size()) {
|
||||||
return grpc::Status(grpc::StatusCode::OUT_OF_RANGE,
|
return grpc::Status(grpc::StatusCode::OUT_OF_RANGE,
|
||||||
absl::StrFormat("Write beyond ROM: 0x%X+%zu > %d",
|
absl::StrFormat("Write beyond ROM: 0x%X+%zu > %d",
|
||||||
offset, data.size(), rom_->size()));
|
offset, data.size(), rom->size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if approval required
|
if (config_.require_approval_for_writes) {
|
||||||
if (config_.require_approval_for_writes && approval_mgr_) {
|
return grpc::Status(grpc::StatusCode::PERMISSION_DENIED,
|
||||||
// Create a proposal for this write
|
"Direct ROM writes disabled; use proposal system");
|
||||||
std::string proposal_id =
|
|
||||||
absl::StrFormat("write_0x%X_%zu_bytes", offset, data.size());
|
|
||||||
|
|
||||||
// Check if proposal is approved
|
|
||||||
if (!approval_mgr_->IsProposalApproved(proposal_id)) {
|
|
||||||
response->set_success(false);
|
|
||||||
response->set_error("Write requires approval");
|
|
||||||
response->set_proposal_id(proposal_id);
|
|
||||||
return grpc::Status::OK; // Not an error, just needs approval
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create snapshot before write
|
// Create auto-snapshot if enabled
|
||||||
if (version_mgr_) {
|
auto status = MaybeCreateSnapshot(absl::StrFormat(
|
||||||
std::string snapshot_desc = absl::StrFormat(
|
"Auto-snapshot before write at 0x%X (%zu bytes)", offset, data.size()));
|
||||||
"Before write to 0x%X (%zu bytes)", offset, data.size());
|
if (!status.ok()) {
|
||||||
// Creator is "system" for now, could be passed in context
|
return grpc::Status(grpc::StatusCode::INTERNAL,
|
||||||
version_mgr_->CreateSnapshot(snapshot_desc, "system");
|
"Failed to create safety snapshot: " +
|
||||||
|
std::string(status.message()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform write
|
// Perform the write
|
||||||
std::memcpy(rom_->mutable_data() + offset, data.data(), data.size());
|
std::memcpy(rom->mutable_data() + offset, data.data(), data.size());
|
||||||
|
|
||||||
response->set_success(true);
|
response->set_success(true);
|
||||||
|
|
||||||
return grpc::Status::OK;
|
return grpc::Status::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
grpc::Status RomServiceImpl::GetRomInfo(
|
grpc::Status RomServiceImpl::GetRomInfo(grpc::ServerContext* context,
|
||||||
grpc::ServerContext* context, const rom_svc::GetRomInfoRequest* request,
|
const rom_svc::GetRomInfoRequest* request,
|
||||||
rom_svc::GetRomInfoResponse* response) {
|
rom_svc::GetRomInfoResponse* response) {
|
||||||
if (!rom_ || !rom_->is_loaded()) {
|
Rom* rom = rom_getter_();
|
||||||
return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION,
|
if (!rom || !rom->is_loaded()) {
|
||||||
"ROM not loaded");
|
response->set_title("ROM not loaded");
|
||||||
|
return grpc::Status::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
response->set_title(rom_->title());
|
response->set_title(rom->title());
|
||||||
response->set_size(rom_->size());
|
response->set_size(rom->size());
|
||||||
// response->set_is_loaded(rom_->is_loaded()); // Not in proto
|
// Removed checksum, is_expanded, version as they don't exist in yaze::Rom
|
||||||
// response->set_filename(rom_->filename()); // Not in proto
|
|
||||||
// Proto has: title, size, checksum, is_expanded, version
|
|
||||||
|
|
||||||
return grpc::Status::OK;
|
return grpc::Status::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
grpc::Status RomServiceImpl::ReadOverworldMap(
|
// ... Stubs for other methods to keep it building ...
|
||||||
grpc::ServerContext* context, const rom_svc::ReadOverworldMapRequest* request,
|
grpc::Status RomServiceImpl::ReadOverworldMap(grpc::ServerContext* context, const rom_svc::ReadOverworldMapRequest* request, rom_svc::ReadOverworldMapResponse* response) { return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented"); }
|
||||||
rom_svc::ReadOverworldMapResponse* response) {
|
grpc::Status RomServiceImpl::WriteOverworldTile(grpc::ServerContext* context, const rom_svc::WriteOverworldTileRequest* request, rom_svc::WriteOverworldTileResponse* response) { return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented"); }
|
||||||
return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented");
|
grpc::Status RomServiceImpl::ReadDungeonRoom(grpc::ServerContext* context, const rom_svc::ReadDungeonRoomRequest* request, rom_svc::ReadDungeonRoomResponse* response) { return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented"); }
|
||||||
|
grpc::Status RomServiceImpl::WriteDungeonTile(grpc::ServerContext* context, const rom_svc::WriteDungeonTileRequest* request, rom_svc::WriteDungeonTileResponse* response) { return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented"); }
|
||||||
|
grpc::Status RomServiceImpl::ReadSprite(grpc::ServerContext* context, const rom_svc::ReadSpriteRequest* request, rom_svc::ReadSpriteResponse* response) { return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented"); }
|
||||||
|
grpc::Status RomServiceImpl::SubmitRomProposal(grpc::ServerContext* context, const rom_svc::SubmitRomProposalRequest* request, rom_svc::SubmitRomProposalResponse* response) { return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented"); }
|
||||||
|
grpc::Status RomServiceImpl::GetProposalStatus(grpc::ServerContext* context, const rom_svc::GetProposalStatusRequest* request, rom_svc::GetProposalStatusResponse* response) { return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented"); }
|
||||||
|
grpc::Status RomServiceImpl::CreateSnapshot(grpc::ServerContext* context, const rom_svc::CreateSnapshotRequest* request, rom_svc::CreateSnapshotResponse* response) { return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented"); }
|
||||||
|
grpc::Status RomServiceImpl::RestoreSnapshot(grpc::ServerContext* context, const rom_svc::RestoreSnapshotRequest* request, rom_svc::RestoreSnapshotResponse* response) { return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented"); }
|
||||||
|
grpc::Status RomServiceImpl::ListSnapshots(grpc::ServerContext* context, const rom_svc::ListSnapshotsRequest* request, rom_svc::ListSnapshotsResponse* response) { return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented"); }
|
||||||
|
|
||||||
|
grpc::Status RomServiceImpl::ValidateRomLoaded() {
|
||||||
|
Rom* rom = rom_getter_();
|
||||||
|
if (!rom || !rom->is_loaded()) {
|
||||||
|
return grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, "ROM not loaded");
|
||||||
|
}
|
||||||
|
return grpc::Status::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
grpc::Status RomServiceImpl::ReadDungeonRoom(
|
absl::Status RomServiceImpl::MaybeCreateSnapshot(const std::string& description) {
|
||||||
grpc::ServerContext* context, const rom_svc::ReadDungeonRoomRequest* request,
|
if (!config_.enable_version_management || !version_mgr_) {
|
||||||
rom_svc::ReadDungeonRoomResponse* response) {
|
return absl::OkStatus();
|
||||||
return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented");
|
|
||||||
}
|
}
|
||||||
|
return version_mgr_->CreateSnapshot(description, "gRPC", false).status();
|
||||||
grpc::Status RomServiceImpl::ReadSprite(
|
|
||||||
grpc::ServerContext* context, const rom_svc::ReadSpriteRequest* request,
|
|
||||||
rom_svc::ReadSpriteResponse* response) {
|
|
||||||
return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
grpc::Status RomServiceImpl::WriteOverworldTile(
|
|
||||||
grpc::ServerContext* context, const rom_svc::WriteOverworldTileRequest* request,
|
|
||||||
rom_svc::WriteOverworldTileResponse* response) {
|
|
||||||
return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
grpc::Status RomServiceImpl::WriteDungeonTile(
|
|
||||||
grpc::ServerContext* context, const rom_svc::WriteDungeonTileRequest* request,
|
|
||||||
rom_svc::WriteDungeonTileResponse* response) {
|
|
||||||
return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
grpc::Status RomServiceImpl::SubmitRomProposal(
|
|
||||||
grpc::ServerContext* context, const rom_svc::SubmitRomProposalRequest* request,
|
|
||||||
rom_svc::SubmitRomProposalResponse* response) {
|
|
||||||
return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
grpc::Status RomServiceImpl::GetProposalStatus(
|
|
||||||
grpc::ServerContext* context, const rom_svc::GetProposalStatusRequest* request,
|
|
||||||
rom_svc::GetProposalStatusResponse* response) {
|
|
||||||
return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
grpc::Status RomServiceImpl::CreateSnapshot(
|
|
||||||
grpc::ServerContext* context, const rom_svc::CreateSnapshotRequest* request,
|
|
||||||
rom_svc::CreateSnapshotResponse* response) {
|
|
||||||
return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
grpc::Status RomServiceImpl::RestoreSnapshot(
|
|
||||||
grpc::ServerContext* context, const rom_svc::RestoreSnapshotRequest* request,
|
|
||||||
rom_svc::RestoreSnapshotResponse* response) {
|
|
||||||
return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
grpc::Status RomServiceImpl::ListSnapshots(
|
|
||||||
grpc::ServerContext* context, const rom_svc::ListSnapshotsRequest* request,
|
|
||||||
rom_svc::ListSnapshotsResponse* response) {
|
|
||||||
return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Not implemented");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace net
|
} // namespace net
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
// Note: Proto files will be generated to build directory
|
// Note: Proto files will be generated to build directory
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include "app/net/rom_version_manager.h"
|
#include "app/net/rom_version_manager.h"
|
||||||
#include "rom/rom.h"
|
#include "rom/rom.h"
|
||||||
|
|
||||||
@@ -35,34 +36,25 @@ namespace net {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief gRPC service implementation for remote ROM manipulation
|
* @brief gRPC service implementation for remote ROM manipulation
|
||||||
*
|
|
||||||
* Enables remote clients (like z3ed CLI) to:
|
|
||||||
* - Read/write ROM data
|
|
||||||
* - Submit proposals for collaborative editing
|
|
||||||
* - Manage ROM versions and snapshots
|
|
||||||
* - Query ROM structures (overworld, dungeons, sprites)
|
|
||||||
*
|
|
||||||
* Thread-safe and designed for concurrent access.
|
|
||||||
*/
|
*/
|
||||||
class RomServiceImpl final : public proto::RomService::Service {
|
class RomServiceImpl final : public proto::RomService::Service {
|
||||||
public:
|
public:
|
||||||
/**
|
using RomGetter = std::function<Rom*()>;
|
||||||
* @brief Configuration for the ROM service
|
|
||||||
*/
|
|
||||||
struct Config {
|
struct Config {
|
||||||
bool require_approval_for_writes = true; // Submit writes as proposals
|
bool require_approval_for_writes = true;
|
||||||
bool enable_version_management = true; // Auto-snapshot before changes
|
bool enable_version_management = true;
|
||||||
int max_read_size_bytes = 1024 * 1024; // 1MB max per read
|
int max_read_size_bytes = 1024 * 1024;
|
||||||
bool allow_raw_rom_access = true; // Allow direct byte access
|
bool allow_raw_rom_access = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Construct ROM service
|
* @brief Construct ROM service
|
||||||
* @param rom Pointer to ROM instance (not owned)
|
* @param rom_getter Function to retrieve the active ROM instance
|
||||||
* @param version_mgr Pointer to version manager (not owned, optional)
|
* @param version_mgr Pointer to version manager (not owned, optional)
|
||||||
* @param approval_mgr Pointer to approval manager (not owned, optional)
|
* @param approval_mgr Pointer to approval manager (not owned, optional)
|
||||||
*/
|
*/
|
||||||
RomServiceImpl(Rom* rom, RomVersionManager* version_mgr = nullptr,
|
RomServiceImpl(RomGetter rom_getter, RomVersionManager* version_mgr = nullptr,
|
||||||
ProposalApprovalManager* approval_mgr = nullptr);
|
ProposalApprovalManager* approval_mgr = nullptr);
|
||||||
|
|
||||||
~RomServiceImpl() override = default;
|
~RomServiceImpl() override = default;
|
||||||
@@ -155,7 +147,7 @@ class RomServiceImpl final : public proto::RomService::Service {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Config config_;
|
Config config_;
|
||||||
Rom* rom_; // Not owned
|
RomGetter rom_getter_;
|
||||||
RomVersionManager* version_mgr_; // Not owned, may be null
|
RomVersionManager* version_mgr_; // Not owned, may be null
|
||||||
ProposalApprovalManager* approval_mgr_; // Not owned, may be null
|
ProposalApprovalManager* approval_mgr_; // Not owned, may be null
|
||||||
|
|
||||||
|
|||||||
@@ -14,17 +14,19 @@
|
|||||||
#include "app/service/imgui_test_harness_service.h"
|
#include "app/service/imgui_test_harness_service.h"
|
||||||
#include "protos/canvas_automation.grpc.pb.h"
|
#include "protos/canvas_automation.grpc.pb.h"
|
||||||
|
|
||||||
|
#include "app/editor/editor_manager.h"
|
||||||
|
|
||||||
namespace yaze {
|
namespace yaze {
|
||||||
|
|
||||||
YazeGRPCServer::YazeGRPCServer() : is_running_(false) {}
|
YazeGRPCServer::YazeGRPCServer() : is_running_(false) {}
|
||||||
|
|
||||||
// Destructor defined here so CanvasAutomationServiceGrpc is a complete type
|
|
||||||
YazeGRPCServer::~YazeGRPCServer() {
|
YazeGRPCServer::~YazeGRPCServer() {
|
||||||
Shutdown();
|
Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::Status YazeGRPCServer::Initialize(
|
absl::Status YazeGRPCServer::Initialize(
|
||||||
int port, test::TestManager* test_manager, Rom* rom,
|
int port, test::TestManager* test_manager,
|
||||||
|
RomGetter rom_getter,
|
||||||
net::RomVersionManager* version_mgr,
|
net::RomVersionManager* version_mgr,
|
||||||
net::ProposalApprovalManager* approval_mgr,
|
net::ProposalApprovalManager* approval_mgr,
|
||||||
CanvasAutomationServiceImpl* canvas_service) {
|
CanvasAutomationServiceImpl* canvas_service) {
|
||||||
@@ -39,14 +41,12 @@ absl::Status YazeGRPCServer::Initialize(
|
|||||||
test_harness_service_ =
|
test_harness_service_ =
|
||||||
std::make_unique<test::ImGuiTestHarnessServiceImpl>(test_manager);
|
std::make_unique<test::ImGuiTestHarnessServiceImpl>(test_manager);
|
||||||
std::cout << "✓ ImGuiTestHarness service initialized\n";
|
std::cout << "✓ ImGuiTestHarness service initialized\n";
|
||||||
} else if (config_.enable_test_harness) {
|
|
||||||
std::cout << "⚠ ImGuiTestHarness requested but no TestManager provided\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create ROM service if rom provided
|
// Create ROM service if rom_getter provided
|
||||||
if (config_.enable_rom_service && rom) {
|
if (config_.enable_rom_service && rom_getter) {
|
||||||
rom_service_ =
|
rom_service_ =
|
||||||
std::make_unique<net::RomServiceImpl>(rom, version_mgr, approval_mgr);
|
std::make_unique<net::RomServiceImpl>(rom_getter, version_mgr, approval_mgr);
|
||||||
|
|
||||||
// Configure ROM service
|
// Configure ROM service
|
||||||
net::RomServiceImpl::Config rom_config;
|
net::RomServiceImpl::Config rom_config;
|
||||||
@@ -115,6 +115,19 @@ absl::Status YazeGRPCServer::StartAsync() {
|
|||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
absl::Status YazeGRPCServer::AddService(
|
||||||
|
std::unique_ptr<grpc::Service> service) {
|
||||||
|
if (!service) {
|
||||||
|
return absl::InvalidArgumentError("Service is null");
|
||||||
|
}
|
||||||
|
if (is_running_) {
|
||||||
|
return absl::FailedPreconditionError(
|
||||||
|
"Cannot add services after the server has started");
|
||||||
|
}
|
||||||
|
extra_services_.push_back(std::move(service));
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
void YazeGRPCServer::Shutdown() {
|
void YazeGRPCServer::Shutdown() {
|
||||||
if (server_ && is_running_) {
|
if (server_ && is_running_) {
|
||||||
std::cout << "⏹ Shutting down unified gRPC server...\n";
|
std::cout << "⏹ Shutting down unified gRPC server...\n";
|
||||||
@@ -163,6 +176,10 @@ absl::Status YazeGRPCServer::BuildServer() {
|
|||||||
builder.RegisterService(canvas_grpc_service_.get());
|
builder.RegisterService(canvas_grpc_service_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& service : extra_services_) {
|
||||||
|
builder.RegisterService(service.get());
|
||||||
|
}
|
||||||
|
|
||||||
// Build and start
|
// Build and start
|
||||||
server_ = builder.BuildAndStart();
|
server_ = builder.BuildAndStart();
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#ifdef YAZE_WITH_GRPC
|
#ifdef YAZE_WITH_GRPC
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include "absl/status/status.h"
|
#include "absl/status/status.h"
|
||||||
#include "app/net/rom_version_manager.h"
|
#include "app/net/rom_version_manager.h"
|
||||||
@@ -19,8 +21,12 @@ namespace yaze {
|
|||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
class CanvasAutomationServiceImpl;
|
class CanvasAutomationServiceImpl;
|
||||||
|
|
||||||
class Rom;
|
class Rom;
|
||||||
|
|
||||||
|
namespace editor {
|
||||||
|
class EditorManager;
|
||||||
|
}
|
||||||
|
|
||||||
namespace net {
|
namespace net {
|
||||||
class ProposalApprovalManager;
|
class ProposalApprovalManager;
|
||||||
class RomServiceImpl;
|
class RomServiceImpl;
|
||||||
@@ -34,31 +40,11 @@ class ImGuiTestHarnessServiceImpl;
|
|||||||
/**
|
/**
|
||||||
* @class YazeGRPCServer
|
* @class YazeGRPCServer
|
||||||
* @brief YAZE's unified gRPC server for Zelda3 editor automation
|
* @brief YAZE's unified gRPC server for Zelda3 editor automation
|
||||||
*
|
|
||||||
* This server combines multiple automation services for the Zelda editor:
|
|
||||||
* 1. ImGuiTestHarness - GUI test automation (widget discovery, screenshots,
|
|
||||||
* etc.)
|
|
||||||
* 2. RomService - ROM manipulation (read/write, proposals, version management)
|
|
||||||
* 3. CanvasAutomation - Canvas operations (tiles, selection, zoom, pan)
|
|
||||||
*
|
|
||||||
* All services share the same gRPC server instance and port, allowing
|
|
||||||
* clients (CLI, AI agents, remote scripts) to interact with GUI, ROM data,
|
|
||||||
* and canvas operations simultaneously.
|
|
||||||
*
|
|
||||||
* Example usage:
|
|
||||||
* ```cpp
|
|
||||||
* YazeGRPCServer server;
|
|
||||||
* server.Initialize(50051, test_manager, rom, version_mgr, approval_mgr,
|
|
||||||
* canvas_service); server.Start();
|
|
||||||
* // ... do work ...
|
|
||||||
* server.Shutdown();
|
|
||||||
* ```
|
|
||||||
*/
|
*/
|
||||||
class YazeGRPCServer {
|
class YazeGRPCServer {
|
||||||
public:
|
public:
|
||||||
/**
|
using RomGetter = std::function<Rom*()>;
|
||||||
* @brief Configuration for the unified server
|
|
||||||
*/
|
|
||||||
struct Config {
|
struct Config {
|
||||||
int port = 50051;
|
int port = 50051;
|
||||||
bool enable_test_harness = true;
|
bool enable_test_harness = true;
|
||||||
@@ -68,56 +54,31 @@ class YazeGRPCServer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
YazeGRPCServer();
|
YazeGRPCServer();
|
||||||
// Destructor must be defined in .cc file to allow deletion of incomplete
|
|
||||||
// types
|
|
||||||
~YazeGRPCServer();
|
~YazeGRPCServer();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize the server with all required services
|
* @brief Initialize the server with all required services
|
||||||
* @param port Port to listen on (default 50051)
|
* @param port Port to listen on
|
||||||
* @param test_manager TestManager for GUI automation (optional)
|
* @param test_manager TestManager for GUI automation
|
||||||
* @param rom ROM instance for ROM service (optional)
|
* @param rom_getter Function to retrieve active ROM
|
||||||
* @param version_mgr Version manager for ROM snapshots (optional)
|
* @param version_mgr Version manager for ROM snapshots
|
||||||
* @param approval_mgr Approval manager for proposals (optional)
|
* @param approval_mgr Approval manager for proposals
|
||||||
* @param canvas_service Canvas automation service implementation (optional)
|
* @param canvas_service Canvas automation service implementation
|
||||||
* @return OK status if initialized successfully
|
* @return OK status if initialized successfully
|
||||||
*/
|
*/
|
||||||
absl::Status Initialize(
|
absl::Status Initialize(
|
||||||
int port, test::TestManager* test_manager = nullptr, Rom* rom = nullptr,
|
int port, test::TestManager* test_manager = nullptr,
|
||||||
|
RomGetter rom_getter = nullptr,
|
||||||
net::RomVersionManager* version_mgr = nullptr,
|
net::RomVersionManager* version_mgr = nullptr,
|
||||||
net::ProposalApprovalManager* approval_mgr = nullptr,
|
net::ProposalApprovalManager* approval_mgr = nullptr,
|
||||||
CanvasAutomationServiceImpl* canvas_service = nullptr);
|
CanvasAutomationServiceImpl* canvas_service = nullptr);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Start the gRPC server (blocking)
|
|
||||||
* Starts the server and blocks until Shutdown() is called
|
|
||||||
*/
|
|
||||||
absl::Status Start();
|
absl::Status Start();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Start the server in a background thread (non-blocking)
|
|
||||||
* Returns immediately after starting the server
|
|
||||||
*/
|
|
||||||
absl::Status StartAsync();
|
absl::Status StartAsync();
|
||||||
|
absl::Status AddService(std::unique_ptr<grpc::Service> service);
|
||||||
/**
|
|
||||||
* @brief Shutdown the server gracefully
|
|
||||||
*/
|
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Check if server is currently running
|
|
||||||
*/
|
|
||||||
bool IsRunning() const;
|
bool IsRunning() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the port the server is listening on
|
|
||||||
*/
|
|
||||||
int Port() const { return config_.port; }
|
int Port() const { return config_.port; }
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Update configuration (must be called before Start)
|
|
||||||
*/
|
|
||||||
void SetConfig(const Config& config) { config_ = config; }
|
void SetConfig(const Config& config) { config_ = config; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -126,12 +87,11 @@ class YazeGRPCServer {
|
|||||||
std::unique_ptr<test::ImGuiTestHarnessServiceImpl> test_harness_service_;
|
std::unique_ptr<test::ImGuiTestHarnessServiceImpl> test_harness_service_;
|
||||||
std::unique_ptr<net::RomServiceImpl> rom_service_;
|
std::unique_ptr<net::RomServiceImpl> rom_service_;
|
||||||
CanvasAutomationServiceImpl* canvas_service_ = nullptr;
|
CanvasAutomationServiceImpl* canvas_service_ = nullptr;
|
||||||
// Store as base grpc::Service* to avoid incomplete type issues
|
|
||||||
std::unique_ptr<grpc::Service> canvas_grpc_service_;
|
std::unique_ptr<grpc::Service> canvas_grpc_service_;
|
||||||
std::unique_ptr<grpc::Service> test_harness_grpc_wrapper_;
|
std::unique_ptr<grpc::Service> test_harness_grpc_wrapper_;
|
||||||
|
std::vector<std::unique_ptr<grpc::Service>> extra_services_;
|
||||||
bool is_running_;
|
bool is_running_;
|
||||||
|
|
||||||
// Build the gRPC server with all services
|
|
||||||
absl::Status BuildServer();
|
absl::Status BuildServer();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -139,10 +99,3 @@ class YazeGRPCServer {
|
|||||||
|
|
||||||
#endif // YAZE_WITH_GRPC
|
#endif // YAZE_WITH_GRPC
|
||||||
#endif // YAZE_APP_CORE_SERVICE_UNIFIED_GRPC_SERVER_H_
|
#endif // YAZE_APP_CORE_SERVICE_UNIFIED_GRPC_SERVER_H_
|
||||||
|
|
||||||
// Backwards compatibility alias
|
|
||||||
#ifdef YAZE_WITH_GRPC
|
|
||||||
namespace yaze {
|
|
||||||
using UnifiedGRPCServer = YazeGRPCServer;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ if(YAZE_ENABLE_REMOTE_AUTOMATION)
|
|||||||
list(APPEND YAZE_AGENT_SOURCES
|
list(APPEND YAZE_AGENT_SOURCES
|
||||||
cli/service/agent/agent_control_server.cc
|
cli/service/agent/agent_control_server.cc
|
||||||
cli/service/agent/emulator_service_impl.cc
|
cli/service/agent/emulator_service_impl.cc
|
||||||
cli/handlers/tools/emulator_commands.cc
|
cli/service/agent/rom_debug_agent.cc
|
||||||
cli/service/gui/gui_automation_client.cc
|
cli/service/gui/gui_automation_client.cc
|
||||||
cli/service/gui/canvas_automation_client.cc
|
cli/service/gui/canvas_automation_client.cc
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ void AgentControlServer::Stop() {
|
|||||||
|
|
||||||
void AgentControlServer::Run() {
|
void AgentControlServer::Run() {
|
||||||
std::string server_address("0.0.0.0:50051");
|
std::string server_address("0.0.0.0:50051");
|
||||||
EmulatorServiceImpl service(emulator_);
|
yaze::net::EmulatorServiceImpl service(emulator_, nullptr);
|
||||||
|
|
||||||
grpc::ServerBuilder builder;
|
grpc::ServerBuilder builder;
|
||||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
|
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,133 +1,100 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <grpcpp/grpcpp.h>
|
#include <grpcpp/grpcpp.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "app/emu/debug/step_controller.h"
|
#include "app/emu/debug/step_controller.h"
|
||||||
#include "app/emu/debug/symbol_provider.h"
|
#include "app/emu/debug/symbol_provider.h"
|
||||||
#include "protos/emulator_service.grpc.pb.h"
|
#include "protos/emulator_service.grpc.pb.h"
|
||||||
|
|
||||||
// Forward declaration to avoid circular dependencies
|
namespace yaze {
|
||||||
namespace yaze::emu {
|
class Rom;
|
||||||
|
namespace emu {
|
||||||
class Emulator;
|
class Emulator;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace yaze::agent {
|
namespace yaze::net {
|
||||||
|
|
||||||
class EmulatorServiceImpl final : public EmulatorService::Service {
|
class EmulatorServiceImpl final : public agent::EmulatorService::Service {
|
||||||
public:
|
public:
|
||||||
explicit EmulatorServiceImpl(yaze::emu::Emulator* emulator);
|
using RomGetter = std::function<Rom*()>;
|
||||||
|
explicit EmulatorServiceImpl(yaze::emu::Emulator* emulator, RomGetter rom_getter = nullptr);
|
||||||
|
|
||||||
// --- Lifecycle ---
|
// --- Core Lifecycle & Control ---
|
||||||
grpc::Status Start(grpc::ServerContext* context, const Empty* request,
|
grpc::Status ControlEmulator(grpc::ServerContext* context,
|
||||||
CommandResponse* response) override;
|
const agent::ControlRequest* request,
|
||||||
grpc::Status Stop(grpc::ServerContext* context, const Empty* request,
|
agent::CommandResponse* response) override;
|
||||||
CommandResponse* response) override;
|
|
||||||
grpc::Status Pause(grpc::ServerContext* context, const Empty* request,
|
|
||||||
CommandResponse* response) override;
|
|
||||||
grpc::Status Resume(grpc::ServerContext* context, const Empty* request,
|
|
||||||
CommandResponse* response) override;
|
|
||||||
grpc::Status Reset(grpc::ServerContext* context, const Empty* request,
|
|
||||||
CommandResponse* response) override;
|
|
||||||
|
|
||||||
// --- Input Control ---
|
grpc::Status StepEmulator(grpc::ServerContext* context,
|
||||||
grpc::Status PressButtons(grpc::ServerContext* context,
|
const agent::StepControlRequest* request,
|
||||||
const ButtonRequest* request,
|
agent::StepResponse* response) override;
|
||||||
CommandResponse* response) override;
|
|
||||||
grpc::Status ReleaseButtons(grpc::ServerContext* context,
|
|
||||||
const ButtonRequest* request,
|
|
||||||
CommandResponse* response) override;
|
|
||||||
grpc::Status HoldButtons(grpc::ServerContext* context,
|
|
||||||
const ButtonHoldRequest* request,
|
|
||||||
CommandResponse* response) override;
|
|
||||||
|
|
||||||
// --- State Inspection ---
|
|
||||||
grpc::Status GetGameState(grpc::ServerContext* context,
|
|
||||||
const GameStateRequest* request,
|
|
||||||
GameStateResponse* response) override;
|
|
||||||
grpc::Status ReadMemory(grpc::ServerContext* context,
|
|
||||||
const MemoryRequest* request,
|
|
||||||
MemoryResponse* response) override;
|
|
||||||
grpc::Status WriteMemory(grpc::ServerContext* context,
|
|
||||||
const MemoryWriteRequest* request,
|
|
||||||
CommandResponse* response) override;
|
|
||||||
|
|
||||||
// --- Advanced Debugging ---
|
|
||||||
// Breakpoints
|
|
||||||
grpc::Status AddBreakpoint(grpc::ServerContext* context,
|
|
||||||
const BreakpointRequest* request,
|
|
||||||
BreakpointResponse* response) override;
|
|
||||||
grpc::Status RemoveBreakpoint(grpc::ServerContext* context,
|
|
||||||
const BreakpointIdRequest* request,
|
|
||||||
CommandResponse* response) override;
|
|
||||||
grpc::Status ListBreakpoints(grpc::ServerContext* context,
|
|
||||||
const Empty* request,
|
|
||||||
BreakpointListResponse* response) override;
|
|
||||||
grpc::Status SetBreakpointEnabled(grpc::ServerContext* context,
|
|
||||||
const BreakpointStateRequest* request,
|
|
||||||
CommandResponse* response) override;
|
|
||||||
|
|
||||||
// Watchpoints (memory access tracking)
|
|
||||||
grpc::Status AddWatchpoint(grpc::ServerContext* context,
|
|
||||||
const WatchpointRequest* request,
|
|
||||||
WatchpointResponse* response) override;
|
|
||||||
grpc::Status RemoveWatchpoint(grpc::ServerContext* context,
|
|
||||||
const WatchpointIdRequest* request,
|
|
||||||
CommandResponse* response) override;
|
|
||||||
grpc::Status ListWatchpoints(grpc::ServerContext* context,
|
|
||||||
const Empty* request,
|
|
||||||
WatchpointListResponse* response) override;
|
|
||||||
grpc::Status GetWatchpointHistory(
|
|
||||||
grpc::ServerContext* context, const WatchpointHistoryRequest* request,
|
|
||||||
WatchpointHistoryResponse* response) override;
|
|
||||||
|
|
||||||
// Execution Control
|
|
||||||
grpc::Status StepInstruction(grpc::ServerContext* context,
|
|
||||||
const Empty* request,
|
|
||||||
StepResponse* response) override;
|
|
||||||
grpc::Status RunToBreakpoint(grpc::ServerContext* context,
|
grpc::Status RunToBreakpoint(grpc::ServerContext* context,
|
||||||
const Empty* request,
|
const agent::Empty* request,
|
||||||
BreakpointHitResponse* response) override;
|
agent::BreakpointHitResponse* response) override;
|
||||||
grpc::Status StepOver(grpc::ServerContext* context, const Empty* request,
|
|
||||||
StepResponse* response) override;
|
|
||||||
grpc::Status StepOut(grpc::ServerContext* context, const Empty* request,
|
|
||||||
StepResponse* response) override;
|
|
||||||
|
|
||||||
// Disassembly & Code Analysis
|
// --- Input & State ---
|
||||||
|
grpc::Status PressButtons(grpc::ServerContext* context,
|
||||||
|
const agent::ButtonRequest* request,
|
||||||
|
agent::CommandResponse* response) override;
|
||||||
|
grpc::Status HoldButtons(grpc::ServerContext* context,
|
||||||
|
const agent::ButtonHoldRequest* request,
|
||||||
|
agent::CommandResponse* response) override;
|
||||||
|
grpc::Status GetGameState(grpc::ServerContext* context,
|
||||||
|
const agent::GameStateRequest* request,
|
||||||
|
agent::GameStateResponse* response) override;
|
||||||
|
grpc::Status ReadMemory(grpc::ServerContext* context,
|
||||||
|
const agent::MemoryRequest* request,
|
||||||
|
agent::MemoryResponse* response) override;
|
||||||
|
grpc::Status WriteMemory(grpc::ServerContext* context,
|
||||||
|
const agent::MemoryWriteRequest* request,
|
||||||
|
agent::CommandResponse* response) override;
|
||||||
|
|
||||||
|
// --- Debugging Management ---
|
||||||
|
grpc::Status BreakpointControl(grpc::ServerContext* context,
|
||||||
|
const agent::BreakpointControlRequest* request,
|
||||||
|
agent::BreakpointControlResponse* response) override;
|
||||||
|
|
||||||
|
grpc::Status WatchpointControl(grpc::ServerContext* context,
|
||||||
|
const agent::WatchpointControlRequest* request,
|
||||||
|
agent::WatchpointControlResponse* response) override;
|
||||||
|
|
||||||
|
// --- Analysis & Symbols ---
|
||||||
grpc::Status GetDisassembly(grpc::ServerContext* context,
|
grpc::Status GetDisassembly(grpc::ServerContext* context,
|
||||||
const DisassemblyRequest* request,
|
const agent::DisassemblyRequest* request,
|
||||||
DisassemblyResponse* response) override;
|
agent::DisassemblyResponse* response) override;
|
||||||
grpc::Status GetExecutionTrace(grpc::ServerContext* context,
|
grpc::Status GetExecutionTrace(grpc::ServerContext* context,
|
||||||
const TraceRequest* request,
|
const agent::TraceRequest* request,
|
||||||
TraceResponse* response) override;
|
agent::TraceResponse* response) override;
|
||||||
|
|
||||||
// Symbol Management
|
|
||||||
grpc::Status LoadSymbols(grpc::ServerContext* context,
|
|
||||||
const SymbolFileRequest* request,
|
|
||||||
CommandResponse* response) override;
|
|
||||||
grpc::Status ResolveSymbol(grpc::ServerContext* context,
|
grpc::Status ResolveSymbol(grpc::ServerContext* context,
|
||||||
const SymbolLookupRequest* request,
|
const agent::SymbolLookupRequest* request,
|
||||||
SymbolLookupResponse* response) override;
|
agent::SymbolLookupResponse* response) override;
|
||||||
grpc::Status GetSymbolAt(grpc::ServerContext* context,
|
grpc::Status GetSymbolAt(grpc::ServerContext* context,
|
||||||
const AddressRequest* request,
|
const agent::AddressRequest* request,
|
||||||
SymbolLookupResponse* response) override;
|
agent::SymbolLookupResponse* response) override;
|
||||||
|
grpc::Status LoadSymbols(grpc::ServerContext* context,
|
||||||
|
const agent::SymbolFileRequest* request,
|
||||||
|
agent::CommandResponse* response) override;
|
||||||
|
|
||||||
// Debugging Session
|
// --- Session & Experiments ---
|
||||||
grpc::Status CreateDebugSession(grpc::ServerContext* context,
|
|
||||||
const DebugSessionRequest* request,
|
|
||||||
DebugSessionResponse* response) override;
|
|
||||||
grpc::Status GetDebugStatus(grpc::ServerContext* context,
|
grpc::Status GetDebugStatus(grpc::ServerContext* context,
|
||||||
const Empty* request,
|
const agent::Empty* request,
|
||||||
DebugStatusResponse* response) override;
|
agent::DebugStatusResponse* response) override;
|
||||||
|
grpc::Status TestRun(grpc::ServerContext* context,
|
||||||
|
const agent::TestRunRequest* request,
|
||||||
|
agent::TestRunResponse* response) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitializeStepController();
|
void InitializeStepController();
|
||||||
|
void CaptureCPUState(agent::CPUState* state);
|
||||||
|
|
||||||
yaze::emu::Emulator*
|
yaze::emu::Emulator*
|
||||||
emulator_; // Non-owning pointer to the emulator instance
|
emulator_; // Non-owning pointer to the emulator instance
|
||||||
|
RomGetter rom_getter_;
|
||||||
yaze::emu::debug::SymbolProvider symbol_provider_; // Symbol table for debugging
|
yaze::emu::debug::SymbolProvider symbol_provider_; // Symbol table for debugging
|
||||||
yaze::emu::debug::StepController step_controller_; // Call stack tracking
|
|
||||||
|
yaze::emu::debug::StepController step_controller_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace yaze::agent
|
} // namespace yaze::net
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <set>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "absl/strings/str_format.h"
|
#include "absl/strings/str_format.h"
|
||||||
@@ -76,7 +77,7 @@ bool ModifiesStack(uint8_t opcode) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
RomDebugAgent::RomDebugAgent(yaze::agent::EmulatorServiceImpl* emulator_service)
|
RomDebugAgent::RomDebugAgent(yaze::net::EmulatorServiceImpl* emulator_service)
|
||||||
: emulator_service_(emulator_service),
|
: emulator_service_(emulator_service),
|
||||||
disassembler_(std::make_unique<Disassembler65816>()),
|
disassembler_(std::make_unique<Disassembler65816>()),
|
||||||
symbol_provider_(std::make_unique<yaze::emu::debug::SymbolProvider>()) {
|
symbol_provider_(std::make_unique<yaze::emu::debug::SymbolProvider>()) {
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ class RomDebugAgent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
explicit RomDebugAgent(yaze::agent::EmulatorServiceImpl* emulator_service);
|
explicit RomDebugAgent(yaze::net::EmulatorServiceImpl* emulator_service);
|
||||||
|
|
||||||
// --- Core Analysis Functions ---
|
// --- Core Analysis Functions ---
|
||||||
|
|
||||||
@@ -277,7 +277,7 @@ class RomDebugAgent {
|
|||||||
std::optional<std::string> GetStructureInfo(uint32_t address) const;
|
std::optional<std::string> GetStructureInfo(uint32_t address) const;
|
||||||
|
|
||||||
// Member variables
|
// Member variables
|
||||||
yaze::agent::EmulatorServiceImpl* emulator_service_; // Non-owning pointer
|
yaze::net::EmulatorServiceImpl* emulator_service_; // Non-owning pointer
|
||||||
std::unique_ptr<Disassembler65816> disassembler_;
|
std::unique_ptr<Disassembler65816> disassembler_;
|
||||||
std::unique_ptr<yaze::emu::debug::SymbolProvider> symbol_provider_;
|
std::unique_ptr<yaze::emu::debug::SymbolProvider> symbol_provider_;
|
||||||
std::vector<uint8_t> original_rom_; // Original ROM for comparison
|
std::vector<uint8_t> original_rom_; // Original ROM for comparison
|
||||||
|
|||||||
@@ -12,7 +12,9 @@
|
|||||||
|
|
||||||
#ifdef YAZE_WITH_JSON
|
#ifdef YAZE_WITH_JSON
|
||||||
#include "nlohmann/json.hpp"
|
#include "nlohmann/json.hpp"
|
||||||
|
#if !defined(_WIN32) && !defined(YAZE_IOS)
|
||||||
#define CPPHTTPLIB_OPENSSL_SUPPORT
|
#define CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
|
#endif
|
||||||
#include "httplib.h"
|
#include "httplib.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -2,56 +2,41 @@ syntax = "proto3";
|
|||||||
|
|
||||||
package yaze.agent;
|
package yaze.agent;
|
||||||
|
|
||||||
// The main service for controlling the yaze emulator
|
// The consolidated service for controlling the yaze emulator
|
||||||
service EmulatorService {
|
service EmulatorService {
|
||||||
// --- Lifecycle ---
|
// --- Core Lifecycle & Control ---
|
||||||
rpc Start(Empty) returns (CommandResponse);
|
// action: "start", "stop", "pause", "resume", "reset"
|
||||||
rpc Stop(Empty) returns (CommandResponse);
|
rpc ControlEmulator(ControlRequest) returns (CommandResponse);
|
||||||
rpc Pause(Empty) returns (CommandResponse);
|
|
||||||
rpc Resume(Empty) returns (CommandResponse);
|
|
||||||
rpc Reset(Empty) returns (CommandResponse);
|
|
||||||
|
|
||||||
// --- Input Control ---
|
// mode: "instruction", "over", "out"
|
||||||
|
rpc StepEmulator(StepControlRequest) returns (StepResponse);
|
||||||
|
|
||||||
|
rpc RunToBreakpoint(Empty) returns (BreakpointHitResponse);
|
||||||
|
|
||||||
|
// --- Input & State ---
|
||||||
rpc PressButtons(ButtonRequest) returns (CommandResponse);
|
rpc PressButtons(ButtonRequest) returns (CommandResponse);
|
||||||
rpc ReleaseButtons(ButtonRequest) returns (CommandResponse);
|
|
||||||
rpc HoldButtons(ButtonHoldRequest) returns (CommandResponse);
|
rpc HoldButtons(ButtonHoldRequest) returns (CommandResponse);
|
||||||
|
|
||||||
// --- State Inspection (The Feedback Loop) ---
|
|
||||||
rpc GetGameState(GameStateRequest) returns (GameStateResponse);
|
rpc GetGameState(GameStateRequest) returns (GameStateResponse);
|
||||||
rpc ReadMemory(MemoryRequest) returns (MemoryResponse);
|
rpc ReadMemory(MemoryRequest) returns (MemoryResponse);
|
||||||
rpc WriteMemory(MemoryWriteRequest) returns (CommandResponse);
|
rpc WriteMemory(MemoryWriteRequest) returns (CommandResponse);
|
||||||
|
|
||||||
// --- Advanced Debugging (NEW) ---
|
// --- Debugging Management ---
|
||||||
// Breakpoints
|
// action: "add", "remove", "list", "toggle"
|
||||||
rpc AddBreakpoint(BreakpointRequest) returns (BreakpointResponse);
|
rpc BreakpointControl(BreakpointControlRequest) returns (BreakpointControlResponse);
|
||||||
rpc RemoveBreakpoint(BreakpointIdRequest) returns (CommandResponse);
|
|
||||||
rpc ListBreakpoints(Empty) returns (BreakpointListResponse);
|
|
||||||
rpc SetBreakpointEnabled(BreakpointStateRequest) returns (CommandResponse);
|
|
||||||
|
|
||||||
// Watchpoints (memory access tracking)
|
// action: "add", "remove", "list", "history"
|
||||||
rpc AddWatchpoint(WatchpointRequest) returns (WatchpointResponse);
|
rpc WatchpointControl(WatchpointControlRequest) returns (WatchpointControlResponse);
|
||||||
rpc RemoveWatchpoint(WatchpointIdRequest) returns (CommandResponse);
|
|
||||||
rpc ListWatchpoints(Empty) returns (WatchpointListResponse);
|
|
||||||
rpc GetWatchpointHistory(WatchpointHistoryRequest) returns (WatchpointHistoryResponse);
|
|
||||||
|
|
||||||
// Execution Control
|
// --- Analysis & Symbols ---
|
||||||
rpc StepInstruction(Empty) returns (StepResponse);
|
|
||||||
rpc RunToBreakpoint(Empty) returns (BreakpointHitResponse);
|
|
||||||
rpc StepOver(Empty) returns (StepResponse); // Step over subroutines
|
|
||||||
rpc StepOut(Empty) returns (StepResponse); // Step out of subroutine
|
|
||||||
|
|
||||||
// Disassembly & Code Analysis
|
|
||||||
rpc GetDisassembly(DisassemblyRequest) returns (DisassemblyResponse);
|
rpc GetDisassembly(DisassemblyRequest) returns (DisassemblyResponse);
|
||||||
rpc GetExecutionTrace(TraceRequest) returns (TraceResponse);
|
rpc GetExecutionTrace(TraceRequest) returns (TraceResponse);
|
||||||
|
|
||||||
// Symbol Management (for Oracle of Secrets labels)
|
|
||||||
rpc LoadSymbols(SymbolFileRequest) returns (CommandResponse);
|
|
||||||
rpc ResolveSymbol(SymbolLookupRequest) returns (SymbolLookupResponse);
|
rpc ResolveSymbol(SymbolLookupRequest) returns (SymbolLookupResponse);
|
||||||
rpc GetSymbolAt(AddressRequest) returns (SymbolLookupResponse);
|
rpc GetSymbolAt(AddressRequest) returns (SymbolLookupResponse);
|
||||||
|
rpc LoadSymbols(SymbolFileRequest) returns (CommandResponse);
|
||||||
|
|
||||||
// Debugging Session
|
// --- Session & Experiments ---
|
||||||
rpc CreateDebugSession(DebugSessionRequest) returns (DebugSessionResponse);
|
|
||||||
rpc GetDebugStatus(Empty) returns (DebugStatusResponse);
|
rpc GetDebugStatus(Empty) returns (DebugStatusResponse);
|
||||||
|
rpc TestRun(TestRunRequest) returns (TestRunResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Message Definitions ---
|
// --- Message Definitions ---
|
||||||
@@ -63,20 +48,15 @@ message CommandResponse {
|
|||||||
string message = 2;
|
string message = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ControlRequest {
|
||||||
|
string action = 1; // "start", "stop", "pause", "resume", "reset"
|
||||||
|
}
|
||||||
|
|
||||||
enum Button {
|
enum Button {
|
||||||
BUTTON_UNSPECIFIED = 0;
|
BUTTON_UNSPECIFIED = 0;
|
||||||
A = 1;
|
A = 1; B = 2; X = 3; Y = 4;
|
||||||
B = 2;
|
L = 5; R = 6; SELECT = 7; START = 8;
|
||||||
X = 3;
|
UP = 9; DOWN = 10; LEFT = 11; RIGHT = 12;
|
||||||
Y = 4;
|
|
||||||
L = 5;
|
|
||||||
R = 6;
|
|
||||||
SELECT = 7;
|
|
||||||
START = 8;
|
|
||||||
UP = 9;
|
|
||||||
DOWN = 10;
|
|
||||||
LEFT = 11;
|
|
||||||
RIGHT = 12;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message ButtonRequest {
|
message ButtonRequest {
|
||||||
@@ -85,7 +65,7 @@ message ButtonRequest {
|
|||||||
|
|
||||||
message ButtonHoldRequest {
|
message ButtonHoldRequest {
|
||||||
repeated Button buttons = 1;
|
repeated Button buttons = 1;
|
||||||
uint32 duration_ms = 2; // How long to hold the buttons
|
uint32 duration_ms = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GameStateRequest {
|
message GameStateRequest {
|
||||||
@@ -94,17 +74,12 @@ message GameStateRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message GameStateResponse {
|
message GameStateResponse {
|
||||||
// Key player and game variables
|
|
||||||
uint32 game_mode = 1;
|
uint32 game_mode = 1;
|
||||||
uint32 link_state = 2;
|
uint32 link_state = 2;
|
||||||
uint32 link_pos_x = 3;
|
uint32 link_pos_x = 3;
|
||||||
uint32 link_pos_y = 4;
|
uint32 link_pos_y = 4;
|
||||||
uint32 link_health = 5;
|
uint32 link_health = 5;
|
||||||
|
bytes screenshot_png = 6;
|
||||||
// Screenshot of the current frame
|
|
||||||
bytes screenshot_png = 6; // PNG encoded image data
|
|
||||||
|
|
||||||
// Results of any requested memory reads
|
|
||||||
repeated MemoryResponse memory_responses = 7;
|
repeated MemoryResponse memory_responses = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,47 +98,28 @@ message MemoryWriteRequest {
|
|||||||
bytes data = 2;
|
bytes data = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Advanced Debugging Messages (NEW) ---
|
// --- Breakpoint Control ---
|
||||||
|
|
||||||
// Breakpoint types (matches BreakpointManager::Type)
|
|
||||||
enum BreakpointType {
|
enum BreakpointType {
|
||||||
BREAKPOINT_TYPE_UNSPECIFIED = 0;
|
BREAKPOINT_TYPE_UNSPECIFIED = 0;
|
||||||
EXECUTE = 1; // Break when PC reaches address
|
EXECUTE = 1; READ = 2; WRITE = 3; ACCESS = 4; CONDITIONAL = 5;
|
||||||
READ = 2; // Break when memory is read
|
|
||||||
WRITE = 3; // Break when memory is written
|
|
||||||
ACCESS = 4; // Break on read OR write
|
|
||||||
CONDITIONAL = 5; // Break when condition is true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CPU type for breakpoints
|
|
||||||
enum CpuType {
|
enum CpuType {
|
||||||
CPU_TYPE_UNSPECIFIED = 0;
|
CPU_TYPE_UNSPECIFIED = 0;
|
||||||
CPU_65816 = 1;
|
CPU_65816 = 1;
|
||||||
SPC700 = 2;
|
SPC700 = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Breakpoint request
|
message BreakpointControlRequest {
|
||||||
message BreakpointRequest {
|
string action = 1; // "add", "remove", "list", "toggle"
|
||||||
uint32 address = 1;
|
uint32 id = 2; // For remove/toggle
|
||||||
BreakpointType type = 2;
|
uint32 address = 3; // For add
|
||||||
CpuType cpu = 3;
|
BreakpointType type = 4;
|
||||||
string condition = 4; // Optional condition (e.g., "A > 0x10")
|
CpuType cpu = 5;
|
||||||
string description = 5; // User-friendly label
|
string condition = 6;
|
||||||
}
|
string description = 7;
|
||||||
|
bool enabled = 8;
|
||||||
message BreakpointResponse {
|
|
||||||
bool success = 1;
|
|
||||||
uint32 breakpoint_id = 2;
|
|
||||||
string message = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message BreakpointIdRequest {
|
|
||||||
uint32 breakpoint_id = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message BreakpointStateRequest {
|
|
||||||
uint32 breakpoint_id = 1;
|
|
||||||
bool enabled = 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message BreakpointInfo {
|
message BreakpointInfo {
|
||||||
@@ -177,35 +133,25 @@ message BreakpointInfo {
|
|||||||
uint32 hit_count = 8;
|
uint32 hit_count = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
message BreakpointListResponse {
|
message BreakpointControlResponse {
|
||||||
repeated BreakpointInfo breakpoints = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message BreakpointHitResponse {
|
|
||||||
bool hit = 1;
|
|
||||||
BreakpointInfo breakpoint = 2;
|
|
||||||
CPUState cpu_state = 3;
|
|
||||||
string message = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Watchpoint messages
|
|
||||||
message WatchpointRequest {
|
|
||||||
uint32 start_address = 1;
|
|
||||||
uint32 end_address = 2; // For range watchpoints
|
|
||||||
bool track_reads = 3;
|
|
||||||
bool track_writes = 4;
|
|
||||||
bool break_on_access = 5;
|
|
||||||
string description = 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
message WatchpointResponse {
|
|
||||||
bool success = 1;
|
bool success = 1;
|
||||||
uint32 watchpoint_id = 2;
|
string message = 2;
|
||||||
string message = 3;
|
uint32 breakpoint_id = 3; // For newly added
|
||||||
|
repeated BreakpointInfo breakpoints = 4; // For list
|
||||||
}
|
}
|
||||||
|
|
||||||
message WatchpointIdRequest {
|
// --- Watchpoint Control ---
|
||||||
uint32 watchpoint_id = 1;
|
|
||||||
|
message WatchpointControlRequest {
|
||||||
|
string action = 1; // "add", "remove", "list", "history"
|
||||||
|
uint32 id = 2;
|
||||||
|
uint32 start_address = 3;
|
||||||
|
uint32 end_address = 4;
|
||||||
|
bool track_reads = 5;
|
||||||
|
bool track_writes = 6;
|
||||||
|
bool break_on_access = 7;
|
||||||
|
string description = 8;
|
||||||
|
uint32 max_entries = 9; // For history
|
||||||
}
|
}
|
||||||
|
|
||||||
message WatchpointInfo {
|
message WatchpointInfo {
|
||||||
@@ -219,15 +165,6 @@ message WatchpointInfo {
|
|||||||
string description = 8;
|
string description = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
message WatchpointListResponse {
|
|
||||||
repeated WatchpointInfo watchpoints = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message WatchpointHistoryRequest {
|
|
||||||
uint32 watchpoint_id = 1;
|
|
||||||
uint32 max_entries = 2; // Max history entries to return
|
|
||||||
}
|
|
||||||
|
|
||||||
message AccessLogEntry {
|
message AccessLogEntry {
|
||||||
uint32 pc = 1;
|
uint32 pc = 1;
|
||||||
uint32 address = 2;
|
uint32 address = 2;
|
||||||
@@ -235,133 +172,95 @@ message AccessLogEntry {
|
|||||||
uint32 new_value = 4;
|
uint32 new_value = 4;
|
||||||
bool is_write = 5;
|
bool is_write = 5;
|
||||||
uint64 cycle_count = 6;
|
uint64 cycle_count = 6;
|
||||||
string description = 7;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message WatchpointHistoryResponse {
|
message WatchpointControlResponse {
|
||||||
repeated AccessLogEntry history = 1;
|
bool success = 1;
|
||||||
|
string message = 2;
|
||||||
|
uint32 watchpoint_id = 3;
|
||||||
|
repeated WatchpointInfo watchpoints = 4;
|
||||||
|
repeated AccessLogEntry history = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Stepping & Status ---
|
||||||
|
|
||||||
|
message StepControlRequest {
|
||||||
|
string mode = 1; // "instruction", "over", "out"
|
||||||
}
|
}
|
||||||
|
|
||||||
// CPU State (for stepping/debugging)
|
|
||||||
message CPUState {
|
message CPUState {
|
||||||
uint32 a = 1;
|
uint32 a = 1; uint32 x = 2; uint32 y = 3; uint32 sp = 4;
|
||||||
uint32 x = 2;
|
uint32 pc = 5; uint32 db = 6; uint32 pb = 7; uint32 d = 8;
|
||||||
uint32 y = 3;
|
uint32 status = 9;
|
||||||
uint32 sp = 4;
|
bool flag_n = 10; bool flag_v = 11; bool flag_z = 12; bool flag_c = 13;
|
||||||
uint32 pc = 5;
|
uint64 cycles = 14;
|
||||||
uint32 db = 6; // Data bank
|
|
||||||
uint32 pb = 7; // Program bank
|
|
||||||
uint32 d = 8; // Direct page
|
|
||||||
uint32 status = 9; // Processor status
|
|
||||||
bool flag_n = 10; // Negative
|
|
||||||
bool flag_v = 11; // Overflow
|
|
||||||
bool flag_d = 12; // Decimal
|
|
||||||
bool flag_i = 13; // Interrupt disable
|
|
||||||
bool flag_z = 14; // Zero
|
|
||||||
bool flag_c = 15; // Carry
|
|
||||||
uint64 cycles = 16;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message StepResponse {
|
message StepResponse {
|
||||||
bool success = 1;
|
bool success = 1;
|
||||||
CPUState cpu_state = 2;
|
string message = 2;
|
||||||
DisassemblyLine instruction = 3;
|
CPUState cpu_state = 3;
|
||||||
string message = 4;
|
}
|
||||||
|
|
||||||
|
message BreakpointHitResponse {
|
||||||
|
bool hit = 1;
|
||||||
|
BreakpointInfo breakpoint = 2;
|
||||||
|
CPUState cpu_state = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disassembly messages
|
|
||||||
message DisassemblyRequest {
|
message DisassemblyRequest {
|
||||||
uint32 start_address = 1;
|
uint32 start_address = 1;
|
||||||
uint32 count = 2; // Number of instructions
|
uint32 count = 2;
|
||||||
bool include_execution_count = 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message DisassemblyLine {
|
message DisassemblyLine {
|
||||||
uint32 address = 1;
|
uint32 address = 1;
|
||||||
uint32 opcode = 2;
|
string mnemonic = 2;
|
||||||
repeated uint32 operands = 3;
|
string operand_str = 3;
|
||||||
string mnemonic = 4;
|
bool is_breakpoint = 4;
|
||||||
string operand_str = 5;
|
|
||||||
uint32 size = 6;
|
|
||||||
uint64 execution_count = 7;
|
|
||||||
bool is_breakpoint = 8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message DisassemblyResponse {
|
message DisassemblyResponse {
|
||||||
repeated DisassemblyLine lines = 1;
|
repeated DisassemblyLine lines = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execution trace
|
message TraceRequest { uint32 max_entries = 1; }
|
||||||
message TraceRequest {
|
|
||||||
uint32 max_entries = 1; // Max trace entries to return
|
|
||||||
uint32 start_address = 2; // Optional: filter by address range
|
|
||||||
uint32 end_address = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message TraceEntry {
|
|
||||||
uint32 address = 1;
|
|
||||||
string instruction = 2;
|
|
||||||
CPUState cpu_state_before = 3;
|
|
||||||
uint64 cycle_count = 4;
|
|
||||||
uint32 opcode = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
message TraceResponse {
|
message TraceResponse {
|
||||||
repeated TraceEntry entries = 1;
|
message Entry { uint32 address = 1; string instruction = 2; uint32 opcode = 3; }
|
||||||
uint32 total_count = 2;
|
repeated Entry entries = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Symbol management
|
|
||||||
message SymbolFileRequest {
|
message SymbolFileRequest {
|
||||||
string filepath = 1; // Path to symbol file (e.g., .sym, .map)
|
string filepath = 1;
|
||||||
SymbolFormat format = 2;
|
enum Format { AUTO = 0; ASAR = 1; WLA_DX = 2; MESEN = 3; }
|
||||||
}
|
Format format = 2;
|
||||||
|
|
||||||
enum SymbolFormat {
|
|
||||||
SYMBOL_FORMAT_UNSPECIFIED = 0;
|
|
||||||
ASAR = 1; // Asar assembler format
|
|
||||||
WLA_DX = 2; // WLA-DX assembler format
|
|
||||||
CA65 = 3; // ca65 assembler format
|
|
||||||
MESEN = 4; // Mesen debug symbol format
|
|
||||||
CUSTOM_JSON = 5; // Custom JSON format
|
|
||||||
}
|
|
||||||
|
|
||||||
message SymbolLookupRequest {
|
|
||||||
string symbol_name = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message AddressRequest {
|
|
||||||
uint32 address = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message SymbolLookupRequest { string symbol_name = 1; }
|
||||||
|
message AddressRequest { uint32 address = 1; }
|
||||||
message SymbolLookupResponse {
|
message SymbolLookupResponse {
|
||||||
bool found = 1;
|
bool found = 1;
|
||||||
string symbol_name = 2;
|
string symbol_name = 2;
|
||||||
uint32 address = 3;
|
uint32 address = 3;
|
||||||
string type = 4; // "function", "data", "label", etc.
|
string type = 4;
|
||||||
string description = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug session
|
|
||||||
message DebugSessionRequest {
|
|
||||||
string session_name = 1;
|
|
||||||
string rom_hash = 2; // For verification
|
|
||||||
bool enable_all_features = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message DebugSessionResponse {
|
|
||||||
bool success = 1;
|
|
||||||
string session_id = 2;
|
|
||||||
string message = 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message DebugStatusResponse {
|
message DebugStatusResponse {
|
||||||
bool is_running = 1;
|
bool is_running = 1;
|
||||||
bool is_paused = 2;
|
CPUState cpu_state = 2;
|
||||||
CPUState cpu_state = 3;
|
uint32 active_breakpoints = 3;
|
||||||
uint32 active_breakpoints = 4;
|
}
|
||||||
uint32 active_watchpoints = 5;
|
|
||||||
BreakpointInfo last_breakpoint_hit = 6;
|
message TestRunRequest {
|
||||||
double fps = 7;
|
uint32 address = 1;
|
||||||
uint64 cycles = 8;
|
bytes data = 2;
|
||||||
|
uint32 frame_count = 3;
|
||||||
|
bool reset_after = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TestRunResponse {
|
||||||
|
bool success = 1;
|
||||||
|
string message = 2;
|
||||||
|
CPUState final_cpu_state = 3;
|
||||||
|
bool crashed = 4;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user