/* Calibration session, proposals, saved profiles and model discovery. */ static bool calibration_session(void *h, void *m, void *ctx) { (void)ctx; const char *p = payload(m); if (!strcmp(p, "{\"enabled\":true}")) { calibration_until = milliseconds() + 110000; if (capture && vt_preset(capture, 0) != 0) { calibration_until = 0; return respond(h, m, "{\"returnValue\":false,\"errorText\":\"Cannot select full-screen " "calibration capture\"}"); } capture_preset = letterbox_mode = 0; settling = 2; pending_letterbox = -1; } else if (!strcmp(p, "{\"enabled\":false}")) calibration_until = 0; else return respond(h, m, "{\"returnValue\":false,\"errorText\":\"Expected enabled boolean\"}"); return respond(h, m, "{\"returnValue\":true}"); } static Calibration calibration_draft; static char calibration_message[256]; static bool report_calibration(void *h, void *m, void *ctx) { if (!playback_json.lib) return respond(h, m, "{\"returnValue\":false,\"errorText\":\"JSON-C is unavailable\"}"); (void)ctx; void *root = playback_json.parse(payload(m)), *message = playback_field(&playback_json, root, "message"); bool valid = message && playback_json.type(message) == 6 && strlen(playback_json.string(message)) < sizeof(calibration_message); if (valid) snprintf(calibration_message, sizeof(calibration_message), "%s", playback_json.string(message)); if (root) playback_json.put(root); return respond( h, m, valid ? "{\"returnValue\":true}" : "{\"returnValue\":false,\"errorText\":\"Invalid calibration result message\"}"); } static bool draft_calibration(void *h, void *m, void *ctx) { (void)ctx; Calibration next = {0}; if (!playback_json.lib || !calibration_parse(&playback_json, payload(m), &next) || next.kind != CAL_CUSTOM || next.count < 4 || strcmp(next.model, tv_model)) return respond(h, m, "{\"returnValue\":false,\"errorText\":\"Invalid measured model profile\"}"); calibration_draft = next; return respond(h, m, "{\"returnValue\":true}"); } static bool model_busy; static unsigned long model_token; static uint64_t model_deadline, next_model_probe; static bool model_reply(void *h, void *m, void *ctx) { (void)h; (void)ctx; model_busy = false; model_token = 0; void *root = playback_json.parse(payload(m)), *model = playback_field(&playback_json, root, "modelName"); if (playback_true(&playback_json, root, "returnValue") && model && playback_json.type(model) == 6 && calibration_model_valid(playback_json.string(model))) { snprintf(tv_model, sizeof(tv_model), "%s", playback_json.string(model)); calibration_generation++; layout_refresh_reset(milliseconds()); } if (root) playback_json.put(root); return true; } static void model_tick(uint64_t now) { if (model_busy && now >= model_deadline) { LSError e; error_init(&e); cancel_call(service_handle, model_token, &e); error_free(&e); model_busy = false; model_token = 0; } if (!tv_model[0] && !model_busy && now >= next_model_probe) { LSError e; error_init(&e); model_busy = call_once(service_handle, "luna://com.webos.service.tv.systemproperty/getSystemInfo", "{\"keys\":[\"modelName\"]}", model_reply, NULL, &model_token, &e); error_free(&e); model_deadline = now + 3000; next_model_probe = now + 60000; } } static bool set_calibration(void *h, void *m, void *ctx) { (void)ctx; Calibration next = calibration; if (!playback_json.lib || !calibration_parse(&playback_json, payload(m), &next)) return respond( h, m, "{\"returnValue\":false,\"errorText\":\"Select a valid profile; custom profiles need a " "model and 2-16 sorted rim points (position 0-4, region 0-15)\"}"); if (!calibration_save(CALIBRATION_PREF, &next)) return respond(h, m, "{\"returnValue\":false,\"errorText\":\"Cannot save calibration profile\"}"); calibration = next; calibration_generation++; layout_refresh_reset(milliseconds()); return respond(h, m, "{\"returnValue\":true}"); }