#include "wrappers.h" #include #include /* * RapidJSON dependency * You might need to adjust the paths when importing into your own project. */ #include "external/rapidjson/document.h" #include "external/rapidjson/writer.h" using namespace rapidjson; namespace spiceapi { static inline std::string doc2str(Document &doc) { StringBuffer sb; rapidjson::Writer writer(sb); doc.Accept(writer); return sb.GetString(); } static inline Document request_gen(const char *module, const char *function) { // create document Document doc; doc.SetObject(); // add attributes auto &alloc = doc.GetAllocator(); doc.AddMember("id", msg_gen_id(), alloc); doc.AddMember("module", StringRef(module), alloc); doc.AddMember("function", StringRef(function), alloc); // add params Value noparam(kArrayType); doc.AddMember("params", noparam, alloc); // return document return doc; } static inline Document *response_get(std::string json) { // parse document Document *doc = new Document(); doc->Parse(json.c_str()); // check for parse error if (doc->HasParseError()) { delete doc; return nullptr; } // check id auto it_id = doc->FindMember("id"); if (it_id == doc->MemberEnd() || !(*it_id).value.IsUint64()) { delete doc; return nullptr; } // check errors auto it_errors = doc->FindMember("errors"); if (it_errors == doc->MemberEnd() || !(*it_errors).value.IsArray()) { delete doc; return nullptr; } // check error count if ((*it_errors).value.Size() > 0) { delete doc; return nullptr; } // check data auto it_data = doc->FindMember("data"); if (it_data == doc->MemberEnd() || !(*it_data).value.IsArray()) { delete doc; return nullptr; } // return document return doc; } } uint64_t spiceapi::msg_gen_id() { static uint64_t id_global = 0; // check if global ID was initialized if (id_global == 0) { // generate a new ID std::random_device rd; std::mt19937_64 gen(rd()); std::uniform_int_distribution dist(1, (uint64_t) std::llround(std::pow(2, 63))); id_global = dist(gen); } else { // increase by one id_global++; } // return global ID return id_global; } bool spiceapi::analogs_read(spiceapi::Connection &con, std::vector &states) { auto req = request_gen("analogs", "read"); auto res = response_get(con.request(doc2str(req))); if (!res) return false; auto &data = (*res)["data"]; for (auto &val : data.GetArray()) { AnalogState state; state.name = val[0].GetString(); state.value = val[1].GetFloat(); states.push_back(state); } delete res; return true; } bool spiceapi::analogs_write(spiceapi::Connection &con, std::vector &states) { auto req = request_gen("analogs", "write"); auto &alloc = req.GetAllocator(); Value params(kArrayType); for (auto &state : states) { Value state_val(kArrayType); state_val.PushBack(StringRef(state.name.c_str()), alloc); state_val.PushBack(state.value, alloc); params.PushBack(state_val, alloc); } req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::analogs_write_reset(spiceapi::Connection &con, std::vector &states) { auto req = request_gen("analogs", "write_reset"); auto &alloc = req.GetAllocator(); Value params(kArrayType); for (auto &state : states) { Value state_val(kArrayType); state_val.PushBack(StringRef(state.name.c_str()), alloc); params.PushBack(state_val, alloc); } req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::buttons_read(spiceapi::Connection &con, std::vector &states) { auto req = request_gen("buttons", "read"); auto res = response_get(con.request(doc2str(req))); if (!res) return false; auto &data = (*res)["data"]; for (auto &val : data.GetArray()) { ButtonState state; state.name = val[0].GetString(); state.value = val[1].GetFloat(); states.push_back(state); } delete res; return true; } bool spiceapi::buttons_write(spiceapi::Connection &con, std::vector &states) { auto req = request_gen("buttons", "write"); auto &alloc = req.GetAllocator(); Value params(kArrayType); for (auto &state : states) { Value state_val(kArrayType); state_val.PushBack(StringRef(state.name.c_str()), alloc); state_val.PushBack(state.value, alloc); params.PushBack(state_val, alloc); } req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::buttons_write_reset(spiceapi::Connection &con, std::vector &states) { auto req = request_gen("buttons", "write_reset"); auto &alloc = req.GetAllocator(); Value params(kArrayType); for (auto &state : states) { Value state_val(kArrayType); state_val.PushBack(StringRef(state.name.c_str()), alloc); params.PushBack(state_val, alloc); } req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::card_insert(spiceapi::Connection &con, size_t index, const char *card_id) { auto req = request_gen("card", "insert"); auto &alloc = req.GetAllocator(); Value params(kArrayType); params.PushBack(index, alloc); params.PushBack(StringRef(card_id), alloc); req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::coin_get(Connection &con, int &coins) { auto req = request_gen("coin", "get"); auto res = response_get(con.request(doc2str(req))); if (!res) return false; coins = (*res)["data"][0].GetInt(); delete res; return true; } bool spiceapi::coin_set(Connection &con, int coins) { auto req = request_gen("coin", "set"); auto &alloc = req.GetAllocator(); Value params(kArrayType); params.PushBack(coins, alloc); req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::coin_insert(Connection &con, int coins) { auto req = request_gen("coin", "insert"); auto &alloc = req.GetAllocator(); Value params(kArrayType); params.PushBack(coins, alloc); req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::coin_blocker_get(Connection &con, bool &closed) { auto req = request_gen("coin", "blocker_get"); auto res = response_get(con.request(doc2str(req))); if (!res) return false; closed = (*res)["data"][0].GetBool(); delete res; return true; } bool spiceapi::control_raise(spiceapi::Connection &con, const char *signal) { auto req = request_gen("control", "raise"); auto &alloc = req.GetAllocator(); Value params(kArrayType); params.PushBack(StringRef(signal), alloc); req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::control_exit(spiceapi::Connection &con) { auto req = request_gen("control", "exit"); auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::control_exit(spiceapi::Connection &con, int exit_code) { auto req = request_gen("control", "exit"); auto &alloc = req.GetAllocator(); Value params(kArrayType); params.PushBack(exit_code, alloc); req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::control_restart(spiceapi::Connection &con) { auto req = request_gen("control", "restart"); auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::control_session_refresh(spiceapi::Connection &con) { auto req = request_gen("control", "session_refresh"); auto res = response_get(con.request(doc2str(req))); if (!res) return false; auto key = (*res)["data"][0].GetString(); con.change_pass(key); delete res; return true; } bool spiceapi::control_shutdown(spiceapi::Connection &con) { auto req = request_gen("control", "shutdown"); auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::control_reboot(spiceapi::Connection &con) { auto req = request_gen("control", "reboot"); auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::iidx_ticker_get(spiceapi::Connection &con, char *ticker) { auto req = request_gen("iidx", "ticker_get"); auto res = response_get(con.request(doc2str(req))); if (!res) return false; auto data = (*res)["data"][0].GetString(); strncpy(ticker, data, 9); ticker[9] = 0x00; delete res; return true; } bool spiceapi::iidx_ticker_set(spiceapi::Connection &con, const char *ticker) { auto req = request_gen("iidx", "ticker_set"); auto &alloc = req.GetAllocator(); Value params(kArrayType); params.PushBack(StringRef(ticker), alloc); req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::iidx_ticker_reset(spiceapi::Connection &con) { auto req = request_gen("iidx", "ticker_reset"); auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::info_avs(spiceapi::Connection &con, spiceapi::InfoAvs &info) { auto req = request_gen("info", "avs"); auto res = response_get(con.request(doc2str(req))); if (!res) return false; auto &data = (*res)["data"][0]; info.model = data["model"].GetString(); info.dest = data["dest"].GetString(); info.spec = data["spec"].GetString(); info.rev = data["rev"].GetString(); info.ext = data["ext"].GetString(); delete res; return true; } bool spiceapi::info_launcher(spiceapi::Connection &con, spiceapi::InfoLauncher &info) { auto req = request_gen("info", "launcher"); auto res = response_get(con.request(doc2str(req))); if (!res) return false; auto &data = (*res)["data"][0]; info.version = data["version"].GetString(); info.compile_date = data["compile_date"].GetString(); info.compile_time = data["compile_time"].GetString(); info.system_time = data["system_time"].GetString(); for (auto &arg : data["args"].GetArray()) info.args.push_back(arg.GetString()); delete res; return true; } bool spiceapi::info_memory(spiceapi::Connection &con, spiceapi::InfoMemory &info) { auto req = request_gen("info", "memory"); auto res = response_get(con.request(doc2str(req))); if (!res) return false; auto &data = (*res)["data"][0]; info.mem_total = data["mem_total"].GetUint64(); info.mem_total_used = data["mem_total_used"].GetUint64(); info.mem_used = data["mem_used"].GetUint64(); info.vmem_total = data["vmem_total"].GetUint64(); info.vmem_total_used = data["vmem_total_used"].GetUint64(); info.vmem_used = data["vmem_used"].GetUint64(); delete res; return true; } bool spiceapi::keypads_write(spiceapi::Connection &con, unsigned int keypad, const char *input) { auto req = request_gen("keypads", "write"); auto &alloc = req.GetAllocator(); Value params(kArrayType); params.PushBack(keypad, alloc); params.PushBack(StringRef(input), alloc); req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::keypads_set(spiceapi::Connection &con, unsigned int keypad, std::vector &keys) { auto req = request_gen("keypads", "set"); auto &alloc = req.GetAllocator(); Value params(kArrayType); params.PushBack(keypad, alloc); for (auto &key : keys) params.PushBack(StringRef(&key, 1), alloc); req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::keypads_get(spiceapi::Connection &con, unsigned int keypad, std::vector &keys) { auto req = request_gen("keypads", "get"); auto &alloc = req.GetAllocator(); Value params(kArrayType); params.PushBack(keypad, alloc); req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; auto &data = (*res)["data"]; for (auto &val : data.GetArray()) keys.push_back(val.GetString()[0]); delete res; return true; } bool spiceapi::lights_read(spiceapi::Connection &con, std::vector &states) { auto req = request_gen("lights", "read"); auto res = response_get(con.request(doc2str(req))); if (!res) return false; auto &data = (*res)["data"]; for (auto &val : data.GetArray()) { LightState state; state.name = val[0].GetString(); state.value = val[1].GetFloat(); states.push_back(state); } delete res; return true; } bool spiceapi::lights_write(spiceapi::Connection &con, std::vector &states) { auto req = request_gen("lights", "write"); auto &alloc = req.GetAllocator(); Value params(kArrayType); for (auto &state : states) { Value state_val(kArrayType); state_val.PushBack(StringRef(state.name.c_str()), alloc); state_val.PushBack(state.value, alloc); params.PushBack(state_val, alloc); } req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::lights_write_reset(spiceapi::Connection &con, std::vector &states) { auto req = request_gen("lights", "write_reset"); auto &alloc = req.GetAllocator(); Value params(kArrayType); for (auto &state : states) { Value state_val(kArrayType); state_val.PushBack(StringRef(state.name.c_str()), alloc); params.PushBack(state_val, alloc); } req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::memory_write(spiceapi::Connection &con, const char *dll_name, const char *hex, uint32_t offset) { auto req = request_gen("memory", "write"); auto &alloc = req.GetAllocator(); Value params(kArrayType); params.PushBack(StringRef(dll_name), alloc); params.PushBack(StringRef(hex), alloc); params.PushBack(offset, alloc); req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::memory_read(spiceapi::Connection &con, const char *dll_name, uint32_t offset, uint32_t size, std::string &hex) { auto req = request_gen("memory", "read"); auto &alloc = req.GetAllocator(); Value params(kArrayType); params.PushBack(StringRef(dll_name), alloc); params.PushBack(offset, alloc); params.PushBack(size, alloc); req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; hex = (*res)["data"][0].GetString(); delete res; return true; } bool spiceapi::memory_signature(spiceapi::Connection &con, const char *dll_name, const char *signature, const char *replacement, uint32_t offset, uint32_t usage, uint32_t &file_offset) { auto req = request_gen("memory", "signature"); auto &alloc = req.GetAllocator(); Value params(kArrayType); params.PushBack(StringRef(dll_name), alloc); params.PushBack(StringRef(signature), alloc); params.PushBack(StringRef(replacement), alloc); params.PushBack(offset, alloc); params.PushBack(usage, alloc); req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; file_offset = (*res)["data"][0].GetUint(); delete res; return true; } bool spiceapi::touch_read(spiceapi::Connection &con, std::vector &states) { auto req = request_gen("touch", "read"); auto res = response_get(con.request(doc2str(req))); if (!res) return false; auto &data = (*res)["data"]; for (auto &val : data.GetArray()) { TouchState state; state.id = val[0].GetUint64(); state.x = val[1].GetInt64(); state.y = val[2].GetInt64(); states.push_back(state); } delete res; return true; } bool spiceapi::touch_write(spiceapi::Connection &con, std::vector &states) { auto req = request_gen("touch", "write"); auto &alloc = req.GetAllocator(); Value params(kArrayType); for (auto &state : states) { Value state_val(kArrayType); state_val.PushBack(state.id, alloc); state_val.PushBack(state.x, alloc); state_val.PushBack(state.y, alloc); params.PushBack(state_val, alloc); } req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::touch_write_reset(spiceapi::Connection &con, std::vector &states) { auto req = request_gen("touch", "write_reset"); auto &alloc = req.GetAllocator(); Value params(kArrayType); for (auto &state : states) params.PushBack(state.id, alloc); req["params"] = params; auto res = response_get(con.request(doc2str(req))); if (!res) return false; delete res; return true; } bool spiceapi::lcd_info(spiceapi::Connection &con, spiceapi::LCDInfo &info) { auto req = request_gen("lcd", "info"); auto res = response_get(con.request(doc2str(req))); if (!res) return false; auto &data = (*res)["data"][0]; info.enabled = data["enabled"].GetBool(); info.csm = data["csm"].GetString(); info.bri = data["bri"].GetInt(); info.con = data["con"].GetInt(); info.bl = data["bl"].GetInt(); info.red = data["red"].GetInt(); info.green = data["green"].GetInt(); info.blue = data["blue"].GetInt(); delete res; return true; }