v1.0.0
Stefan Schuermans authored 13 years ago
|
4) *
5) * Copyright 2010 Stefan Schuermans <stefan schuermans info>
6) *
7) * This program is free software: you can redistribute it and/or modify
8) * it under the terms of the GNU General Public License as published by
9) * the Free Software Foundation, version 3 of the License.
10) *
11) *
12) * This program is distributed in the hope that it will be useful,
13) * but WITHOUT ANY WARRANTY; without even the implied warranty of
14) * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15) * GNU General Public License for more details.
16) *
17) * You should have received a copy of the GNU Lesser General Public License
18) * along with this program. If not, see <http://www.gnu.org/licenses/>.
19) */
20)
21) #include <errno.h>
22) #include <stdio.h>
23) #include <stdlib.h>
24) #include <string.h>
25)
26) #include <flexipix/msg.h>
27) #include <flexipix/types.h>
28) #include <intern/const_data.h>
29) #include <intern/constants.h>
30) #include <intern/config.h>
31) #include <intern/mapping.h>
32) #include <intern/net.h>
33) #include <intern/parse.h>
34) #include <intern/types.h>
35)
36) /**
37) * \brief process distributor from config file
38) *
39) * \param[in,out] p_ctx context information
40) * \param[in] p_setting_part2 second half of setting to process
41) * \param[in] p_value value of setting
42) * \return 0 in case of success, -1 in case of error
43) */
44) int flp_config_proc_distri(flp_config_ctx_t *p_ctx, char *p_setting_part2,
45) char *value)
46) {
47) char *ptr;
48) unsigned long val;
49) unsigned int distri, out, pix, i;
50) flp_distri_t *p_distri;
51)
52) /* get distributor number */
53) val = strtoul(p_setting_part2, &ptr, 0);
54) if (ptr == p_setting_part2 || *ptr != 0 || val >= FLP_DISTRI_MAX_CNT) {
55) if (p_ctx->p_msg_func)
56) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
57) "invalid distributor number \"%s\""
58) " in line %u of config file\n",
59) p_setting_part2, p_ctx->line_no);
60) return -1;
61) }
62) distri = (unsigned int)val;
63)
64) /* get number of outputs and pixels */
65) if (flp_parse_two_nos(value, &out, &pix, &ptr) || *ptr != 0) {
66) if (p_ctx->p_msg_func)
67) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
68) "invalid distributor size \"%s\""
69) " in line %u of config file\n",
70) value, p_ctx->line_no);
71) return -1;
72) }
73) if (out >= FLP_OUTPUT_MAX_CNT) {
74) if (p_ctx->p_msg_func)
75) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
76) "invalid number of outputs \"%u\""
77) " in line %u of config file\n",
78) out, p_ctx->line_no);
79) return -1;
80) }
81) if (pix >= FLP_PIXEL_MAX_CNT) {
82) if (p_ctx->p_msg_func)
83) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
84) "invalid number of pixels \"%u\""
85) " in line %u of config file\n",
86) pix, p_ctx->line_no);
87) return -1;
88) }
89)
90) /* check if distributor is already present */
91) if (p_ctx->p_display->distri_ptrs[distri]) {
92) if (p_ctx->p_msg_func)
93) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
94) "duplicate definition of distributor \"%u\""
95) " in line %u of config file\n",
96) distri, p_ctx->line_no);
97) return -1;
98) }
99)
100) /* create a new distributor */
101) p_distri = (flp_distri_t *)malloc(sizeof (flp_distri_t));
102) if (!p_distri) {
103) if (p_ctx->p_msg_func)
104) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "out of memory\n");
105) return -1;
106) }
107) p_distri->distri = distri;
108) p_distri->output_cnt = out;
109) p_distri->pixel_cnt = pix;
110) /* initialize mapping information */
111) for (i = 0; i < 3; i++) {
112) p_distri->mapping[i].base = 0.0;
113) p_distri->mapping[i].gamma = 1.0;
114) p_distri->mapping[i].factor = 1.0;
115) flp_mapping_precalc(&p_distri->mapping[i]);
116) }
117) /* create and initialize pixel array */
118) p_distri->p_pixels =
119) (flp_pixel_t *)malloc(out * pix * sizeof (flp_pixel_t));
120) if (!p_distri->p_pixels) {
121) free(p_distri);
122) if (p_ctx->p_msg_func)
123) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "out of memory\n");
124) return -1;
125) }
126) for (i = 0; i < out * pix; i++) {
127) p_distri->p_pixels[i].x = -1;
128) p_distri->p_pixels[i].y = -1;
129) }
130) /* create and initialize message buffer */
131) p_distri->msg_len = FLP_MCUF_HDR_LEN + out * pix * 3;
132) p_distri->p_msg_buf = (flp_u8_t *)malloc(p_distri->msg_len);
133) if (!p_distri->p_msg_buf) {
134) free(p_distri->p_pixels);
135) free(p_distri);
136) if (p_ctx->p_msg_func)
137) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err, "out of memory\n");
138) return -1;
139) }
140) memset(p_distri->p_msg_buf, 0, p_distri->msg_len);
141) memcpy(p_distri->p_msg_buf, flp_mcuf_hdr, FLP_MCUF_HDR_LEN);
142) p_distri->p_msg_buf[FLP_MCUF_HDR_OFS_OUTPUTS] = (flp_u8_t)out;
143) p_distri->p_msg_buf[FLP_MCUF_HDR_OFS_PIXELS] = (flp_u8_t)pix;
144) /* store pointer to distributor */
145) p_ctx->p_display->distri_ptrs[distri] = p_distri;
146)
147) /* count distributors */
148) p_ctx->p_display->distri_cnt++;
149)
150) return 0;
151) }
152)
153) /**
154) * \brief process mapping from config file
155) *
156) * \param[in,out] p_ctx context information
157) * \param[in] p_setting_part2 second half of setting to process
158) * \param[in] p_value value of setting
159) * \return 0 in case of success, -1 in case of error
160) */
161) int flp_config_proc_mapping(flp_config_ctx_t *p_ctx, char *p_setting_part2,
162) char *value)
163) {
164) char *ptr, *ptr2;
165) unsigned long val;
166) unsigned int distri, chan;
167) flp_distri_t *p_distri;
168) double base, factor, gamma;
169)
170) /* get distributor number */
171) val = strtoul(p_setting_part2, &ptr, 0);
172) if (ptr == p_setting_part2
173) || (*ptr != 0 && *ptr != ' ' && *ptr != '\t'
174) && *ptr != '\r' && *ptr != '\n')) {
175) if (p_ctx->p_msg_func)
176) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
177) "invalid mapping specifier \"%s\""
178) " in line %u of config file\n",
179) p_setting_part2, p_ctx->line_no);
180) return -1;
181) }
182) distri = (unsigned int)val;
183) if (distri >= FLP_DISTRI_MAX_CNT) {
184) if (p_ctx->p_msg_func)
185) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
186) "invalid distributor number \"%u\""
187) " in line %u of config file\n",
188) distri, p_ctx->line_no);
189) return -1;
190) }
191)
192) /* get channel */
193) while (*ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\n')
194) ptr++;
195) if (!strcmp(ptr, "red"))
196) chan = 0;
197) else if (!strcmp(ptr, "green"))
198) chan = 1;
199) else if (!strcmp(ptr, "blue"))
200) chan = 2;
201) else {
202) if (p_ctx->p_msg_func)
203) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
204) "invalid channel \"%s\""
205) " in line %u of config file\n", ptr,
206) p_ctx->line_no);
207) return -1;
208) }
209)
210) /* get distributor */
211) p_distri = p_ctx->p_display->distri_ptrs[distri];
212) if (!p_distri) {
213) if (p_ctx->p_msg_func)
214) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
215) "no distributor with number \"%u\""
216) " in line %u of config file\n",
217) distri, p_ctx->line_no);
218) return -1;
219) }
220)
221) /* get mapping parameters: base, factor, gamma */
222) base = strtod(value, &ptr);
223) if (ptr == value
224) || (*ptr != 0 && *ptr != ' ' && *ptr != '\t'
225) && *ptr != '\r' && *ptr != '\n')) {
226) if (p_ctx->p_msg_func)
227) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
228) "invalid mapping parameters \"%s\""
229) " in line %u of config file\n",
230) value, p_ctx->line_no);
231) return -1;
232) }
233) factor = strtod(ptr, &ptr2);
234) if (ptr2 == ptr
235) || (*ptr2 != 0 && *ptr2 != ' ' && *ptr2 != '\t'
236) && *ptr2 != '\r' && *ptr2 != '\n')) {
237) if (p_ctx->p_msg_func)
238) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
239) "invalid mapping parameters \"%s\""
240) " in line %u of config file\n",
241) value, p_ctx->line_no);
242) return -1;
243) }
244) gamma = strtod(ptr2, &ptr);
245) if (ptr == ptr2
246) || (*ptr != 0 && *ptr != ' ' && *ptr != '\t'
247) && *ptr != '\r' && *ptr != '\n')) {
248) if (p_ctx->p_msg_func)
249) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
250) "invalid mapping parameters \"%s\""
251) " in line %u of config file\n",
252) value, p_ctx->line_no);
253) return -1;
254) }
255) if (gamma <= 0.0) {
256) if (p_ctx->p_msg_func)
257) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
258) "invalid gamma value \"%f\""
259) " in line %u of config file\n",
260) gamma, p_ctx->line_no);
261) return -1;
262) }
263)
264) /* store new mapping parameters and re-calculate mapping table */
265) p_distri->mapping[chan].base = base;
266) p_distri->mapping[chan].factor = factor;
267) p_distri->mapping[chan].gamma = gamma;
268) flp_mapping_precalc(&p_distri->mapping[chan]);
269)
270) return 0;
271) }
272)
273) /**
274) * \brief process pixel from config file
275) *
276) * \param[in,out] p_ctx context information
277) * \param[in] sz_pixel text of pixel to process
278) * \param[in] distri number of distributor
279) * \param[in] out number of output
280) * \param[in] pix number of pixel
281) * \return 0 in case of success, -1 in case of error
282) */
283) int flp_config_proc_pixel(flp_config_ctx_t *p_ctx, char *sz_pixel,
284) unsigned int distri, unsigned int out,
285) unsigned int pix)
286) {
287) flp_distri_t *p_distri = p_ctx->p_display->distri_ptrs[distri];
288) char *ptr;
289) unsigned int x, y, idx;
290)
291) /* get coordinates of pixel */
292) if (flp_parse_two_nos(sz_pixel, &x, &y, &ptr) || *ptr != 0
293) || (int)x < 0 || (int)x >= p_ctx->p_display->size.x
294) || (int)y < 0 || (int)y >= p_ctx->p_display->size.y) {
295) if (p_ctx->p_msg_func)
296) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
297) "invalid pixel \"%s\""
298) " in line %u of config file\n",
299) sz_pixel, p_ctx->line_no);
300) return -1;
301) }
302)
303) /* check pixel number */
304) if (pix >= FLP_PIXEL_MAX_CNT || pix >= p_distri->pixel_cnt) {
305) if (p_ctx->p_msg_func)
306) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
307) "too many pixels (more than %u)"
308) " in line %u of config file\n",
309) p_distri->pixel_cnt, p_ctx->line_no);
310) return -1;
311) }
312)
313) /* check that pixel is not yet set */
314) idx = out * p_distri->pixel_cnt + pix;
315) if (p_distri->p_pixels[idx].x >= 0
316) && p_distri->p_pixels[idx].y >= 0) {
317) if (p_ctx->p_msg_func)
318) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
319) "pixel %u of output %u of distributor %u already set"
320) " to pixel %u,%u in line %u of config file\n",
321) pix, out, distri, p_distri->p_pixels[idx].x,
322) p_distri->p_pixels[idx].y, p_ctx->line_no);
323) return -1;
324) }
325)
326) /* set pixel coordinates */
327) p_distri->p_pixels[idx].x = x;
328) p_distri->p_pixels[idx].y = y;
329)
330) /* count pixels in total */
331) p_ctx->p_display->pixel_cnt++;
332)
333) return 0;
334) }
335)
336) /**
337) * \brief process output from config file
338) *
339) * \param[in,out] p_ctx context information
340) * \param[in] p_setting_part2 second half of setting to process
341) * \param[in] p_value value of setting
342) * \return 0 in case of success, -1 in case of error
343) */
344) int flp_config_proc_output(flp_config_ctx_t *p_ctx, char *p_setting_part2,
345) char *value)
346) {
347) char *ptr, *p_pos, *p_white, white;
348) unsigned int distri, out, pix;
349) flp_distri_t *p_distri;
350) int err;
351)
352) /* get number of distributor and output */
353) if (flp_parse_two_nos(p_setting_part2, &distri, &out, &ptr) || *ptr != 0) {
354) if (p_ctx->p_msg_func)
355) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
356) "invalid output specifier \"%s\""
357) " in line %u of config file\n",
358) p_setting_part2, p_ctx->line_no);
359) return -1;
360) }
361) if (distri >= FLP_DISTRI_MAX_CNT) {
362) if (p_ctx->p_msg_func)
363) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
364) "invalid distributor number \"%u\""
365) " in line %u of config file\n",
366) distri, p_ctx->line_no);
367) return -1;
368) }
369) if (out >= FLP_OUTPUT_MAX_CNT) {
370) if (p_ctx->p_msg_func)
371) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
372) "invalid output number \"%u\""
373) " in line %u of config file\n",
374) out, p_ctx->line_no);
375) return -1;
376) }
377)
378) /* get distributor */
379) p_distri = p_ctx->p_display->distri_ptrs[distri];
380) if (!p_distri) {
381) if (p_ctx->p_msg_func)
382) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
383) "no distributor with number \"%u\""
384) " in line %u of config file\n",
385) distri, p_ctx->line_no);
386) return -1;
387) }
388) /* check output number */
389) if (out >= p_distri->output_cnt) {
390) if (p_ctx->p_msg_func)
391) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
392) "no output with output number \"%u\""
393) " in line %u of config file\n",
394) out, p_ctx->line_no);
395) return -1;
396) }
397)
398) /* count outputs */
399) p_ctx->p_display->output_cnt++;
400)
401) /* process pixels */
402)
403) /* process all parts separated by whitespace */
404) p_pos = value;
405) err = 0;
406) pix = 0;
407) while (*p_pos != 0) {
408)
409) /* get end of item (first whitespace) */
410) for (p_white = p_pos;
411) *p_white && *p_white != ' ' && *p_white != '\t'
412) && *p_white != '\r' && *p_white != '\n'; p_white++);
413)
414) /* process item: a pixel */
415) white = *p_white; /* terminate item */
416) *p_white = 0;
417) if (flp_config_proc_pixel(p_ctx, p_pos, distri, out, pix)) /* process */
418) err = -1; /* remember errors */
419) pix++; /* count pixels */
420) *p_white = white; /* undo termination */
421)
422) /* skip whitespace and continue after it */
423) for (;
424) *p_white == ' ' || *p_white == '\t'
425) || *p_white == '\r' || *p_white == '\n'; p_white++);
426) p_pos = p_white;
427)
428) } /* while (*p_pos != 0) */
429)
430) return err;
431) }
432)
433) /**
434) * \brief process setting from config file
435) *
436) * \param[in,out] p_ctx context information
437) * \param[in] p_setting setting to process
438) * \param[in] p_value value of setting
439) * \return 0 in case of success, -1 in case of error
440) */
441) int flp_config_proc_setting(flp_config_ctx_t *p_ctx, char *p_setting,
442) char *p_value)
443) {
444) char *ptr;
445) unsigned int x, y;
446)
447) /* replace all whitespace with spaces in setting */
448) while ((ptr = strchr(p_setting, '\t')))
449) *ptr = ' ';
450) while ((ptr = strchr(p_setting, '\r')))
451) *ptr = ' ';
452) while ((ptr = strchr(p_setting, '\n')))
453) *ptr = ' ';
454)
455) /* bind address for UDP output */
456) if (!strcmp(p_setting, "bindAddr")) {
457) if (flp_parse_addr(p_value, &p_ctx->p_display->bind_addr)) {
458) if (p_ctx->p_msg_func)
459) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
460) "invalid address \"%s\" for \"%s\""
461) " in line %u of config file\n",
462) p_value, p_setting, p_ctx->line_no);
463) return -1;
464) }
465) if (p_ctx->p_msg_func)
466) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_info, "bind address: %s\n", p_value);
467) return 0;
468) }
469)
470) /* size of display */
471) if (!strcmp(p_setting, "size")) {
472) if (flp_parse_two_nos(p_value, &x, &y, &ptr)
473) || (int)x <= 0 || (int)y <= 0) {
474) if (p_ctx->p_msg_func)
475) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_err,
476) "invalid value \"%s\" for \"%s\""
477) " in line %u of config file\n",
478) p_value, p_setting, p_ctx->line_no);
479) return -1;
480) }
481) p_ctx->p_display->size.x = x;
482) p_ctx->p_display->size.y = y;
483) return 0;
484) }
485)
486) /* distributor */
487) if (!strncmp(p_setting, "distributor ", 12))
488) return flp_config_proc_distri(p_ctx, p_setting + 12, p_value);
489)
490) /* mapping */
491) if (!strncmp(p_setting, "mapping ", 8))
492) return flp_config_proc_mapping(p_ctx, p_setting + 8, p_value);
493)
494) /* output */
495) if (!strncmp(p_setting, "output ", 7))
496) return flp_config_proc_output(p_ctx, p_setting + 7, p_value);
497)
498) /* unknown setting */
499) if (p_ctx->p_msg_func)
500) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_warn,
501) "unknown setting \"%s\""
502) " in line %u of config file, ignored\n",
503) p_setting, p_ctx->line_no);
504) return 0;
505) }
506)
507) /**
508) * \brief process line from config file
509) *
510) * \param[in,out] p_ctx context information
511) * \param[in] p_line line to process
512) * \return 0 in case of success, -1 in case of error
513) */
514) int flp_config_proc_line(flp_config_ctx_t *p_ctx, char *p_line)
515) {
516) char *p_hash, *p_equal, *p_setting, *p_value;
517) int i;
518)
519) /* remove comment */
520) p_hash = strchr(p_line, '#');
521) if (p_hash)
522) *p_hash = 0;
523)
524) /* remove trailing whitespace */
525) for (i = strlen(p_line) - 1;
526) i >= 0 && (p_line[i] == ' ' || p_line[i] == '\t'
527) || p_line[i] == '\r' || p_line[i] == '\n'); i--)
528) p_line[i] = 0;
529)
530) /* remove leading whitespace */
531) for (; *p_line == ' ' || *p_line == '\t'
532) || *p_line == '\r' || *p_line == '\n'; p_line++);
533)
534) /* ignore empty line */
535) if (!p_line[0])
536) return 0;
537)
538) /* find equal sign */
539) p_equal = strchr(p_line, '=');
540) if (!p_equal) { /* no equal sign found */
541) if (p_ctx->p_msg_func)
542) p_ctx->p_msg_func(p_ctx->p_msg_ctx, flp_msg_type_warn,
543) "invalid line %u in config file, ignored\n",
544) p_ctx->line_no);
545) return 0;
546) }
547)
548) /* split string at equal sign */
549) *p_equal = 0;
550) p_setting = p_line;
551) p_value = p_equal + 1;
552)
553) /* remove trailing whitespaces in setting name */
554) for (i = strlen(p_setting) - 1;
555) i >= 0 && (p_setting[i] == ' ' || p_setting[i] == '\t'
556) || p_setting[i] == '\r' || p_setting[i] == '\n'); i--)
557) p_setting[i] = 0;
558)
559) /* remove leading whitespaces in value */
560) for (; *p_value == ' ' || *p_value == '\t'
561) || *p_value == '\r' || *p_value == '\n'; p_value++);
562)
563) /* process setting */
564) return flp_config_proc_setting(p_ctx, p_setting, p_value);
565) }
566)
567) /**
568) * \brief process config file
569) *
570) * \param[in,out] p_display display to configure
571) * \param[in] sz_config_file name of config file to read
572) * \param[in] p_msg_func message callback function or NULL
573) * \param[in] p_msg_ctx user context for message callback
574) * \return 0 in case of success, -1 in case of error
575) */
576) int flp_config_proc_file(flp_display_t *p_display,
577) const char *sz_config_file,
578) flp_msg_func_p_t p_msg_func, void *p_msg_ctx)
579) {
580) flp_config_ctx_t ctx;
581) FILE *file;
582)
583) /* set up context */
584) ctx.p_display = p_display;
585) ctx.p_msg_func = p_msg_func;
586) ctx.p_msg_ctx = p_msg_ctx;
587)
588) /* check if file is present */
589) if (!sz_config_file || !sz_config_file[0]) {
590) if (p_msg_func)
591) p_msg_func(p_msg_ctx, flp_msg_type_err,
592) "no config file specified\n");
593) return -1;
594) }
595)
596) if (p_msg_func)
597) p_msg_func(p_msg_ctx, flp_msg_type_info,
598) "using config file \"%s\"\n",
599) sz_config_file);
600)
601) /* open file */
602) file = fopen(sz_config_file, "rt");
603) if (!file) {
|