|
|
@ -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 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; |
|
|
|