yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
emulator_commands.cc
Go to the documentation of this file.
2
3#include <grpcpp/grpcpp.h>
4#include "protos/emulator_service.grpc.pb.h"
5#include "absl/strings/str_split.h"
6#include "absl/strings/string_view.h"
7#include "absl/time/time.h"
8#include "absl/status/statusor.h"
9#include "absl/strings/escaping.h"
10
11namespace yaze {
12namespace cli {
13namespace handlers {
14
15namespace {
16
17// A simple client for the EmulatorService
19public:
21 auto channel = grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials());
22 stub_ = agent::EmulatorService::NewStub(channel);
23 }
24
25 template <typename TRequest, typename TResponse>
26 absl::StatusOr<TResponse> CallRpc(
27 grpc::Status (agent::EmulatorService::Stub::*rpc_method)(grpc::ClientContext*, const TRequest&, TResponse*),
28 const TRequest& request) {
29
30 TResponse response;
31 grpc::ClientContext context;
32
33 auto deadline = std::chrono::system_clock::now() + std::chrono::seconds(5);
34 context.set_deadline(deadline);
35
36 grpc::Status status = (stub_.get()->*rpc_method)(&context, request, &response);
37
38 if (!status.ok()) {
39 return absl::UnavailableError(absl::StrFormat(
40 "RPC failed: (%d) %s", status.error_code(), status.error_message()));
41 }
42 return response;
43 }
44
45private:
46 std::unique_ptr<agent::EmulatorService::Stub> stub_;
47};
48
49// Helper to parse button from string
50absl::StatusOr<agent::Button> StringToButton(absl::string_view s) {
51 if (s == "A") return agent::Button::A;
52 if (s == "B") return agent::Button::B;
53 if (s == "X") return agent::Button::X;
54 if (s == "Y") return agent::Button::Y;
55 if (s == "L") return agent::Button::L;
56 if (s == "R") return agent::Button::R;
57 if (s == "SELECT") return agent::Button::SELECT;
58 if (s == "START") return agent::Button::START;
59 if (s == "UP") return agent::Button::UP;
60 if (s == "DOWN") return agent::Button::DOWN;
61 if (s == "LEFT") return agent::Button::LEFT;
62 if (s == "RIGHT") return agent::Button::RIGHT;
63 return absl::InvalidArgumentError(absl::StrCat("Unknown button: ", s));
64}
65
66} // namespace
67
68// --- Command Implementations ---
69
71 resources::OutputFormatter& formatter) {
72 EmulatorClient client;
73 agent::Empty request;
74 auto response_or = client.CallRpc(&agent::EmulatorService::Stub::Reset, request);
75 if (!response_or.ok()) {
76 return response_or.status();
77 }
78 auto response = response_or.value();
79
80 formatter.BeginObject("EmulatorReset");
81 formatter.AddField("success", response.success());
82 formatter.AddField("message", response.message());
83 formatter.EndObject();
84 return absl::OkStatus();
85}
86
88 resources::OutputFormatter& formatter) {
89 EmulatorClient client;
90 agent::GameStateRequest request;
91 request.set_include_screenshot(parser.HasFlag("screenshot"));
92
93 auto response_or = client.CallRpc(&agent::EmulatorService::Stub::GetGameState, request);
94 if (!response_or.ok()) {
95 return response_or.status();
96 }
97 auto response = response_or.value();
98
99 formatter.BeginObject("EmulatorState");
100 formatter.AddField("game_mode", static_cast<uint64_t>(response.game_mode()));
101 formatter.AddField("link_state", static_cast<uint64_t>(response.link_state()));
102 formatter.AddField("link_pos_x", static_cast<uint64_t>(response.link_pos_x()));
103 formatter.AddField("link_pos_y", static_cast<uint64_t>(response.link_pos_y()));
104 formatter.AddField("link_health", static_cast<uint64_t>(response.link_health()));
105 if (!response.screenshot_png().empty()) {
106 formatter.AddField("screenshot_size", static_cast<uint64_t>(response.screenshot_png().size()));
107 }
108 formatter.EndObject();
109 return absl::OkStatus();
110}
111
113 resources::OutputFormatter& formatter) {
114 EmulatorClient client;
115 agent::MemoryRequest request;
116
117 uint32_t address;
118 if (!absl::SimpleHexAtoi(parser.GetString("address").value(), &address)) {
119 return absl::InvalidArgumentError("Invalid address format.");
120 }
121 request.set_address(address);
122 request.set_size(parser.GetInt("length").value_or(16));
123
124 auto response_or = client.CallRpc(&agent::EmulatorService::Stub::ReadMemory, request);
125 if (!response_or.ok()) {
126 return response_or.status();
127 }
128 auto response = response_or.value();
129
130 formatter.BeginObject("MemoryRead");
131 formatter.AddHexField("address", response.address());
132 formatter.AddField("data_hex", absl::BytesToHexString(response.data()));
133 formatter.EndObject();
134 return absl::OkStatus();
135}
136
138 resources::OutputFormatter& formatter) {
139 EmulatorClient client;
140 agent::MemoryWriteRequest request;
141
142 uint32_t address;
143 if (!absl::SimpleHexAtoi(parser.GetString("address").value(), &address)) {
144 return absl::InvalidArgumentError("Invalid address format.");
145 }
146 request.set_address(address);
147
148 std::string data_hex = parser.GetString("data").value();
149 request.set_data(absl::HexStringToBytes(data_hex));
150
151 auto response_or = client.CallRpc(&agent::EmulatorService::Stub::WriteMemory, request);
152 if (!response_or.ok()) {
153 return response_or.status();
154 }
155 auto response = response_or.value();
156
157 formatter.BeginObject("MemoryWrite");
158 formatter.AddField("success", response.success());
159 formatter.AddField("message", response.message());
160 formatter.EndObject();
161 return absl::OkStatus();
162}
163
164
166 resources::OutputFormatter& formatter) {
167 EmulatorClient client;
168 agent::ButtonRequest request;
169 std::vector<std::string> buttons = absl::StrSplit(parser.GetString("buttons").value(), ',');
170 for (const auto& btn_str : buttons) {
171 auto button_or = StringToButton(btn_str);
172 if (!button_or.ok()) return button_or.status();
173 request.add_buttons(button_or.value());
174 }
175
176 auto response_or = client.CallRpc(&agent::EmulatorService::Stub::PressButtons, request);
177 if (!response_or.ok()) {
178 return response_or.status();
179 }
180 auto response = response_or.value();
181
182 formatter.BeginObject("PressButtons");
183 formatter.AddField("success", response.success());
184 formatter.AddField("message", response.message());
185 formatter.EndObject();
186 return absl::OkStatus();
187}
188
190 resources::OutputFormatter& formatter) {
191 EmulatorClient client;
192 agent::ButtonRequest request;
193 std::vector<std::string> buttons = absl::StrSplit(parser.GetString("buttons").value(), ',');
194 for (const auto& btn_str : buttons) {
195 auto button_or = StringToButton(btn_str);
196 if (!button_or.ok()) return button_or.status();
197 request.add_buttons(button_or.value());
198 }
199
200 auto response_or = client.CallRpc(&agent::EmulatorService::Stub::ReleaseButtons, request);
201 if (!response_or.ok()) {
202 return response_or.status();
203 }
204 auto response = response_or.value();
205
206 formatter.BeginObject("ReleaseButtons");
207 formatter.AddField("success", response.success());
208 formatter.AddField("message", response.message());
209 formatter.EndObject();
210 return absl::OkStatus();
211}
212
214 resources::OutputFormatter& formatter) {
215 EmulatorClient client;
216 agent::ButtonHoldRequest request;
217 std::vector<std::string> buttons = absl::StrSplit(parser.GetString("buttons").value(), ',');
218 for (const auto& btn_str : buttons) {
219 auto button_or = StringToButton(btn_str);
220 if (!button_or.ok()) return button_or.status();
221 request.add_buttons(button_or.value());
222 }
223 request.set_duration_ms(parser.GetInt("duration").value());
224
225 auto response_or = client.CallRpc(&agent::EmulatorService::Stub::HoldButtons, request);
226 if (!response_or.ok()) {
227 return response_or.status();
228 }
229 auto response = response_or.value();
230
231 formatter.BeginObject("HoldButtons");
232 formatter.AddField("success", response.success());
233 formatter.AddField("message", response.message());
234 formatter.EndObject();
235 return absl::OkStatus();
236}
237
238
239// --- Placeholder Implementations for commands not yet migrated to gRPC ---
240
242 resources::OutputFormatter& formatter) {
243 formatter.BeginObject("Emulator Step");
244 formatter.AddField("status", "not_implemented");
245 formatter.EndObject();
246 return absl::OkStatus();
247}
248
250 resources::OutputFormatter& formatter) {
251 formatter.BeginObject("Emulator Run");
252 formatter.AddField("status", "not_implemented");
253 formatter.EndObject();
254 return absl::OkStatus();
255}
256
258 resources::OutputFormatter& formatter) {
259 formatter.BeginObject("Emulator Pause");
260 formatter.AddField("status", "not_implemented");
261 formatter.EndObject();
262 return absl::OkStatus();
263}
264
266 resources::OutputFormatter& formatter) {
267 formatter.BeginObject("Emulator Breakpoint Set");
268 formatter.AddField("status", "not_implemented");
269 formatter.EndObject();
270 return absl::OkStatus();
271}
272
274 resources::OutputFormatter& formatter) {
275 formatter.BeginObject("Emulator Breakpoint Cleared");
276 formatter.AddField("status", "not_implemented");
277 formatter.EndObject();
278 return absl::OkStatus();
279}
280
282 resources::OutputFormatter& formatter) {
283 formatter.BeginObject("Emulator Breakpoints");
284 formatter.AddField("status", "not_implemented");
285 formatter.EndObject();
286 return absl::OkStatus();
287}
288
290 resources::OutputFormatter& formatter) {
291 formatter.BeginObject("Emulator Registers");
292 formatter.AddField("status", "not_implemented");
293 formatter.EndObject();
294 return absl::OkStatus();
295}
296
298 resources::OutputFormatter& formatter) {
299 formatter.BeginObject("Emulator Metrics");
300 formatter.AddField("status", "not_implemented");
301 formatter.EndObject();
302 return absl::OkStatus();
303}
304
305} // namespace handlers
306} // namespace cli
307} // namespace yaze
The Rom class is used to load, save, and modify Rom data.
Definition rom.h:71
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::Status Execute(Rom *rom, const resources::ArgumentParser &parser, resources::OutputFormatter &formatter) override
Execute the command business logic.
absl::StatusOr< TResponse > CallRpc(grpc::Status(agent::EmulatorService::Stub::*rpc_method)(grpc::ClientContext *, const TRequest &, TResponse *), const TRequest &request)
Utility for parsing common CLI argument patterns.
std::optional< std::string > GetString(const std::string &name) const
Parse a named argument (e.g., –format=json or –format json)
bool HasFlag(const std::string &name) const
Check if a flag is present.
absl::StatusOr< int > GetInt(const std::string &name) const
Parse an integer argument (supports hex with 0x prefix)
Utility for consistent output formatting across commands.
void BeginObject(const std::string &title="")
Start a JSON object or text section.
void EndObject()
End a JSON object or text section.
void AddField(const std::string &key, const std::string &value)
Add a key-value pair.
void AddHexField(const std::string &key, uint64_t value, int width=2)
Add a hex-formatted field.
absl::StatusOr< agent::Button > StringToButton(absl::string_view s)
Main namespace for the application.