4 changed files with 324 additions and 0 deletions
@ -0,0 +1,3 @@ |
|||||
|
[submodule "frozen"] |
||||
|
path = frozen |
||||
|
url = https://github.com/cesanta/frozen.git |
@ -0,0 +1,20 @@ |
|||||
|
{ |
||||
|
"header": { |
||||
|
"manufacturer_id": "GSM", |
||||
|
"product_code": 22997, |
||||
|
"serial_number": 607492, |
||||
|
"week_of_manufacture": 3, |
||||
|
"year_of_manufacture": 2013, |
||||
|
"edid_version": 1, |
||||
|
"edid_revision": 3 |
||||
|
}, |
||||
|
"video_input_parameters": { |
||||
|
"input_type": "analog", |
||||
|
"levels": 3, |
||||
|
"blank_to_black": false, |
||||
|
"seperate_sync": true, |
||||
|
"composite_sync": false, |
||||
|
"sync_on_green": false, |
||||
|
"vsync_serrated": false |
||||
|
} |
||||
|
} |
@ -0,0 +1,300 @@ |
|||||
|
#include <stdio.h> |
||||
|
#include <stdint.h> |
||||
|
#include <string.h> |
||||
|
#include <stdlib.h> |
||||
|
#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 |
||||
|
|
||||
|
|
||||
|
typedef struct __attribute__ (( packed )) { |
||||
|
uint8_t resolution; |
||||
|
uint8_t image_aspect_ratio : 2; |
||||
|
uint8_t vertical_frequency : 6; |
||||
|
} standard_timing_information_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 h_screen_size; |
||||
|
uint8_t v_screen_size; |
||||
|
uint8_t gamma; |
||||
|
struct __attribute__ (( packed )) { |
||||
|
uint8_t dpms_standby : 1; |
||||
|
uint8_t dpms_suspend : 1; |
||||
|
uint8_t dpms_active_off : 1; |
||||
|
uint8_t display_type : 2; |
||||
|
uint8_t standard_srgb : 1; |
||||
|
uint8_t preferred_timing_mode : 1; |
||||
|
uint8_t continuous_timings : 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 red_x : 2; |
||||
|
uint8_t red_y : 2; |
||||
|
uint8_t green_x : 2; |
||||
|
uint8_t green_y : 2; |
||||
|
} red_green_lsbs; |
||||
|
struct __attribute__ (( packed )) { |
||||
|
uint8_t blue_x : 2; |
||||
|
uint8_t blue_y : 2; |
||||
|
uint8_t white_x : 2; |
||||
|
uint8_t white_y : 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; |
||||
|
} chromacity_cordinates; |
||||
|
/*! Established timing bitmap. Supported bitmap for (formerly) very common
|
||||
|
timing modes. 3 bytes */ |
||||
|
struct __attribute__ (( packed )) { |
||||
|
uint8_t m720_400_70 : 1; |
||||
|
uint8_t m720_400_80 : 1; |
||||
|
uint8_t m640_480_60 : 1; |
||||
|
uint8_t m640_480_67 : 1; |
||||
|
uint8_t m640_480_72 : 1; |
||||
|
uint8_t m640_480_75 : 1; |
||||
|
uint8_t m800_600_56 : 1; |
||||
|
uint8_t m800_600_60 : 1; |
||||
|
uint8_t m800_600_72 : 1; |
||||
|
uint8_t m800_600_75 : 1; |
||||
|
uint8_t m832_624_75 : 1; |
||||
|
uint8_t m1024_768_87 : 1; |
||||
|
uint8_t m1024_768_60 : 1; |
||||
|
uint8_t m1024_768_70 : 1; |
||||
|
uint8_t m1024_768_75 : 1; |
||||
|
uint8_t m1280_1024_75: 1; |
||||
|
uint8_t m1152_870_75 : 1; |
||||
|
uint8_t reserved : 7; |
||||
|
} 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]; |
||||
|
uint8_t descriptor_1[18]; |
||||
|
uint8_t descriptor_2[18]; |
||||
|
uint8_t descriptor_3[18]; |
||||
|
uint8_t descriptor_4[18]; |
||||
|
uint8_t number_extensions; |
||||
|
uint8_t checksum; |
||||
|
} edid_t; |
||||
|
|
||||
|
/**
|
||||
|
* @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); |
||||
|
/*memset( edid + EDID_BYTES_OFFSET_HEADER_PREAMBLE,
|
||||
|
0x00, 1); |
||||
|
memset( edid + EDID_BYTES_OFFSET_HEADER_PREAMBLE + 1, |
||||
|
0xFF, 6); |
||||
|
memset( edid + EDID_BYTES_OFFSET_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; |
||||
|
} |
||||
|
// 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_video_input_parameters( edid_t* edid, |
||||
|
unsigned char* json_str, |
||||
|
size_t json_len) |
||||
|
{ |
||||
|
char* multi_use_str; |
||||
|
unsigned int multi_use_int; |
||||
|
bool multi_use_bool; |
||||
|
|
||||
|
if (edid && json_str) { |
||||
|
// Input type analog or digital
|
||||
|
json_scanf( json_str, json_len, "{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, "{video_input_parameters: {levels: %d}", |
||||
|
&multi_use_int); |
||||
|
edid->basic_display_parameters.video_input_parameters |
||||
|
.analog.levels = 0x3 & multi_use_int; |
||||
|
// Blank to black
|
||||
|
json_scanf( json_str, json_len, |
||||
|
"{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, |
||||
|
"{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, |
||||
|
"{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, |
||||
|
"{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: {blank_to_black: %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; |
||||
|
} |
||||
|
} else { |
||||
|
printf("One of either edid or json_str is NULL.\n"); |
||||
|
return 3; |
||||
|
} |
||||
|
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.json"); |
||||
|
if (mystr) { |
||||
|
printf("%s\n", mystr); |
||||
|
printf("len> %d\n", len); |
||||
|
//free(mystr);
|
||||
|
} |
||||
|
generate_header(&edith, mystr, len); |
||||
|
generate_video_input_parameters(&edith, mystr, len); |
||||
|
disp_buf((uint8_t*)&edith, EDID_LENGTH); |
||||
|
return 0; |
||||
|
} |
Loading…
Reference in new issue