#include "codec_board.h" #define BOARD_SECTION "Board:" #define IN_STR(a, const_b, len) in_str(a, const_b, sizeof(const_b) - 1, len) typedef struct _board_cfg_attr { const char *attr; const char *value; struct _board_cfg_attr *next; } board_cfg_attr_t; typedef struct { const char *type; board_cfg_attr_t *attr; } board_cfg_line_t; static board_section_t *codec_section; extern const char board_cfg_start[] asm("_binary_board_cfg_txt_start"); extern const char board_cfg_end[] asm("_binary_board_cfg_txt_end"); static bool is_word(char s) { return ((s >= 'A' && s <= 'Z') || (s >= 'a' && s <= 'z') || (s >= '0' && s <= '9') || s == '_' || s == '-' || s == '.'); } bool str_same(const char *a, const char *b) { while (*b && *a == *b) { a++; b++; } if (*b == 0) { if (is_word(*a) == false) { return true; } } return false; } static const char *in_str(const char *s, const char *org, int org_len, int len) { while (len > org_len) { if (*s == *org && memcmp(s, org, org_len) == 0 && is_word(s[org_len]) == false) { return s; } s++; len--; } return NULL; } const char *get_section_data(const char *data, int size, const char *section_name) { const char *s = data; while (1) { int left = size - (s - data); s = IN_STR(s, BOARD_SECTION, left); if (s == NULL) { break; } s += sizeof(BOARD_SECTION) - 1; while (!is_word(*s)) { s++; } if (str_same(s, section_name)) { while (*(s++) != '\n') ; return s; } } return NULL; } static int str_len(const char *s) { int len = 0; while (is_word(*s)) { len++; s++; } return len; } static void print_cfg_line(board_cfg_line_t *cfg_line) { printf("%.*s: {", str_len(cfg_line->type), cfg_line->type); board_cfg_attr_t *attr = cfg_line->attr; while (attr) { printf("%.*s: %.*s", str_len(attr->attr), attr->attr, str_len(attr->value), attr->value); if (attr->next) { printf(", "); } attr = attr->next; } printf("}\n"); } static void free_cfg_line(board_cfg_line_t *cfg_line) { if (cfg_line) { board_cfg_attr_t *attr = cfg_line->attr; while (attr) { board_cfg_attr_t *nxt = attr->next; free(attr); attr = nxt; } free(cfg_line); } } static board_cfg_line_t *parse_section(const char *s, int size, int *consume) { board_cfg_line_t *cfg_line; const char *start = s; const char *end = s + size; const char *name = s; bool is_comment = false; while (size) { if (*name == '#') { is_comment = true; } if (is_comment) { if (*name == '\n') { is_comment = false; } } else { if (is_word(*name)) { break; } } size--; name++; } if (size == 0 || str_same(name, BOARD_SECTION)) { return NULL; } cfg_line = calloc(1, sizeof(board_cfg_line_t)); if (cfg_line == NULL) { return NULL; } board_cfg_attr_t *tail = NULL; cfg_line->type = name; s = name; while (*(s++) != '{') ; int word_len = 0; const char *attr = NULL; while (s < end) { if (*s == '}') { *consume = (s + 1 - start); break; } if (is_word(*s)) { if (word_len == 0) { if (attr == NULL) { attr = s; } else { board_cfg_attr_t *cfg_attr = calloc(1, sizeof(board_cfg_attr_t)); if (cfg_attr) { cfg_attr->attr = attr; cfg_attr->value = s; if (tail == NULL) { cfg_line->attr = cfg_attr; } else { tail->next = cfg_attr; } tail = cfg_attr; } attr = NULL; } } word_len++; } else { word_len = 0; } s++; } return cfg_line; } static int fill_i2c_cfg(board_cfg_attr_t *attr) { if (codec_section->i2c_num >= MAX_I2C_NUM) { return -1; } codec_i2c_pin_t *i2c_cfg = &codec_section->i2c_pin[codec_section->i2c_num++]; while (attr) { if (str_same(attr->attr, "sda")) { i2c_cfg->sda = atoi(attr->value); } else if (str_same(attr->attr, "scl")) { i2c_cfg->scl = atoi(attr->value); } attr = attr->next; } return 0; } static int fill_i2s_cfg(board_cfg_attr_t *attr) { if (codec_section->i2s_num >= MAX_I2C_NUM) { return -1; } codec_i2s_pin_t *i2s_cfg = &codec_section->i2s_pin[codec_section->i2s_num++]; i2s_cfg->din = i2s_cfg->dout = -1; while (attr) { if (str_same(attr->attr, "bclk")) { i2s_cfg->bclk = atoi(attr->value); } else if (str_same(attr->attr, "din")) { i2s_cfg->din = atoi(attr->value); } else if (str_same(attr->attr, "dout")) { i2s_cfg->dout = atoi(attr->value); } else if (str_same(attr->attr, "ws")) { i2s_cfg->ws = atoi(attr->value); } else if (str_same(attr->attr, "mclk")) { i2s_cfg->mclk = atoi(attr->value); } attr = attr->next; } return 0; } static extend_io_type_t lcd_get_io_type(const char* s) { if (str_same(s, "tca9554")) { return EXTENT_IO_TYPE_TCA9554; } return EXTENT_IO_TYPE_NONE; } static lcd_controller_type_t lcd_get_controller(const char* s) { if (str_same(s, "st7789")) { return LCD_CONTROLLER_TYPE_ST7789; } return LCD_CONTROLLER_TYPE_NONE; } static lcd_bus_type_t lcd_get_bus(const char* s) { if (str_same(s, "spi")) { return LCD_BUS_TYPE_SPI; } if (str_same(s, "rgb")) { return LCD_BUS_TYPE_RGB; } if (str_same(s, "i80")) { return LCD_BUS_TYPE_I80; } if (str_same(s, "mipi")) { return LCD_BUS_TYPE_MIPI; } return LCD_BUS_TYPE_NONE; } static int16_t get_pin(const char* s) { char* ext = strstr(s, "ext"); if (ext) { return 0x1000 + atoi(ext + 3); } return (int16_t)atoi(s); } static int fill_lcd_cfg(board_cfg_attr_t *attr) { if (codec_section->lcd_num >= 1) { return -1; } lcd_cfg_t *lcd_cfg = &codec_section->lcd; lcd_cfg->reset_pin = lcd_cfg->ctrl_pin = -1; codec_section->lcd_num++; while (attr) { if (str_same(attr->attr, "bus")) { lcd_cfg->bus_type = lcd_get_bus(attr->value); if (lcd_cfg->bus_type == LCD_BUS_TYPE_SPI) { for (int i = 0; i < sizeof(lcd_cfg->spi_cfg.d)/sizeof(lcd_cfg->spi_cfg.d[0]); i++) { lcd_cfg->spi_cfg.d[i] = -1; } } } else if (str_same(attr->attr, "controller")) { lcd_cfg->controller = lcd_get_controller(attr->value); } else if (str_same(attr->attr, "extend_io")) { lcd_cfg->io_type = lcd_get_io_type(attr->value); } else if (str_same(attr->attr, "width")) { lcd_cfg->width = atoi(attr->value); } else if (str_same(attr->attr, "height")) { lcd_cfg->height = atoi(attr->value); } else if (str_same(attr->attr, "mirror_x")) { lcd_cfg->mirror_x = atoi(attr->value) ? 1: 0; } else if (str_same(attr->attr, "mirror_y")) { lcd_cfg->mirror_y = atoi(attr->value) ? 1: 0; } else if (str_same(attr->attr, "swap_xy")) { lcd_cfg->swap_xy = atoi(attr->value) ? 1: 0; } else if (str_same(attr->attr, "color_inv")) { lcd_cfg->color_inv = atoi(attr->value) ? 1: 0; } else if (str_same(attr->attr, "ctrl")) { lcd_cfg->ctrl_pin = get_pin(attr->value); } else if (str_same(attr->attr, "rst")) { lcd_cfg->reset_pin = get_pin(attr->value); } else if (lcd_cfg->bus_type == LCD_BUS_TYPE_SPI) { // Bus configuration if (str_same(attr->attr, "spi_bus")) { lcd_cfg->spi_cfg.spi_bus = atoi(attr->value); } else if (str_same(attr->attr, "cs")) { lcd_cfg->spi_cfg.cs = get_pin(attr->value); } else if (str_same(attr->attr, "dc")) { lcd_cfg->spi_cfg.dc = get_pin(attr->value); } else if (str_same(attr->attr, "clk")) { lcd_cfg->spi_cfg.clk = get_pin(attr->value); } else if (str_same(attr->attr, "mosi")) { lcd_cfg->spi_cfg.mosi = get_pin(attr->value); } else if (str_same(attr->attr, "cmd_bits")) { lcd_cfg->spi_cfg.cmd_bits = (uint8_t)atoi(attr->value); } else if (str_same(attr->attr, "param_bits")) { lcd_cfg->spi_cfg.param_bits = (uint8_t)atoi(attr->value); } } else if (lcd_cfg->bus_type == LCD_BUS_TYPE_MIPI) { if (str_same(attr->attr, "ldo_chan")) { lcd_cfg->mipi_cfg.ldo_chan = (uint8_t)atoi(attr->value); } else if (str_same(attr->attr, "ldo_voltage")) { lcd_cfg->mipi_cfg.ldo_voltage = (uint16_t)atoi(attr->value); } else if (str_same(attr->attr, "lane_num")) { lcd_cfg->mipi_cfg.lane_num = (uint8_t)atoi(attr->value); } else if (str_same(attr->attr, "fb_num")) { lcd_cfg->mipi_cfg.fb_num = (uint8_t)atoi(attr->value); } else if (str_same(attr->attr, "bit_depth")) { lcd_cfg->mipi_cfg.bit_depth = (uint16_t)atoi(attr->value); } else if (str_same(attr->attr, "lane_bitrate")) { lcd_cfg->mipi_cfg.lane_bitrate = (uint32_t)atoi(attr->value); } else if (str_same(attr->attr, "dpi_clk")) { lcd_cfg->mipi_cfg.dpi_clk = (uint32_t)atoi(attr->value); } else if (str_same(attr->attr, "dsi_hsync")) { lcd_cfg->mipi_cfg.dsi_hsync = (uint8_t)atoi(attr->value); } else if (str_same(attr->attr, "dsi_vsync")) { lcd_cfg->mipi_cfg.dsi_vsync = (uint8_t)atoi(attr->value); } else if (str_same(attr->attr, "dsi_hbp")) { lcd_cfg->mipi_cfg.dsi_hbp = (uint8_t)atoi(attr->value); } else if (str_same(attr->attr, "dsi_hfp")) { lcd_cfg->mipi_cfg.dsi_hfp = (uint8_t)atoi(attr->value); } else if (str_same(attr->attr, "dsi_vbp")) { lcd_cfg->mipi_cfg.dsi_vbp = (uint8_t)atoi(attr->value); } else if (str_same(attr->attr, "dsi_vfp")) { lcd_cfg->mipi_cfg.dsi_vfp = (uint8_t)atoi(attr->value); } } attr = attr->next; } return 0; } // TODO add other codec static codec_type_t get_codec_type(const char *type) { if (str_same(type, "ES8311")) { return CODEC_TYPE_ES8311; } if (str_same(type, "ES8388")) { return CODEC_TYPE_ES8388; } if (str_same(type, "ES7243")) { return CODEC_TYPE_ES7243; } if (str_same(type, "ES7210")) { return CODEC_TYPE_ES7210; } if (str_same(type, "DUMMY")) { return CODEC_TYPE_DUMMY; } return CODEC_TYPE_NONE; } static int fill_codec_cfg(board_cfg_attr_t *attr, uint8_t codec_dir) { if (codec_section->codec_num >= MAX_CODEC_NUM) { return -1; } codec_section->codec[codec_section->codec_num].codec_dir = codec_dir; codec_cfg_t *codec_cfg = &codec_section->codec[codec_section->codec_num].codec_cfg; while (attr) { if (str_same(attr->attr, "i2c_port")) { codec_cfg->i2c_port = atoi(attr->value); if (codec_cfg->i2c_port >= codec_section->i2c_num) { return -1; } } else if (str_same(attr->attr, "i2s_port")) { codec_cfg->i2s_port = atoi(attr->value); if (codec_cfg->i2s_port >= codec_section->i2s_num) { return -1; } } else if (str_same(attr->attr, "pa")) { codec_cfg->pa_pin = atoi(attr->value); } else if (str_same(attr->attr, "pa_gain")) { codec_cfg->pa_gain = atof(attr->value); } else if (str_same(attr->attr, "use_mclk")) { codec_cfg->use_mclk = (bool) atoi(attr->value); } else if (str_same(attr->attr, "codec")) { codec_cfg->codec_type = get_codec_type(attr->value); if (codec_cfg->codec_type == CODEC_TYPE_NONE) { return -1; } } else if (str_same(attr->attr, "i2c_addr")) { codec_cfg->i2c_addr = (uint8_t) atoi(attr->value); } attr = attr->next; } printf("Codec %d dir %d type:%d\n", codec_section->codec_num, codec_dir, codec_cfg->codec_type); codec_section->codec_num++; return 0; } static int fill_sdcard_cfg(board_cfg_attr_t *attr) { if (codec_section->sdcard_num >= 1) { return -1; } sdcard_cfg_t *sdcard_cfg = &codec_section->sdcard; sdcard_cfg->power = -1; while (attr) { if (str_same(attr->attr, "clk")) { sdcard_cfg->clk = (int16_t) atoi(attr->value); } else if (str_same(attr->attr, "cmd")) { sdcard_cfg->cmd = (int16_t) atoi(attr->value); } else if (str_same(attr->attr, "d0")) { sdcard_cfg->d0 = (int16_t) atoi(attr->value); } else if (str_same(attr->attr, "d1")) { sdcard_cfg->d1 = (int16_t) atoi(attr->value); } else if (str_same(attr->attr, "d2")) { sdcard_cfg->d2 = (int16_t) atoi(attr->value); } else if (str_same(attr->attr, "d3")) { sdcard_cfg->d3 = (int16_t) atoi(attr->value); } else if (str_same(attr->attr, "power")) { sdcard_cfg->power = (int16_t) atoi(attr->value); } attr = attr->next; } printf("Sdcard clk:%d cmd:%d d0:%d\n", sdcard_cfg->clk, sdcard_cfg->cmd, sdcard_cfg->d0); codec_section->sdcard_num++; return 0; } static camera_type_t get_camera_type(const char* s) { if (str_same(s, "dvp")) { return CAMERA_TYPE_DVP; } if (str_same(s, "usb")) { return CAMERA_TYPE_USB; } if (str_same(s, "mipi")) { return CAMERA_TYPE_MIPI; } return CAMERA_TYPE_NONE; } static int fill_camera_cfg(board_cfg_attr_t *attr) { if (codec_section->camera_num >= 1) { return -1; } camera_cfg_t *camera_cfg = &codec_section->camera; for (int i = 0; i < sizeof(camera_cfg->data)/sizeof(camera_cfg->data[0]); i++) { camera_cfg->data[i] = -1; } camera_cfg->pwr = -1; camera_cfg->reset = -1; while (attr) { if (str_same(attr->attr, "type")) { camera_cfg->type = get_camera_type(attr->value); } if (str_same(attr->attr, "xclk")) { camera_cfg->xclk = (int16_t) atoi(attr->value); } else if (str_same(attr->attr, "pclk")) { camera_cfg->pclk = (int16_t) atoi(attr->value); } else if (str_same(attr->attr, "pwr")) { camera_cfg->pwr = (int16_t) atoi(attr->value); } else if (str_same(attr->attr, "reset")) { camera_cfg->reset = (int16_t) atoi(attr->value); } else if (str_same(attr->attr, "vsync")) { camera_cfg->vsync = (int16_t) atoi(attr->value); } else if (str_same(attr->attr, "href")) { camera_cfg->href = (int16_t) atoi(attr->value); } else if (str_same(attr->attr, "de")) { camera_cfg->de = (int16_t) atoi(attr->value); } else if (attr->attr[0] == 'd' && attr->attr[1] >= '0' && attr->attr[1] <= '9') { int n = atoi(attr->attr + 1); if (n < sizeof(camera_cfg->data)/sizeof(camera_cfg->data[0])) { camera_cfg->data[n] = (int16_t) atoi(attr->value); } } attr = attr->next; } codec_section->camera_num++; return 0; } static int fill_cfg(board_cfg_line_t *cfg_line) { board_cfg_attr_t *attr = cfg_line->attr; if (str_same(cfg_line->type, "i2c")) { if (fill_i2c_cfg(attr) != 0) { return -1; } } else if (str_same(cfg_line->type, "i2s")) { if (fill_i2s_cfg(attr) != 0) { return -1; } } else if (str_same(cfg_line->type, "sdcard")) { if (fill_sdcard_cfg(attr) != 0) { return -1; } } else if (str_same(cfg_line->type, "in_out")) { if (fill_codec_cfg(attr, CODEC_DIR_IN_OUT) != 0) { return -1; } } else if (str_same(cfg_line->type, "out")) { if (fill_codec_cfg(attr, CODEC_DIR_OUT) != 0) { return -1; } } else if (str_same(cfg_line->type, "in")) { if (fill_codec_cfg(attr, CODEC_DIR_IN) != 0) { return -1; } } else if (str_same(cfg_line->type, "lcd")) { if (fill_lcd_cfg(attr) != 0) { return -1; } } else if (str_same(cfg_line->type, "camera")) { if (fill_camera_cfg(attr) != 0) { return -1; } } return 0; } static int parse_cfg(const char *section, int size) { int consume = 0; while (1) { board_cfg_line_t *cfg_line = parse_section(section, size, &consume); if (cfg_line == NULL) { break; } size -= consume; section += consume; print_cfg_line(cfg_line); int ret = fill_cfg(cfg_line); free_cfg_line(cfg_line); if (ret != 0) { printf("Fail to parse cfg line\n"); return ret; } } return 0; } board_section_t *get_codec_section(const char *codec_type) { if (codec_section) { free(codec_section); } codec_section = calloc(1, sizeof(board_section_t)); if (codec_type == NULL) { return NULL; } int cfg_size = board_cfg_end - board_cfg_start; do { const char *section = get_section_data(board_cfg_start, cfg_size, codec_type); if (section == NULL) { break; } int left_size = cfg_size - (section - board_cfg_start); if (parse_cfg(section, left_size) != 0) { break; } return codec_section; } while (0); free(codec_section); return NULL; }