#include #include #include #include #include "frozen/frozen.h" #define EDID_LENGTH 128 enum edid_analog_display_t { EDID_DISPLAY_TYPE_MONOCHROME_OR_GRAYSCALE = 0, EDID_DISPLAY_TYPE_RGB_COLOR = 1, EDID_DISPLAY_TYPE_NON_RGB_COLOR = 2, EDID_DISPLAY_TYPE_UNDEFINED = 3 }; enum edid_aspect_ratio_t { EDID_ASPECT_RATIO_16_10 = 0, EDID_ASPECT_RATIO_4_3 = 1, EDID_ASPECT_RATIO_5_4 = 2, EDID_ASPECT_RATIO_16_9 = 3 }; enum edid_sync_mode_t { EDID_SYNC_MODE_ANALOG = 0, EDID_SYNC_MODE_DIGITAL_COMPOSITE = 2, EDID_SYNC_MODE_DIGITAL_SEPERATE = 3 }; typedef struct __attribute__ (( packed )) { uint8_t x_resolution; uint8_t vertical_frequency:6; uint8_t aspect_ratio :2; } standard_timing_information_t; typedef struct __attribute__ (( packed )) { uint16_t pixel_clock; // 0-1 uint8_t horizontal_active_pixels_lsbs; // 2 uint8_t horizontal_blanking_pixels_lsbs; // 3 uint8_t horizontal_blanking_pixels_msbs :4; // 4 uint8_t horizontal_active_pixels_msbs :4; uint8_t vertical_active_lines_lsbs; // 5 uint8_t vertical_blanking_lines_lsbs; // 6 uint8_t vertical_blanking_lines_msbs :4; // 7 uint8_t vertical_active_lines_msbs :4; uint8_t horizontal_front_porch_pixels_lsbs; // 8 uint8_t horizontal_sync_pulse_pixels_lsbs; // 9 uint8_t vertical_sync_pulse_lines_lsbs :4; // 10 uint8_t vertical_front_porch_lines_lsbs :4; uint8_t vertical_sync_pulse_lines_msbs :2; // 11 uint8_t vertical_front_porch_lines_msbs :2; uint8_t horizontal_sync_pulse_pixels_msbs :2; uint8_t horizontal_front_porch_pixels_msbs :2; uint8_t horizontal_image_size_lsbs; // 12 uint8_t vertical_image_size_lsbs; uint8_t vertical_image_size_msbs :4; uint8_t horizontal_image_size_msbs :4; uint8_t horizontal_border_pixels; uint8_t vertical_border_lines; // Feature bitmap union __attribute__ (( packed )) { struct __attribute__ (( packed )) { uint8_t stereo_mode_lsb :1; uint8_t sync_on_red_blue :1; uint8_t vertical_sync_serration :1; uint8_t sync_type :1; uint8_t analog_sync :1; uint8_t stereo_mode_msbs :2; uint8_t interlaced :1; } analog; struct __attribute__ (( packed )) { uint8_t stereo_mode_lsb :1; uint8_t reserved :1; uint8_t vertical_sync_polarity :1; uint8_t digital_composite_sync :2; uint8_t stereo_mode_msbs :2; uint8_t interlaced :1; } digital_composite; struct __attribute__ (( packed )) { uint8_t stereo_mode_lsb :1; uint8_t horizontal_sync_polarity :1; uint8_t vertical_sync_serration :1; uint8_t digital_seperate_sync :2; uint8_t stereo_mode_msbs :2; uint8_t interlaced :1; } digital_seperate; } features; } detailed_timing_descriptor_t; typedef struct __attribute__ (( packed )) { uint16_t display_descriptor; uint8_t reserved; uint8_t display_range_limits_descriptor; struct __attribute__ (( packed )) { uint8_t vertical :2; uint8_t horizontal :2; uint8_t reserved :4; } rate_offsets; struct __attribute__ (( packed )) { uint8_t minimum; uint8_t maximum; } vertical_field_rate; struct __attribute__ (( packed )) { uint8_t minimum; uint8_t maximum; } horizontal_line_rate; uint8_t maximum_pixel_clock_mhz; // In 10 MHz units uint8_t extended_timing_information_type; uint8_t video_timing_params[7]; } range_limits_descriptor_t; typedef struct __attribute__ (( packed )) { uint16_t display_descriptor; uint8_t reserved0; uint8_t descriptor_type; uint8_t reserved1; uint8_t descriptor_data[13]; } display_descriptor_t; typedef struct __attribute__ (( packed )) { /*! Header information, 20 bytes */ struct __attribute__ (( packed )) { uint64_t preamble; uint8_t manufacturer_id[2]; uint16_t product_code; uint32_t serial_number; uint8_t week_of_manufacture; uint8_t year_of_manufacture; uint8_t edid_version; uint8_t edid_revision; } header; /*! Basic display parameters, 5 bytes */ struct __attribute__ (( packed )) { union __attribute__ (( packed )) { struct __attribute__ (( packed )) { uint8_t video_interface : 4; uint8_t bit_depth : 3; uint8_t input_type : 1; // 1 for digital } digital; struct __attribute__ (( packed )) { uint8_t vsync_serrated: 1; uint8_t sync_on_green : 1; uint8_t composite_sync: 1; uint8_t seperate_sync : 1; uint8_t blank_to_black: 1; uint8_t levels : 2; uint8_t input_type : 1; // 0 for analog } analog; } video_input_parameters; // 1 byte uint8_t horizontal_screen_size; uint8_t vertical_screen_size; uint8_t gamma; struct __attribute__ (( packed )) { uint8_t continuous_timings : 1; uint8_t preferred_timing_mode : 1; uint8_t standard_srgb : 1; uint8_t display_type : 2; uint8_t dpms_active_off_supported : 1; uint8_t dpms_suspend_supported : 1; uint8_t dpms_standby_supported : 1; } features; } basic_display_parameters; /*! Chromaticity coordinates. 10-bit CIE 1931 xy coordinates for red, green, * blue, and white point, 10 bytes */ struct __attribute__ (( packed )) { struct __attribute__ (( packed )) { uint8_t green_y : 2; uint8_t green_x : 2; uint8_t red_y : 2; uint8_t red_x : 2; } red_green_lsbs; struct __attribute__ (( packed )) { uint8_t white_y : 2; uint8_t white_x : 2; uint8_t blue_y : 2; uint8_t blue_x : 2; } blue_white_lsbs; uint8_t red_x_msbs; uint8_t red_y_msbs; uint8_t green_x_msbs; uint8_t green_y_msbs; uint8_t blue_x_msbs; uint8_t blue_y_msbs; uint8_t white_x_msbs; uint8_t white_y_msbs; } chromaticity_coordinates; /*! Established timing bitmap. Supported bitmap for (formerly) very common timing modes. 3 bytes */ struct __attribute__ (( packed )) { uint8_t m800_600_60 : 1; uint8_t m800_600_56 : 1; uint8_t m640_480_75 : 1; uint8_t m640_480_72 : 1; uint8_t m640_480_67 : 1; uint8_t m640_480_60 : 1; uint8_t m720_400_88 : 1; uint8_t m720_400_70 : 1; uint8_t m1280_1024_75: 1; uint8_t m1024_768_75 : 1; uint8_t m1024_768_70 : 1; uint8_t m1024_768_60 : 1; uint8_t m1024_768_87 : 1; uint8_t m832_624_75 : 1; uint8_t m800_600_75 : 1; uint8_t m800_600_72 : 1; uint8_t reserved : 7; uint8_t m1152_870_75 : 1; } common_timing_modes; /*! Standard timing information. Up to 8 2-byte fields describing standard display modes. Unused fields are filled with 01 01 hex. 16 bytes */ standard_timing_information_t timings[8]; detailed_timing_descriptor_t detailed_timing_descriptor; range_limits_descriptor_t range_limits_descriptor; display_descriptor_t display_name_descriptor; display_descriptor_t display_serial_number_descriptor; uint8_t number_extensions; uint8_t checksum; } edid_t; static int stp_round(const float in) { return (int)(in < 0 ? (in - 0.5) : (in + 0.5)); } /** * @brief test function to show buffer */ static void disp_buf(uint8_t *buf, int len) { int i; for (i = 0; i < len; i++) { printf("%02x ", buf[i]); if ((i + 1) % 16 == 0) { printf("\n"); } } printf("\n"); } static size_t file_to_str(unsigned char** str, const char const* filename) { size_t length; FILE * f = fopen (filename, "rb"); if (f) { fseek (f, 0, SEEK_END); length = ftell (f); fseek (f, 0, SEEK_SET); *str = (unsigned char*)malloc(length); if (*str) { fread (*str, 1, length, f); } fclose (f); } else { printf("File pointer is NULL..\n"); } return length; } static void generate_preamble(edid_t* edid) { memset((uint8_t*)&(edid->header.preamble)+0, 0x00, 1); memset((uint8_t*)&(edid->header.preamble)+1, 0xFF, 6); memset((uint8_t*)&(edid->header.preamble)+7, 0x00, 1); } static int generate_header(edid_t* edid, unsigned char* json_str, size_t json_len) { char* multi_use_str; unsigned int multi_use_int; if (edid && json_str) { // Manufacturer ID json_scanf( json_str, json_len, "{header: {manufacturer_id: %Q}", &multi_use_str); if (strlen(multi_use_str) == 3) { multi_use_int = 0; multi_use_int |= ((0x1F & (multi_use_str[0]-64)) << 10)| // First letter ((0x1F & (multi_use_str[1]-64)) << 5) | // Second letter ((0x1F & (multi_use_str[2]-64)) << 0); // Third letter edid->header.manufacturer_id[0] = multi_use_int >> 8; edid->header.manufacturer_id[1] = multi_use_int; } else { printf("Error: JSON file format is wrong somewhere arround manufacturer\ ID.\n"); return 1; } // %Q mallocs a string free(multi_use_str); // Product code json_scanf(json_str, json_len, "{header: {product_code: %d}", &multi_use_int); edid->header.product_code = 0xFFFF & multi_use_int; // Serial number json_scanf(json_str, json_len, "{header: {serial_number: %d}", &multi_use_int); edid->header.serial_number = 0xFFFFFFFF & multi_use_int; // Week of manufacture json_scanf( json_str, json_len, "{header: {week_of_manufacture: %d}", &multi_use_int); edid->header.week_of_manufacture = 0xFF & multi_use_int; // Year of manufacture json_scanf( json_str, json_len, "{header: {year_of_manufacture: %d}", &multi_use_int); edid->header.year_of_manufacture = 0xFF & (multi_use_int - 1990); // EDID version json_scanf(json_str, json_len, "{header: {edid_version: %d}", &multi_use_int); edid->header.edid_version = 0xFF & multi_use_int; // EDID revision json_scanf(json_str, json_len, "{header: {edid_revision: %d}", &multi_use_int); edid->header.edid_revision = 0xFF & multi_use_int; } else { printf("One of either edid or json_str is NULL.\n"); return 2; } return 0; } static int generate_basic_display_parameters( edid_t* edid, unsigned char* json_str, size_t json_len) { char* multi_use_str; float multi_use_flt0; float multi_use_flt1; unsigned int multi_use_int; bool multi_use_bool; if (edid && json_str) { // Input type analog or digital json_scanf( json_str, json_len, "{basic_display_parameters: {video_input_parameters: \ {input_type: %Q}}}", &multi_use_str); if (strcmp(multi_use_str, "analog") == 0) { edid->basic_display_parameters.video_input_parameters .analog.input_type = 0; // Levels json_scanf( json_str, json_len, "{basic_display_parameters: {video_input_parameters: \ {levels: {upper: %f}}}", &multi_use_flt0); json_scanf( json_str, json_len, "{basic_display_parameters: {video_input_parameters: \ {levels: {lower: %f}}}", &multi_use_flt1); if (multi_use_flt0 == 0.7f && multi_use_flt1 == -0.3f) { multi_use_int = 0; } else if (multi_use_flt0 == 0.714f && multi_use_flt1 == -0.286f) { multi_use_int = 1; } else if (multi_use_flt0 == 1.0f && multi_use_flt1 == -0.4f) { multi_use_int = 2; } else if (multi_use_flt0 == 0.7f && multi_use_flt1 == 0.0f) { multi_use_int = 3; } else { printf("Error: The levels %f/%f are not conforming to the standard.\n", multi_use_flt0, multi_use_flt1); } edid->basic_display_parameters.video_input_parameters .analog.levels = 0x3 & multi_use_int; // Blank to black json_scanf( json_str, json_len, "{basic_display_parameters: {video_input_parameters: \ {blank_to_black: %B}}}", &multi_use_bool); edid->basic_display_parameters.video_input_parameters .analog.blank_to_black = 0x1 & multi_use_bool; // Seperate sync json_scanf( json_str, json_len, "{basic_display_parameters: {video_input_parameters: \ {seperate_sync: %B}}}", &multi_use_bool); edid->basic_display_parameters.video_input_parameters .analog.seperate_sync = 0x1 & multi_use_bool; // Composite sync json_scanf( json_str, json_len, "{basic_display_parameters: {video_input_parameters: \ {composite_sync: %B}}}", &multi_use_bool); edid->basic_display_parameters.video_input_parameters .analog.composite_sync = 0x1 & multi_use_bool; // Sync on green json_scanf( json_str, json_len, "{basic_display_parameters: {video_input_parameters: \ {sync_on_green: %B}}}", &multi_use_bool); edid->basic_display_parameters.video_input_parameters .analog.sync_on_green = 0x1 & multi_use_bool; // Vsync serrated json_scanf( json_str, json_len, "{video_input_parameters: {sync_on_green: %B}}", &multi_use_bool); edid->basic_display_parameters.video_input_parameters .analog.blank_to_black = 0x1 & multi_use_bool; } else if (strcmp(multi_use_str, "digital") == 0) { printf("Digital video configuration is not yet supported.\n"); return 1; } else { printf("Error: JSON file format is wrong somewhere around\ the video input params.\n"); return 2; } // %Q mallocs a string free(multi_use_str); // Horizontal screen size json_scanf( json_str, json_len, "{basic_display_parameters: {horizontal_screen_size: %d}}", &multi_use_int); edid->basic_display_parameters .horizontal_screen_size = multi_use_int; // Vertical screen size json_scanf( json_str, json_len, "{basic_display_parameters: {vertical_screen_size: %d}}", &multi_use_int); edid->basic_display_parameters .vertical_screen_size = multi_use_int; // Horizontal screen size json_scanf( json_str, json_len, "{basic_display_parameters: {gamma: %f}}", &multi_use_flt0); edid->basic_display_parameters .gamma = (multi_use_flt0-1)*100; // Display Power Management Signaling (DPMS) // Standby json_scanf( json_str, json_len, "{basic_display_parameters: {features: {dpms: \ {standby_supported: %B}}}}", &multi_use_bool); edid->basic_display_parameters .features.dpms_standby_supported = 0x1 & multi_use_bool; // Suspend json_scanf( json_str, json_len, "{basic_display_parameters: {features: {dpms: \ {suspend_supported: %B}}}}", &multi_use_bool); edid->basic_display_parameters .features.dpms_suspend_supported = 0x1 & multi_use_bool; // Active-off json_scanf( json_str, json_len, "{basic_display_parameters: {features: {dpms: \ {active_off_supported: %B}}}}", &multi_use_bool); edid->basic_display_parameters .features.dpms_active_off_supported = 0x1 & multi_use_bool; // Display type char a_str[] = "analog"; char d_str[] = "digital"; json_scanf( json_str, json_len, "{basic_display_parameters: {features: {display_type: %Q}}}", &multi_use_str); // Create substrings for comparison memcpy(a_str, multi_use_str, strlen(a_str)); memcpy(d_str, multi_use_str, strlen(d_str)); if (strcmp(a_str, "analog") == 0) { // Remove "analog_" memcpy( multi_use_str, multi_use_str+strlen(a_str)+1, strlen(multi_use_str)-strlen(a_str)); if (strcmp(multi_use_str, "monochrome_or_grayscale") == 0) { edid->basic_display_parameters .features.display_type = 0x3 & EDID_DISPLAY_TYPE_MONOCHROME_OR_GRAYSCALE; } else if (strcmp(multi_use_str, "rgb_color") == 0) { edid->basic_display_parameters .features.display_type = 0x3 & ~EDID_DISPLAY_TYPE_RGB_COLOR; } else if (strcmp(multi_use_str, "non_rgb_color") == 0) { edid->basic_display_parameters .features.display_type = 0x3 & ~EDID_DISPLAY_TYPE_NON_RGB_COLOR; } else if (strcmp(multi_use_str, "undefined") == 0) { edid->basic_display_parameters .features.display_type = 0x3 & EDID_DISPLAY_TYPE_UNDEFINED; } else { printf("Error: Unknown analog display_type.\n"); return 3; } } else if (strcmp(d_str, "digital") == 0) { printf("Error: Digital format is not supported yet.\n"); return 4; } else { printf("Error: JSON format is wrong. First word needs of display_type \ should either be analog or digital.\n"); } // %Q mallocs a string, which needs to be freed free(multi_use_str); // Standard sRGB json_scanf( json_str, json_len, "{basic_display_parameters: {features: {standard_srgb: %B}}}", &multi_use_bool); edid->basic_display_parameters .features.standard_srgb = 0x1 & multi_use_bool; // Prefered timing mode json_scanf( json_str, json_len, "{basic_display_parameters: {features: \ {preferred_timing_mode: %B}}}", &multi_use_bool); edid->basic_display_parameters .features.preferred_timing_mode = 0x1 & multi_use_bool; // Continuous timings json_scanf( json_str, json_len, "{basic_display_parameters: {features: {continuous_timings: %B}}}", &multi_use_bool); edid->basic_display_parameters .features.continuous_timings = 0x1 & multi_use_bool; } else { printf("Error: One of either edid or json_str is NULL.\n"); return 5; } return 0; } static int generate_chromaticity_coordinates( edid_t* edid, unsigned char* json_str, size_t json_len) { float multi_use_flt; unsigned int multi_use_int; if (edid && json_str) { // Red x json_scanf( json_str, json_len, "{chromaticity_coordinates: {red_x: %f}}", &multi_use_flt); multi_use_int = stp_round(1024.0f * multi_use_flt); edid->chromaticity_coordinates.red_green_lsbs.red_x = 0x3 & multi_use_int; edid->chromaticity_coordinates.red_x_msbs = 0xFF & multi_use_int >> 2; // Red y json_scanf( json_str, json_len, "{chromaticity_coordinates: {red_y: %f}}", &multi_use_flt); multi_use_int = stp_round(1024.0f * multi_use_flt); edid->chromaticity_coordinates.red_green_lsbs.red_y = 0x3 & multi_use_int; edid->chromaticity_coordinates.red_y_msbs = 0xFF & multi_use_int >> 2; // Green x json_scanf( json_str, json_len, "{chromaticity_coordinates: {green_x: %f}}", &multi_use_flt); multi_use_int = stp_round(1024.0f * multi_use_flt); edid->chromaticity_coordinates.red_green_lsbs.green_x = 0x3 & multi_use_int; edid->chromaticity_coordinates.green_x_msbs = 0xFF & multi_use_int >> 2; // Green y json_scanf( json_str, json_len, "{chromaticity_coordinates: {green_y: %f}}", &multi_use_flt); multi_use_int = stp_round(1024.0f * multi_use_flt); edid->chromaticity_coordinates.red_green_lsbs.green_y = 0x3 & multi_use_int; edid->chromaticity_coordinates.green_y_msbs = 0xFF & multi_use_int >> 2; // Blue x json_scanf( json_str, json_len, "{chromaticity_coordinates: {blue_x: %f}}", &multi_use_flt); multi_use_int = stp_round(1024.0f * multi_use_flt); edid->chromaticity_coordinates.blue_white_lsbs.blue_x = 0x3 & multi_use_int; edid->chromaticity_coordinates.blue_x_msbs = 0xFF & multi_use_int >> 2; // Blue y json_scanf( json_str, json_len, "{chromaticity_coordinates: {blue_y: %f}}", &multi_use_flt); multi_use_int = stp_round(1024.0f * multi_use_flt); edid->chromaticity_coordinates.blue_white_lsbs.blue_y = 0x3 & multi_use_int; edid->chromaticity_coordinates.blue_y_msbs = 0xFF & multi_use_int >> 2; // White x json_scanf( json_str, json_len, "{chromaticity_coordinates: {white_x: %f}}", &multi_use_flt); multi_use_int = stp_round(1024.0f * multi_use_flt); edid->chromaticity_coordinates.blue_white_lsbs.white_x = 0x3 & multi_use_int; edid->chromaticity_coordinates.white_x_msbs = 0xFF & multi_use_int >> 2; // White y json_scanf( json_str, json_len, "{chromaticity_coordinates: {white_y: %f}}", &multi_use_flt); multi_use_int = stp_round(1024.0f * multi_use_flt); edid->chromaticity_coordinates.blue_white_lsbs.white_y = 0x3 & multi_use_int; edid->chromaticity_coordinates.white_y_msbs = 0xFF & multi_use_int >> 2; } else { printf("Error: One of either edid or json_str is NULL.\n"); return 1; } return 0; } static int generate_common_timing_modes( edid_t* edid, unsigned char* json_str, size_t json_len) { bool multi_use_bool; if (edid && json_str) { json_scanf( json_str, json_len, "{common_timing_modes: {m720_400_70: %B}}", &multi_use_bool); edid->common_timing_modes.m720_400_70 = 0x1 & multi_use_bool; json_scanf( json_str, json_len, "{common_timing_modes: {m720_400_88: %B}}", &multi_use_bool); edid->common_timing_modes.m720_400_88 = 0x1 & multi_use_bool; json_scanf( json_str, json_len, "{common_timing_modes: {m640_480_60: %B}}", &multi_use_bool); edid->common_timing_modes.m640_480_60 = 0x1 & multi_use_bool; json_scanf( json_str, json_len, "{common_timing_modes: {m640_480_67: %B}}", &multi_use_bool); edid->common_timing_modes.m640_480_67 = 0x1 & multi_use_bool; json_scanf( json_str, json_len, "{common_timing_modes: {m640_480_72: %B}}", &multi_use_bool); edid->common_timing_modes.m640_480_72 = 0x1 & multi_use_bool; json_scanf( json_str, json_len, "{common_timing_modes: {m640_480_75: %B}}", &multi_use_bool); edid->common_timing_modes.m640_480_75 = 0x1 & multi_use_bool; json_scanf( json_str, json_len, "{common_timing_modes: {m800_600_56: %B}}", &multi_use_bool); edid->common_timing_modes.m800_600_56 = 0x1 & multi_use_bool; json_scanf( json_str, json_len, "{common_timing_modes: {m800_600_60: %B}}", &multi_use_bool); edid->common_timing_modes.m800_600_60 = 0x1 & multi_use_bool; json_scanf( json_str, json_len, "{common_timing_modes: {m800_600_72: %B}}", &multi_use_bool); edid->common_timing_modes.m800_600_72 = 0x1 & multi_use_bool; json_scanf( json_str, json_len, "{common_timing_modes: {m800_600_75: %B}}", &multi_use_bool); edid->common_timing_modes.m800_600_75 = 0x1 & multi_use_bool; json_scanf( json_str, json_len, "{common_timing_modes: {m832_624_75: %B}}", &multi_use_bool); edid->common_timing_modes.m832_624_75 = 0x1 & multi_use_bool; json_scanf( json_str, json_len, "{common_timing_modes: {m1024_768_87: %B}}", &multi_use_bool); edid->common_timing_modes.m1024_768_87 = 0x1 & multi_use_bool; json_scanf( json_str, json_len, "{common_timing_modes: {m1024_768_60: %B}}", &multi_use_bool); edid->common_timing_modes.m1024_768_60 = 0x1 & multi_use_bool; json_scanf( json_str, json_len, "{common_timing_modes: {m1024_768_70: %B}}", &multi_use_bool); edid->common_timing_modes.m1024_768_70 = 0x1 & multi_use_bool; json_scanf( json_str, json_len, "{common_timing_modes: {m1024_768_75: %B}}", &multi_use_bool); edid->common_timing_modes.m1024_768_75 = 0x1 & multi_use_bool; json_scanf( json_str, json_len, "{common_timing_modes: {m1280_1024_75: %B}}", &multi_use_bool); edid->common_timing_modes.m1280_1024_75 = 0x1 & multi_use_bool; json_scanf( json_str, json_len, "{common_timing_modes: {m1152_870_75: %B}}", &multi_use_bool); edid->common_timing_modes.m1152_870_75 = 0x1 & multi_use_bool; } else { printf("Error: One of either edid or json_str is NULL.\n"); return 1; } return 0; } static int generate_timings(edid_t* edid, unsigned char* json_str, size_t json_len) { struct json_token multi_use_token; float multi_use_flt; int multi_use_int; char* multi_use_str; if (edid && json_str) { int i = 0; for (i = 0; json_scanf_array_elem(json_str, json_len, ".timings", i, &multi_use_token) > 0; i++) { // t.type == JSON_TYPE_OBJECT // X resolution json_scanf(multi_use_token.ptr, multi_use_token.len, "{x_resolution: %f}", &multi_use_flt); edid->timings[i].x_resolution = stp_round(multi_use_flt/8-31); printf("res> %f\n", multi_use_flt); // Aspect ratio json_scanf(multi_use_token.ptr, multi_use_token.len, "{aspect_ratio: %Q}", &multi_use_str); if (strcmp(multi_use_str, "16:10") == 0) { edid->timings[i].aspect_ratio = 0x3 & EDID_ASPECT_RATIO_16_10; } else if (strcmp(multi_use_str, "4:3") == 0) { edid->timings[i].aspect_ratio = 0x3 & EDID_ASPECT_RATIO_4_3; } else if (strcmp(multi_use_str, "5:4") == 0) { edid->timings[i].aspect_ratio = 0x3 & EDID_ASPECT_RATIO_5_4; } else if (strcmp(multi_use_str, "16:9") == 0) { edid->timings[i].aspect_ratio = 0x3 & EDID_ASPECT_RATIO_16_9; } else { printf("Error: Aspect ratio not supported"); return 1; } // Free string that has been allocated in memory free(multi_use_str); // Vertical frequency json_scanf(multi_use_token.ptr, multi_use_token.len, "{vertical_frequency: %d}", &multi_use_int); if (multi_use_int >= 60) { edid->timings[i].vertical_frequency = multi_use_int-60; } else { printf("Error: Vertical frequency cannot be lower than 60 Hz.\n"); return 1; } } } else { printf("Error: One of either edid or json_str is NULL.\n"); return 1; } return 0; } static int generate_detailed_timing_descriptor( edid_t* edid, unsigned char* json_str, size_t json_len) { unsigned int multi_use_int; float multi_use_float; struct json_token multi_use_token; bool multi_use_bool; char* multi_use_str; if (edid && json_str) { // Pixel clock json_scanf( json_str, json_len, "{detailed_timing_descriptor: {pixel_clock_mhz: %f}}", &multi_use_float); /* The data is stored as 10 kHz unitsi in the EDID structure. It is a float representing MHz in the JSON file. */ edid->detailed_timing_descriptor.pixel_clock = stp_round(multi_use_float/0.01f); // Horizontal active pixels json_scanf( json_str, json_len, "{detailed_timing_descriptor: {horizontal_active_pixels: %d}}", &multi_use_int); edid->detailed_timing_descriptor .horizontal_active_pixels_lsbs = 0xFF & multi_use_int; edid->detailed_timing_descriptor .horizontal_active_pixels_msbs = 0x0F & (multi_use_int >> 8); // Horizontal blanking pixels json_scanf( json_str, json_len, "{detailed_timing_descriptor: {horizontal_blanking_pixels: %d}}", &multi_use_int); edid->detailed_timing_descriptor .horizontal_blanking_pixels_lsbs = 0xFF & multi_use_int; edid->detailed_timing_descriptor .horizontal_blanking_pixels_msbs = 0x0F & (multi_use_int >> 8); // Vertical active lines json_scanf( json_str, json_len, "{detailed_timing_descriptor: {vertical_active_lines: %d}}", &multi_use_int); edid->detailed_timing_descriptor .vertical_active_lines_lsbs = 0xFF & multi_use_int; edid->detailed_timing_descriptor .vertical_active_lines_msbs = 0x0F & (multi_use_int >> 8); // Vertical blanking lines json_scanf( json_str, json_len, "{detailed_timing_descriptor: {vertical_blanking_lines: %d}}", &multi_use_int); edid->detailed_timing_descriptor .vertical_blanking_lines_lsbs = 0xFF & multi_use_int; edid->detailed_timing_descriptor .vertical_blanking_lines_msbs = 0x0F & (multi_use_int >> 8); // Horizontal front porch pixels json_scanf( json_str, json_len, "{detailed_timing_descriptor: {horizontal_front_porch_pixels: %d}}", &multi_use_int); edid->detailed_timing_descriptor .horizontal_front_porch_pixels_lsbs = 0xFF & multi_use_int; edid->detailed_timing_descriptor .horizontal_front_porch_pixels_msbs = 0x03 & (multi_use_int >> 8); // Horizontal sync pulse pixels json_scanf( json_str, json_len, "{detailed_timing_descriptor: {horizontal_sync_pulse_pixels: %d}}", &multi_use_int); edid->detailed_timing_descriptor .horizontal_sync_pulse_pixels_lsbs = 0xFF & multi_use_int; edid->detailed_timing_descriptor .horizontal_sync_pulse_pixels_msbs = 0x03 & (multi_use_int >> 8); // Vertical front porch lines json_scanf( json_str, json_len, "{detailed_timing_descriptor: {vertical_front_porch_lines: %d}}", &multi_use_int); edid->detailed_timing_descriptor .vertical_front_porch_lines_lsbs = 0x0F & multi_use_int; edid->detailed_timing_descriptor .vertical_front_porch_lines_msbs = 0x03 & (multi_use_int >> 4); // Vertical sync pulse lines json_scanf( json_str, json_len, "{detailed_timing_descriptor: {vertical_sync_pulse_lines: %d}}", &multi_use_int); edid->detailed_timing_descriptor .vertical_sync_pulse_lines_lsbs = 0x0F & multi_use_int; edid->detailed_timing_descriptor .vertical_sync_pulse_lines_msbs = 0x03 & (multi_use_int >> 4); // Horizontal image size json_scanf( json_str, json_len, "{detailed_timing_descriptor: {horizontal_image_size_mm: %d}}", &multi_use_int); edid->detailed_timing_descriptor .horizontal_image_size_lsbs = 0xFF & multi_use_int; edid->detailed_timing_descriptor .horizontal_image_size_msbs = 0x0F & (multi_use_int >> 8); // Vertical image size json_scanf( json_str, json_len, "{detailed_timing_descriptor: {vertical_image_size_mm: %d}}", &multi_use_int); edid->detailed_timing_descriptor .vertical_image_size_lsbs = 0xFF & multi_use_int; edid->detailed_timing_descriptor .vertical_image_size_msbs = 0x0F & (multi_use_int >> 8); // Horizontal border pixels json_scanf( json_str, json_len, "{detailed_timing_descriptor: {horizontal_border_pixels: %d}}", &multi_use_int); edid->detailed_timing_descriptor .horizontal_border_pixels = 0xFF & multi_use_int; // Vertical border lines json_scanf( json_str, json_len, "{detailed_timing_descriptor: {vertical_border_lines: %d}}", &multi_use_int); edid->detailed_timing_descriptor .vertical_border_lines = 0xFF & multi_use_int; // Sync features bitmap json_scanf( json_str, json_len, "{detailed_timing_descriptor: {stereo_mode: %Q}}", &multi_use_str); if (strcmp(multi_use_str, "none") == 0) { multi_use_int = 0; } else { printf("Error: This stereo mode is not implemented yet.\n"); return 1; } free(multi_use_str); edid->detailed_timing_descriptor .features.digital_seperate.stereo_mode_lsb = 0x1 & multi_use_int; edid->detailed_timing_descriptor .features.digital_seperate.stereo_mode_msbs = 0x3 & (multi_use_int >> 1); // Interlaced json_scanf( json_str, json_len, "{detailed_timing_descriptor: {interlaced: %B}}", &multi_use_bool); edid->detailed_timing_descriptor .features.digital_seperate.interlaced = multi_use_bool; // Sync details if (json_scanf(json_str, json_len, "{detailed_timing_descriptor: { digital_seperate_sync: %T}}", &multi_use_token) > 0) { // Set sync mode edid->detailed_timing_descriptor .features.digital_seperate.digital_seperate_sync = 0x3 & EDID_SYNC_MODE_DIGITAL_SEPERATE; // Vertical sync serration json_scanf( multi_use_token.ptr, multi_use_token.len, "{vertical_sync_serration: %B}", &multi_use_bool); edid->detailed_timing_descriptor .features.digital_seperate.vertical_sync_serration = multi_use_bool; // Horizontal sync polarity json_scanf( multi_use_token.ptr, multi_use_token.len, "{horizontal_sync_polarity: %Q}", &multi_use_str); if (strcmp(multi_use_str, "positive") == 0) { multi_use_bool = true; } else if (strcmp(multi_use_str, "negative") == 0) { multi_use_bool = false; } else { printf("Error: The horizontal sync polarity can either be positive or negative (JSON string).\n"); return 1; } edid->detailed_timing_descriptor .features.digital_seperate.horizontal_sync_polarity = multi_use_bool; free(multi_use_str); } else { printf("Error: Could not parse JSON file somewhere arround sync \ features in detailed timing descriptor.\n"); return 1; } } else { printf("Error: One of either edid or json_str is NULL.\n"); return 1; } return 0; } static int generate_range_limit_descriptor( edid_t* edid, unsigned char* json_str, size_t json_len) { char* multi_use_str; unsigned multi_use_int; if (edid && json_str) { edid->range_limits_descriptor.display_descriptor = 0; edid->range_limits_descriptor.reserved = 0; edid->range_limits_descriptor.display_range_limits_descriptor = 0xFD; // Range offsets int n = json_scanf( json_str, json_len, "{range_limits_descriptor: {rate_offsets: {vertical: %Q}}}", &multi_use_str); printf("n>%d\n", n); if (strcmp(multi_use_str, "none") == 0) { edid->range_limits_descriptor.rate_offsets.vertical = 0; } else { printf("Error: Range limit offset other than none is not yet implemented.\n"); return 1; } free(multi_use_str); json_scanf( json_str, json_len, "{range_limits_descriptor: {rate_offsets: {horizontal: %Q}}}", &multi_use_str); if (strcmp(multi_use_str, "none") == 0) { edid->range_limits_descriptor.rate_offsets.horizontal = 0; } else { printf("Error: Range limit offset other than none is not yet implemented.\n"); return 1; } free(multi_use_str); // Vertical and horizontal lines json_scanf( json_str, json_len, "{range_limits_descriptor: {rates: {vertical: {minimum_hz: %d}}}}", &multi_use_int); edid->range_limits_descriptor.vertical_field_rate.minimum = 0xFF & multi_use_int; json_scanf( json_str, json_len, "{range_limits_descriptor: {rates: {vertical: {maximum_hz: %d}}}}", &multi_use_int); edid->range_limits_descriptor.vertical_field_rate.maximum = 0xFF & multi_use_int; json_scanf( json_str, json_len, "{range_limits_descriptor: {rates: {horizontal: {minimum_khz: %d}}}}", &multi_use_int); edid->range_limits_descriptor.horizontal_line_rate.minimum = 0xFF & multi_use_int; json_scanf( json_str, json_len, "{range_limits_descriptor: {rates: {horizontal: {maximum_khz: %d}}}}", &multi_use_int); edid->range_limits_descriptor.horizontal_line_rate.maximum = 0xFF & multi_use_int; // Maximum pixel clock rate json_scanf( json_str, json_len, "{range_limits_descriptor: {maximum_pixel_clock_mhz: %d}}", &multi_use_int); // Multiples of 10 MHz edid->range_limits_descriptor.maximum_pixel_clock_mhz = 0xFF & (multi_use_int/10); json_scanf( json_str, json_len, "{range_limits_descriptor: {extended_timing_information_type: %Q}}", &multi_use_str); if (strcmp(multi_use_str, "default_gtf") == 0) { edid->range_limits_descriptor.extended_timing_information_type = 0; // Apply padding for video timing parameters edid->range_limits_descriptor.video_timing_params[0] = 0x0A; memset(edid->range_limits_descriptor.video_timing_params + 1, 0x20, 6); } else { printf("Error: Any other timing information type than default_gtf is currently not implemented.\n"); return 1; } free(multi_use_str); } else { printf("Error: One of either edid or json_str is NULL.\n"); return 1; } return 0; } static int generate_display_name_descriptor( edid_t* edid, unsigned char* json_str, size_t json_len) { char* display_name = NULL; if (edid && json_str) { edid->display_name_descriptor.display_descriptor = 0; edid->display_name_descriptor.reserved0 = 0; edid->display_name_descriptor.descriptor_type = 0xFC; edid->display_name_descriptor.reserved1 = 0; json_scanf( json_str, json_len, "{display_name_descriptor: {name: %Q}}", &display_name); if (display_name != NULL) { if (strlen(display_name) <= 13) { memcpy(edid->display_name_descriptor.descriptor_data, display_name, strlen(display_name)); if (strlen(display_name) < 13) { memset( edid->display_name_descriptor.descriptor_data + strlen(display_name), 0x0A, 1); memset( edid->display_name_descriptor.descriptor_data + strlen(display_name) + 1, 0x20, 13-strlen(display_name)-1); } } else { printf("Error: Display name is too long.\n"); return 1; } } else { printf("Error: Could not parse JSON file somewhere around display_name_descriptor.\n"); return 1; } } else { printf("Error: One of either edid or json_str is NULL.\n"); return 1; } return 0; } int main(void) { //uint8_t edith[EDID_LENGTH]; edid_t edith; memset(&edith, 0x00, sizeof(edith)); printf("size> %d bytes\n", sizeof(edith)); generate_preamble(&edith); unsigned char* mystr = NULL; size_t len = file_to_str(&mystr, "edid_stockach.json"); if (mystr) { printf("%s\n", mystr); printf("len> %d\n", len); } generate_header(&edith, mystr, len); generate_basic_display_parameters(&edith, mystr, len); generate_chromaticity_coordinates(&edith, mystr, len); generate_common_timing_modes(&edith, mystr, len); generate_timings(&edith, mystr, len); generate_detailed_timing_descriptor(&edith, mystr, len); generate_range_limit_descriptor(&edith, mystr, len); generate_display_name_descriptor(&edith, mystr, len); disp_buf((uint8_t*)&edith, EDID_LENGTH); free(mystr); return 0; }