BlinkenArea - GitList
Repositories
Blog
Wiki
libflexipix
Code
Commits
Branches
Tags
Search
Tree:
aa3270a
Branches
Tags
master
v1.0.0
v1.0.1
v1.0.2
v1.0.3
v1.0.4
v1.0.5
v1.0.6
v1.0.7
v1.0.8
libflexipix
src
config.c
removed version information from file headers (manged via git now)
Stefan Schuermans
commited
aa3270a
at 2011-09-11 17:30:15
config.c
Blame
History
Raw
/* * FlexiPix library * * Copyright 2010-2011 Stefan Schuermans <stefan schuermans info> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3 of the License. * * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <flexipix/msg.h> #include <flexipix/types.h> #include <intern/const_data.h> #include <intern/constants.h> #include <intern/config.h> #include <intern/mapping.h> #include <intern/missing.h> #include <intern/net.h> #include <intern/parse.h> #include <intern/strtod_noloc.h> #include <intern/types.h> /** * \brief process distributor from config file * * \param[in,out] p_ctx context information * \param[in] p_setting_part2 second half of setting to process * \param[in] p_value value of setting * \return 0 in case of success, -1 in case of error */ int flp_config_proc_distri(flp_config_ctx_t *p_ctx, char *p_setting_part2, char *value) { char *ptr; unsigned long val; unsigned int distri, out, pix, i; flp_distri_t *p_distri; /* get distributor number */ val = strtoul(p_setting_part2, &ptr, 0); if (ptr == p_setting_part2 || *ptr != 0 || val >= FLP_DISTRI_MAX_CNT) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "invalid distributor number \"%s\"" " in line %u of config file\n", p_setting_part2, p_ctx->line_no); return -1; } distri = (unsigned int)val; /* get number of outputs and pixels */ if (flp_parse_two_nos(value, &out, &pix, &ptr) || *ptr != 0) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "invalid distributor size \"%s\"" " in line %u of config file\n", value, p_ctx->line_no); return -1; } if (out >= FLP_OUTPUT_MAX_CNT) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "invalid number of outputs \"%u\"" " in line %u of config file\n", out, p_ctx->line_no); return -1; } if (pix >= FLP_PIXEL_MAX_CNT) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "invalid number of pixels \"%u\"" " in line %u of config file\n", pix, p_ctx->line_no); return -1; } /* check if distributor is already present */ if (p_ctx->p_display->distri_ptrs[distri]) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "duplicate definition of distributor \"%u\"" " in line %u of config file\n", distri, p_ctx->line_no); return -1; } /* create a new distributor */ p_distri = (flp_distri_t *)malloc(sizeof (flp_distri_t)); if (!p_distri) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "out of memory\n"); return -1; } p_distri->distri = distri; p_distri->output_cnt = out; p_distri->pixel_cnt = pix; /* initialize mapping information */ for (i = 0; i < 3; i++) { p_distri->mapping[i].base = 0.0; p_distri->mapping[i].gamma = 1.0; p_distri->mapping[i].factor = 1.0; flp_mapping_precalc(&p_distri->mapping[i]); } /* create and initialize pixel array */ p_distri->p_pixels = (flp_pixel_t *)malloc(out * pix * sizeof (flp_pixel_t)); if (!p_distri->p_pixels) { free(p_distri); if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "out of memory\n"); return -1; } for (i = 0; i < out * pix; i++) { p_distri->p_pixels[i].x = -1; p_distri->p_pixels[i].y = -1; } /* create and initialize message buffer */ p_distri->msg_len = FLP_MCUF_HDR_LEN + out * pix * 3; p_distri->p_msg_buf = (flp_u8_t *)malloc(p_distri->msg_len); if (!p_distri->p_msg_buf) { free(p_distri->p_pixels); free(p_distri); if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "out of memory\n"); return -1; } memset(p_distri->p_msg_buf, 0, p_distri->msg_len); memcpy(p_distri->p_msg_buf, flp_mcuf_hdr, FLP_MCUF_HDR_LEN); p_distri->p_msg_buf[FLP_MCUF_HDR_OFS_OUTPUTS] = (flp_u8_t)out; p_distri->p_msg_buf[FLP_MCUF_HDR_OFS_PIXELS] = (flp_u8_t)pix; /* store pointer to distributor */ p_ctx->p_display->distri_ptrs[distri] = p_distri; /* count distributors */ p_ctx->p_display->distri_cnt++; return 0; } /** * \brief process mapping from config file * * \param[in,out] p_ctx context information * \param[in] p_setting_part2 second half of setting to process * \param[in] p_value value of setting * \return 0 in case of success, -1 in case of error */ int flp_config_proc_mapping(flp_config_ctx_t *p_ctx, char *p_setting_part2, char *value) { char *ptr, *ptr2; unsigned long val; unsigned int distri, chan; flp_distri_t *p_distri; double base, factor, gamma; /* get distributor number */ val = strtoul(p_setting_part2, &ptr, 0); if (ptr == p_setting_part2 || (*ptr != 0 && *ptr != ' ' && *ptr != '\t' && *ptr != '\r' && *ptr != '\n')) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "invalid mapping specifier \"%s\"" " in line %u of config file\n", p_setting_part2, p_ctx->line_no); return -1; } distri = (unsigned int)val; if (distri >= FLP_DISTRI_MAX_CNT) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "invalid distributor number \"%u\"" " in line %u of config file\n", distri, p_ctx->line_no); return -1; } /* get channel */ while (*ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\n') ptr++; if (!strcmp(ptr, "red")) chan = 0; else if (!strcmp(ptr, "green")) chan = 1; else if (!strcmp(ptr, "blue")) chan = 2; else { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "invalid channel \"%s\"" " in line %u of config file\n", ptr, p_ctx->line_no); return -1; } /* get distributor */ p_distri = p_ctx->p_display->distri_ptrs[distri]; if (!p_distri) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "no distributor with number \"%u\"" " in line %u of config file\n", distri, p_ctx->line_no); return -1; } /* get mapping parameters: base, factor, gamma */ base = flp_strtod_noloc(value, &ptr); if (ptr == value || (*ptr != 0 && *ptr != ' ' && *ptr != '\t' && *ptr != '\r' && *ptr != '\n')) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "invalid mapping parameters \"%s\"" " in line %u of config file\n", value, p_ctx->line_no); return -1; } factor = flp_strtod_noloc(ptr, &ptr2); if (ptr2 == ptr || (*ptr2 != 0 && *ptr2 != ' ' && *ptr2 != '\t' && *ptr2 != '\r' && *ptr2 != '\n')) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "invalid mapping parameters \"%s\"" " in line %u of config file\n", value, p_ctx->line_no); return -1; } gamma = flp_strtod_noloc(ptr2, &ptr); if (ptr == ptr2 || (*ptr != 0 && *ptr != ' ' && *ptr != '\t' && *ptr != '\r' && *ptr != '\n')) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "invalid mapping parameters \"%s\"" " in line %u of config file\n", value, p_ctx->line_no); return -1; } if (gamma <= 0.0) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "invalid gamma value \"%f\"" " in line %u of config file\n", gamma, p_ctx->line_no); return -1; } /* store new mapping parameters and re-calculate mapping table */ p_distri->mapping[chan].base = base; p_distri->mapping[chan].factor = factor; p_distri->mapping[chan].gamma = gamma; flp_mapping_precalc(&p_distri->mapping[chan]); return 0; } /** * \brief process pixel from config file * * \param[in,out] p_ctx context information * \param[in] sz_pixel text of pixel to process * \param[in] distri number of distributor * \param[in] out number of output * \param[in] pix number of pixel * \return 0 in case of success, -1 in case of error */ int flp_config_proc_pixel(flp_config_ctx_t *p_ctx, char *sz_pixel, unsigned int distri, unsigned int out, unsigned int pix) { flp_distri_t *p_distri = p_ctx->p_display->distri_ptrs[distri]; char *ptr; unsigned int x, y, idx; /* get coordinates of pixel */ if (flp_parse_two_nos(sz_pixel, &x, &y, &ptr) || *ptr != 0 || (int)x < 0 || (int)x >= p_ctx->p_display->size.x || (int)y < 0 || (int)y >= p_ctx->p_display->size.y) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "invalid pixel \"%s\"" " in line %u of config file\n", sz_pixel, p_ctx->line_no); return -1; } /* check pixel number */ if (pix >= FLP_PIXEL_MAX_CNT || pix >= p_distri->pixel_cnt) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "too many pixels (more than %u)" " in line %u of config file\n", p_distri->pixel_cnt, p_ctx->line_no); return -1; } /* check that pixel is not yet set */ idx = out * p_distri->pixel_cnt + pix; if (p_distri->p_pixels[idx].x >= 0 && p_distri->p_pixels[idx].y >= 0) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "pixel %u of output %u of distributor %u already set" " to pixel %u,%u in line %u of config file\n", pix, out, distri, p_distri->p_pixels[idx].x, p_distri->p_pixels[idx].y, p_ctx->line_no); return -1; } /* set pixel coordinates */ p_distri->p_pixels[idx].x = x; p_distri->p_pixels[idx].y = y; /* count pixels in total */ p_ctx->p_display->pixel_cnt++; return 0; } /** * \brief process output from config file * * \param[in,out] p_ctx context information * \param[in] p_setting_part2 second half of setting to process * \param[in] p_value value of setting * \return 0 in case of success, -1 in case of error */ int flp_config_proc_output(flp_config_ctx_t *p_ctx, char *p_setting_part2, char *value) { char *ptr, *p_pos, *p_white, white; unsigned int distri, out, pix; flp_distri_t *p_distri; int err; /* get number of distributor and output */ if (flp_parse_two_nos(p_setting_part2, &distri, &out, &ptr) || *ptr != 0) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "invalid output specifier \"%s\"" " in line %u of config file\n", p_setting_part2, p_ctx->line_no); return -1; } if (distri >= FLP_DISTRI_MAX_CNT) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "invalid distributor number \"%u\"" " in line %u of config file\n", distri, p_ctx->line_no); return -1; } if (out >= FLP_OUTPUT_MAX_CNT) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "invalid output number \"%u\"" " in line %u of config file\n", out, p_ctx->line_no); return -1; } /* get distributor */ p_distri = p_ctx->p_display->distri_ptrs[distri]; if (!p_distri) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "no distributor with number \"%u\"" " in line %u of config file\n", distri, p_ctx->line_no); return -1; } /* check output number */ if (out >= p_distri->output_cnt) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "no output with output number \"%u\"" " in line %u of config file\n", out, p_ctx->line_no); return -1; } /* count outputs */ p_ctx->p_display->output_cnt++; /* process pixels */ /* process all parts separated by whitespace */ p_pos = value; err = 0; pix = 0; while (*p_pos != 0) { /* get end of item (first whitespace) */ for (p_white = p_pos; *p_white && *p_white != ' ' && *p_white != '\t' && *p_white != '\r' && *p_white != '\n'; p_white++); /* process item: a pixel */ white = *p_white; /* terminate item */ *p_white = 0; if (flp_config_proc_pixel(p_ctx, p_pos, distri, out, pix)) /* process */ err = -1; /* remember errors */ pix++; /* count pixels */ *p_white = white; /* undo termination */ /* skip whitespace and continue after it */ for (; *p_white == ' ' || *p_white == '\t' || *p_white == '\r' || *p_white == '\n'; p_white++); p_pos = p_white; } /* while (*p_pos != 0) */ return err; } /** * \brief process setting from config file * * \param[in,out] p_ctx context information * \param[in] p_setting setting to process * \param[in] p_value value of setting * \return 0 in case of success, -1 in case of error */ int flp_config_proc_setting(flp_config_ctx_t *p_ctx, char *p_setting, char *p_value) { char *ptr; unsigned int x, y; /* replace all whitespace with spaces in setting */ while ((ptr = strchr(p_setting, '\t'))) *ptr = ' '; while ((ptr = strchr(p_setting, '\r'))) *ptr = ' '; while ((ptr = strchr(p_setting, '\n'))) *ptr = ' '; /* bind address for UDP output */ if (!strcmp(p_setting, "bindAddr")) { if (flp_parse_addr(p_value, &p_ctx->p_display->bind_addr)) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "invalid address \"%s\" for \"%s\"" " in line %u of config file\n", p_value, p_setting, p_ctx->line_no); return -1; } if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_info, "bind address: %s\n", p_value); return 0; } /* size of display */ if (!strcmp(p_setting, "size")) { if (flp_parse_two_nos(p_value, &x, &y, &ptr) || (int)x <= 0 || (int)y <= 0) { if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "invalid value \"%s\" for \"%s\"" " in line %u of config file\n", p_value, p_setting, p_ctx->line_no); return -1; } p_ctx->p_display->size.x = x; p_ctx->p_display->size.y = y; return 0; } /* distributor */ if (!strncmp(p_setting, "distributor ", 12)) return flp_config_proc_distri(p_ctx, p_setting + 12, p_value); /* mapping */ if (!strncmp(p_setting, "mapping ", 8)) return flp_config_proc_mapping(p_ctx, p_setting + 8, p_value); /* output */ if (!strncmp(p_setting, "output ", 7)) return flp_config_proc_output(p_ctx, p_setting + 7, p_value); /* unknown setting */ if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_warn, "unknown setting \"%s\"" " in line %u of config file, ignored\n", p_setting, p_ctx->line_no); return 0; } /** * \brief process line from config file * * \param[in,out] p_ctx context information * \param[in] p_line line to process * \return 0 in case of success, -1 in case of error */ int flp_config_proc_line(flp_config_ctx_t *p_ctx, char *p_line) { char *p_hash, *p_equal, *p_setting, *p_value; int i; /* remove comment */ p_hash = strchr(p_line, '#'); if (p_hash) *p_hash = 0; /* remove trailing whitespace */ for (i = strlen(p_line) - 1; i >= 0 && (p_line[i] == ' ' || p_line[i] == '\t' || p_line[i] == '\r' || p_line[i] == '\n'); i--) p_line[i] = 0; /* remove leading whitespace */ for (; *p_line == ' ' || *p_line == '\t' || *p_line == '\r' || *p_line == '\n'; p_line++); /* ignore empty line */ if (!p_line[0]) return 0; /* find equal sign */ p_equal = strchr(p_line, '='); if (!p_equal) { /* no equal sign found */ if (p_ctx->p_msg_func) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_warn, "invalid line %u in config file, ignored\n", p_ctx->line_no); return 0; } /* split string at equal sign */ *p_equal = 0; p_setting = p_line; p_value = p_equal + 1; /* remove trailing whitespaces in setting name */ for (i = strlen(p_setting) - 1; i >= 0 && (p_setting[i] == ' ' || p_setting[i] == '\t' || p_setting[i] == '\r' || p_setting[i] == '\n'); i--) p_setting[i] = 0; /* remove leading whitespaces in value */ for (; *p_value == ' ' || *p_value == '\t' || *p_value == '\r' || *p_value == '\n'; p_value++); /* process setting */ return flp_config_proc_setting(p_ctx, p_setting, p_value); } /** * \brief process config file * * \param[in,out] p_display display to configure * \param[in] sz_config_file name of config file to read * \param[in] p_msg_func message callback function or NULL * \param[in] p_msg_ctx user context for message callback * \return 0 in case of success, -1 in case of error */ int flp_config_proc_file(flp_display_t *p_display, const char *sz_config_file, flp_msg_func_p_t p_msg_func, void *p_msg_ctx) { flp_config_ctx_t ctx; FILE *file; /* set up context */ ctx.p_display = p_display; ctx.p_msg_func = p_msg_func; ctx.p_msg_ctx = p_msg_ctx; /* check if file is present */ if (!sz_config_file || !sz_config_file[0]) { if (p_msg_func) p_msg_func(p_msg_ctx, flp_msg_type_err, "no config file specified\n"); return -1; } if (p_msg_func) p_msg_func(p_msg_ctx, flp_msg_type_info, "using config file \"%s\"\n", sz_config_file); /* open file */ file = fopen(sz_config_file, "rt"); if (!file) { if (p_msg_func) { char errmsg[256]; strerror_r(errno, errmsg, sizeof(errmsg)); p_msg_func(p_msg_ctx, flp_msg_type_err, "cannot open config file \"%s\" for reading: %s\n", sz_config_file, errmsg); } return -1; } /* process lines in file */ ctx.line_no = 1; while (!feof(file)) { char line[4096], *p_lf; /* read a line */ line[0] = 0; fgets(line, sizeof (line), file); p_lf = strchr(line, '\n'); /* find LF in line in replace it with 0 */ if (p_lf) *p_lf = 0; else { /* no LF in line */ if (!feof(file)) { /* not at end of file */ char dummy[4096]; if (p_msg_func) p_msg_func(p_msg_ctx, flp_msg_type_warn, "line %u too long in config file, truncated\n", ctx.line_no); /* jump over in rest of line */ dummy[0] = 0; while (!feof(file) && !strchr(dummy, '\n')) fgets(dummy, sizeof (dummy), file); } } /* process line from file */ if (flp_config_proc_line(&ctx, line)) return -1; ctx.line_no++; } /* close file */ fclose(file); if (p_msg_func) p_msg_func(p_msg_ctx, flp_msg_type_info, "%ux%u input format, %u distributors, %u outputs, %lu pixels\n", p_display->size.x, p_display->size.y, p_display->distri_cnt, p_display->output_cnt, p_display->pixel_cnt); return 0; }