From f0e5199b50f488b8b25552c09c136167b311ca22 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 21 Nov 2022 15:33:26 +0100 Subject: [PATCH] Add a CLI tool For now it only prints the JSON representation of the information exposed by libdisplay-info. A JSON schema [1] and libjsonschema [2] are used to encode JSON. [1]: https://json-schema.org/ [2]: https://sr.ht/~emersion/libjsonschema/ Signed-off-by: Simon Ser --- meson.build | 1 + tool/main.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++ tool/meson.build | 40 +++++++++++++++ tool/schema.json | 53 +++++++++++++++++++ 4 files changed, 223 insertions(+) create mode 100644 tool/main.c create mode 100644 tool/meson.build create mode 100644 tool/schema.json diff --git a/meson.build b/meson.build index 4b9a16c..cf25bf8 100644 --- a/meson.build +++ b/meson.build @@ -85,4 +85,5 @@ di_dep = declare_dependency( meson.override_dependency('libdisplay-info', di_dep) subdir('di-edid-decode') +subdir('tool') subdir('test') diff --git a/tool/main.c b/tool/main.c new file mode 100644 index 0000000..7059f46 --- /dev/null +++ b/tool/main.c @@ -0,0 +1,129 @@ +#include +#include +#include + +#include +#include + +#include "schema.h" + +static struct edid * +get_edid(const struct di_edid *edid) +{ + const struct di_edid_vendor_product *vendor_product; + char manufacturer[4]; + struct edid *wire_edid; + struct edid_vendor_product *wire_vendor_product; + + vendor_product = di_edid_get_vendor_product(edid); + + snprintf(manufacturer, sizeof(manufacturer), "%.3s", vendor_product->manufacturer); + + wire_vendor_product = malloc(sizeof(*wire_vendor_product)); + *wire_vendor_product = (struct edid_vendor_product) { + .manufacturer = strdup(manufacturer), + .product = vendor_product->product, + .serial = vendor_product->serial, + .model_year = vendor_product->model_year, + .manufacture_week = vendor_product->manufacture_week, + .manufacture_year = vendor_product->manufacture_year, + }; + + wire_edid = malloc(sizeof(*wire_edid)); + *wire_edid = (struct edid) { + .version = di_edid_get_version(edid), + .revision = di_edid_get_revision(edid), + .vendor_product = wire_vendor_product, + }; + + return wire_edid; +} + +static struct display_info * +get_info(const struct di_info *info) +{ + const struct di_edid *edid; + struct edid *wire_edid = NULL; + struct display_info *wire_info; + + edid = di_info_get_edid(info); + if (edid != NULL) + wire_edid = get_edid(edid); + + wire_info = malloc(sizeof(*wire_info)); + *wire_info = (struct display_info) { + .edid = wire_edid, + }; + + return wire_info; +} + +static const char usage[] = + "usage: libdisplay-info \n"; + +static const struct option long_options[] = { + { "help", no_argument, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +int +main(int argc, char *argv[]) +{ + FILE *in; + static uint8_t raw[32 * 1024]; + size_t size = 0; + struct di_info *info; + int opt; + struct jsch_encoder *enc; + struct display_info *wire_info; + + in = stdin; + while (1) { + int option_index = 0; + opt = getopt_long(argc, argv, "h", long_options, &option_index); + if (opt == -1) + break; + + fprintf(stderr, "%s", usage); + return opt == 'h' ? 0 : 1; + } + + if (argc > 1) { + in = fopen(argv[1], "r"); + if (!in) { + perror("failed to open input file"); + return 1; + } + } + + while (!feof(in)) { + size += fread(&raw[size], 1, sizeof(raw) - size, in); + if (ferror(in)) { + perror("fread failed"); + return 1; + } else if (size >= sizeof(raw)) { + fprintf(stderr, "input too large\n"); + return 1; + } + } + + fclose(in); + + info = di_info_parse_edid(raw, size); + if (!info) { + perror("di_edid_parse failed"); + return 1; + } + + wire_info = get_info(info); + + enc = jsch_encoder_create(stdout); + display_info_encode(wire_info, enc); + jsch_encoder_destroy(enc); + printf("\n"); + + display_info_finish(wire_info); + free(wire_info); + di_info_destroy(info); + return 0; +} diff --git a/tool/meson.build b/tool/meson.build new file mode 100644 index 0000000..128c260 --- /dev/null +++ b/tool/meson.build @@ -0,0 +1,40 @@ +libjsonschema = dependency('libjsonschema') +libjsonschema_native = dependency('libjsonschema', native: true) +libjsonschema_tool_path = libjsonschema_native.get_variable(pkgconfig: 'tool', internal: 'tool') +libjsonschema_tool = find_program(libjsonschema_tool_path, native: true) + +schema = files('schema.json') + +schema_header = custom_target( + 'schema.h', + command: [libjsonschema_tool, 'gen-header', '@INPUT@'], + input: schema, + output: 'schema.h', + capture: true, +) + +schema_code = custom_target( + 'schema.c', + command: [libjsonschema_tool, 'gen-code', '@INPUT@'], + input: schema, + output: 'schema.c', + capture: true, +) + +schema_lib = static_library( + 'schema', + schema_code, + c_args: cc.get_supported_arguments(['-Wno-declaration-after-statement']), + dependencies: libjsonschema, +) + +executable( + 'libdisplay-info', + [ + 'main.c', + schema_header, + ], + dependencies: [di_dep, libjsonschema], + link_with: schema_lib, + install: true, +) diff --git a/tool/schema.json b/tool/schema.json new file mode 100644 index 0000000..a73c62c --- /dev/null +++ b/tool/schema.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "#/$defs/edid", + "$defs": { + "uint16": { + "type": "integer", + "minimum": 0, + "maximum": 65535 + }, + "uint32": { + "type": "integer", + "minimum": 0, + "maximum": 4294967295 + }, + "display_info": { + "type": "object", + "additionalProperties": false, + "properties": { + "edid": { "$ref": "#/$defs/edid" } + } + }, + "edid": { + "type": "object", + "additionalProperties": false, + "properties": { + "version": { "type": "integer" }, + "revision": { "type": "integer" }, + "vendor_product": { "$ref": "#/$defs/edid_vendor_product" } + }, + "required": [ + "version", + "revision", + "vendor_product" + ] + }, + "edid_vendor_product": { + "type": "object", + "additionalProperties": false, + "properties": { + "manufacturer": { "type": "string" }, + "product": { "$ref": "#/$defs/uint16" }, + "serial": { "$ref": "#/$defs/uint32" }, + "model_year": { "type": "integer" }, + "manufacture_week": { "type": "integer" }, + "manufacture_year": { "type": "integer" } + }, + "required": [ + "manufacturer", + "product" + ] + } + } +}