diff --git a/edid_stockach.json b/edid_stockach.json index 5860682..9856eb6 100644 --- a/edid_stockach.json +++ b/edid_stockach.json @@ -64,5 +64,68 @@ "m1024_768_75": true, "m1280_1024_75": true, "m1152_870_75": true + }, + "timings": [ + { + "x_resolution": 1680, + "aspect_ratio": "16:10", + "vertical_frequency": 60 + }, + { + "x_resolution": 1280, + "aspect_ratio": "5:4", + "vertical_frequency": 60 + }, + { + "x_resolution": 1440, + "aspect_ratio": "16:10", + "vertical_frequency": 60 + }, + { + "x_resolution": 1152, + "aspect_ratio": "4:3", + "vertical_frequency": 75 + }, + { + "x_resolution": 1600, + "aspect_ratio": "16:9", + "vertical_frequency": 60 + }, + { + "x_resolution": 1280, + "aspect_ratio": "16:10", + "vertical_frequency": 60 + }, + { + "x_resolution": 1280, + "aspect_ratio": "16:9", + "vertical_frequency": 60 + }, + { + "x_resolution": 1400, + "aspect_ratio": "4:3", + "vertical_frequency": 60 + } + ], + "detailed_timing_descriptor": { + "pixel_clock_mhz": 148.5, + "horizontal_active_pixels": 1920, + "horizontal_blanking_pixels": 280, + "vertical_active_lines": 1080, + "vertical_blanking_lines": 45, + "horizontal_front_porch_pixels": 88, + "horizontal_sync_pulse_pixels": 44, + "vertical_front_porch_lines": 4, + "vertical_sync_pulse_lines": 5, + "horizontal_image_size_mm": 521, + "vertical_image_size_mm": 293, + "horizontal_border_pixels": 0, + "vertical_border_lines": 0, + "stereo_mode": "none", + "interlaced": false, + "digital_seperate_sync": { + "vertical_sync_serration": true, + "horizontal_sync_polarity": "positive" + } } } diff --git a/main b/main deleted file mode 100755 index 2c9646f..0000000 Binary files a/main and /dev/null differ diff --git a/main.c b/main.c index a9656e6..52e5dce 100644 --- a/main.c +++ b/main.c @@ -5,9 +5,6 @@ #include "frozen/frozen.h" #define EDID_LENGTH 128 -#define EDID_BYTES_OFFSET_HEADER_PREAMBLE 0 -#define EDID_BYTES_OFFSET_HEADER_MANUFACTURER_ID 8 -#define EDID_BYTES_OFFSET_HEADER_PRODUCT_CODE 10 enum edid_analog_display_t { EDID_DISPLAY_TYPE_MONOCHROME_OR_GRAYSCALE = 0, @@ -16,12 +13,79 @@ enum edid_analog_display_t { 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 resolution; - uint8_t image_aspect_ratio : 2; - uint8_t vertical_frequency : 6; + 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 )) { /*! Header information, 20 bytes */ struct __attribute__ (( packed )) { @@ -114,10 +178,13 @@ typedef struct __attribute__ (( packed )) { /*! 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]; - uint8_t descriptor_1[18]; +/* uint8_t descriptor_1[18]; uint8_t descriptor_2[18]; uint8_t descriptor_3[18]; uint8_t descriptor_4[18]; +*/ + detailed_timing_descriptor_t detailed_timing_descriptor; + detailed_timing_descriptor_t descriptors[3]; uint8_t number_extensions; uint8_t checksum; } edid_t; @@ -563,6 +630,231 @@ static int generate_common_timing_modes( edid_t* edid, 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; +#define PETER +#ifdef PETER + // 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; + } +#endif + } 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]; @@ -575,12 +867,13 @@ int main(void) if (mystr) { printf("%s\n", mystr); printf("len> %d\n", len); - //free(mystr); } 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); disp_buf((uint8_t*)&edith, EDID_LENGTH); free(mystr); return 0;