Home | History | Annotate | Line # | Download | only in tpctl
      1 /*	$NetBSD: main.c,v 1.8 2024/07/12 22:31:40 andvar Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2002 TAKEMRUA Shin
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of The NetBSD Foundation nor the names of its
     16  *    contributors may be used to endorse or promote products derived
     17  *    from this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <stdio.h>
     33 #include <strings.h>
     34 #include <stdlib.h>
     35 #include <unistd.h>
     36 #include <err.h>
     37 #include <errno.h>
     38 #include <time.h>
     39 #include <termios.h>
     40 #include <sys/fcntl.h>
     41 #include <sys/mman.h>
     42 #ifdef __STDC__
     43 #include <stdarg.h>
     44 #else
     45 #include <varargs.h>
     46 #endif
     47 
     48 #include "tpctl.h"
     49 
     50 #ifndef lint
     51 #include <sys/cdefs.h>
     52 __RCSID("$NetBSD: main.c,v 1.8 2024/07/12 22:31:40 andvar Exp $");
     53 #endif /* not lint */
     54 
     55 void load_data(const char *, struct tpctl_data *);
     56 void save_data(const char *, struct tpctl_data *);
     57 int do_calibration(const char *, struct tp *, struct wsmouse_calibcoords *);
     58 void drawcross(struct fb *, int, int, int, fb_pixel_t);
     59 int check_esc(void *);
     60 
     61 int opt_verbose;
     62 int opt_noupdate;
     63 int opt_forceupdate;
     64 
     65 static __dead void
     66 usage(void)
     67 {
     68 
     69 	fprintf(stderr, "usage: %s [-D dispdev] [-d dev] [-f file] [-hnuv]\n",
     70 	    getprogname());
     71 	exit(EXIT_FAILURE);
     72 	/* NOTREACHED */
     73 }
     74 
     75 int
     76 main(int argc, char *argv[])
     77 {
     78 	int tpfd, ch;
     79 	struct tp tp;
     80 	struct wsmouse_calibcoords *pref;
     81 	struct tpctl_data data;
     82 	const char *data_file;
     83 	const char *dev_name;
     84 	const char *dispdev_name;
     85 
     86 	/* set default values */
     87 	opt_verbose = 0;
     88 	opt_noupdate = 0;
     89 	opt_forceupdate = 0;
     90 	dev_name = TPCTL_TP_DEVICE;
     91 	dispdev_name = TPCTL_FB_DEVICE;
     92 	data_file = TPCTL_DB_FILENAME;
     93 
     94 	/* parse command line */
     95 	while ((ch = getopt(argc, argv, "d:D:f:hnuv")) != -1) {
     96 		switch (ch) {
     97 		case 'D':
     98 			dispdev_name = optarg;
     99 			break;
    100 		case 'd':
    101 			dev_name = optarg;
    102 			break;
    103 		case 'f':
    104 			data_file = optarg;
    105 			break;
    106 		case 'h':
    107 			usage();
    108 			/* NOTREACHED */
    109 		case 'n':
    110 			opt_noupdate = 1;
    111 			break;
    112 		case 'u':
    113 			opt_forceupdate = 1;
    114 			break;
    115 		case 'v':
    116 			opt_verbose = 1;
    117 			break;
    118 		default:
    119 			usage();
    120 			/* NOTREACHED */
    121 		}
    122 	}
    123 	if (argv[optind] != NULL) {
    124 		usage();
    125 		/* NOTREACHED */
    126 	}
    127 
    128 	/* load calibration parameters from specified file */
    129 	load_data(data_file, &data);
    130 
    131 	/* open touch panel device and initialize touch panel routines */
    132 	if ((tpfd = open(dev_name, O_RDWR)) < 0)
    133 		errx(EXIT_FAILURE, "can't open touch panel");
    134 	if (tp_init(&tp, tpfd) < 0)
    135 		errx(EXIT_FAILURE, "can't initialize touch panel");
    136 
    137 	/* find out saved parameters for the touch panel */
    138 	pref = search_data(&data, tp.id);
    139 	if (opt_forceupdate || pref == NULL) {
    140 		/* if the parameters wasn't found or '-f' options was
    141 		   specified, do 'calibration' */
    142 		struct wsmouse_calibcoords coords;
    143 
    144 		/* draw cursors and collect samples */
    145 		if (do_calibration(dispdev_name, &tp, &coords) < 0) {
    146 			/* ESC key was pressed to abort */
    147 			exit(EXIT_FAILURE);
    148 		}
    149 		/* update parameters with new one */
    150 		replace_data(&data, tp.id, &coords);
    151 		pref = search_data(&data, tp.id);
    152 	} else {
    153 		/* nothing is updated,
    154 		   so you don't have to write back the data */
    155 		opt_noupdate = 1;
    156 	}
    157 
    158 	if (opt_verbose)
    159 		write_coords(stdout, tp.id, pref);
    160 
    161 	/* set calibration parameters into touch panel device */
    162 	if (tp_setcalibcoords(&tp, pref) < 0)
    163 		errx(EXIT_FAILURE, "can't set samples");
    164 
    165 	/* save calibration parameters from specified file */
    166 	if (!opt_noupdate)
    167 		save_data(data_file, &data);
    168 	/* dispose data */
    169 	free_data(&data);
    170 
    171 	exit(EXIT_SUCCESS);
    172 	/* NOTREACHED */
    173 }
    174 
    175 /*
    176  * load calibration parameters from specified file
    177  *
    178  * return:	none (it won't return if some error occurs)
    179  */
    180 void
    181 load_data(const char *data_file, struct tpctl_data *data)
    182 {
    183 	int error;
    184 
    185 	init_data(data);
    186 	error = read_data(data_file, data);
    187 	switch (error) {
    188 	case ERR_NONE:
    189 		break;
    190 	case ERR_NOFILE:
    191 		fprintf(stderr, "%s: can't open %s\n", getprogname(),
    192 		    data_file);
    193 		/* it might be OK... */
    194 		break;
    195 	case ERR_IO:
    196 		fprintf(stderr, "%s: I/O error on %s\n", getprogname(),
    197 		    data_file);
    198 		exit(EXIT_FAILURE);
    199 		break;
    200 	case ERR_SYNTAX:
    201 		fprintf(stderr, "%s: format error at %s, line %d\n",
    202 		    getprogname(), data_file, data->lineno);
    203 		exit(EXIT_FAILURE);
    204 		break;
    205 	case ERR_DUPNAME:
    206 		fprintf(stderr, "%s: duplicate entry at %s, line %d\n",
    207 		    getprogname(), data_file, data->lineno);
    208 		exit(EXIT_FAILURE);
    209 		break;
    210 	default:
    211 		fprintf(stderr, "%s: internal error\n", getprogname());
    212 		exit(EXIT_FAILURE);
    213 		break;
    214 	}
    215 }
    216 
    217 /*
    218  * save calibration parameters to specified file
    219  *
    220  * return:	none (it won't return if some error occurs)
    221  */
    222 void
    223 save_data(const char *data_file, struct tpctl_data *data)
    224 {
    225 	int error;
    226 
    227 	error = write_data(data_file, data);
    228 	switch (error) {
    229 	case ERR_NONE:
    230 		break;
    231 	case ERR_NOFILE:
    232 		fprintf(stderr, "%s: can't open %s\n", getprogname(),
    233 		    data_file);
    234 		exit(EXIT_FAILURE);
    235 		break;
    236 	case ERR_IO:
    237 		fprintf(stderr, "%s: I/O error on %s\n", getprogname(),
    238 		    data_file);
    239 		exit(EXIT_FAILURE);
    240 		break;
    241 	default:
    242 		fprintf(stderr, "%s: internal error\n", getprogname());
    243 		exit(EXIT_FAILURE);
    244 		break;
    245 	}
    246 }
    247 
    248 /*
    249  * draw cursors on frame buffer and collect samples in
    250  * wamouse_calibcoords structure.
    251  *
    252  * return:	0	succeeded
    253  *		-1	aborted by user (ESC key was pressed)
    254  *		(it won't return if some error occurs)
    255  */
    256 int
    257 do_calibration(const char *dev, struct tp *tp,
    258     struct wsmouse_calibcoords *coords)
    259 {
    260 	int fbfd;
    261 	struct fb fb;
    262 	int i, x, y, xm, ym, cursize, error, res;
    263 
    264 	/* open frame buffer device and initialize frame buffer routine */
    265 	if ((fbfd = open(dev, O_RDWR)) < 0)
    266 		errx(EXIT_FAILURE, "can't open frame buffer");
    267 	if (fb_init(&fb, fbfd) < 0)
    268 		errx(EXIT_FAILURE, "can't map frame buffer");
    269 
    270 	memset(coords, 0, sizeof(*coords));
    271 	coords->minx = 0;
    272 	coords->miny = 0;
    273 	coords->maxx = fb.conf.hf_width - 1;
    274 	coords->maxy = fb.conf.hf_height - 1;
    275 	coords->samplelen = 5;
    276 
    277 	cursize = 20;
    278 	xm = fb.conf.hf_width/10;
    279 	ym = fb.conf.hf_height/10;
    280 
    281 	/* center */
    282 	coords->samples[0].x = fb.conf.hf_width/2;
    283 	coords->samples[0].y = fb.conf.hf_height/2;
    284 
    285 	/* top left */
    286 	coords->samples[1].x = xm;
    287 	coords->samples[1].y = ym;
    288 
    289 	/* bottom left */
    290 	coords->samples[2].x = xm;
    291 	coords->samples[2].y = fb.conf.hf_height - ym;
    292 
    293 	/* bottom right */
    294 	coords->samples[3].x = fb.conf.hf_width - xm;
    295 	coords->samples[3].y = fb.conf.hf_height - ym;
    296 
    297 	/* top right */
    298 	coords->samples[4].x = fb.conf.hf_width - xm;
    299 	coords->samples[4].y = ym;
    300 
    301 	tp_setrawmode(tp);
    302 	error = 0;
    303 	for (i = 0; i < coords->samplelen; i++) {
    304 		drawcross(&fb,
    305 		    coords->samples[i].x,
    306 		    coords->samples[i].y,
    307 		    cursize, fb.white);
    308 		fb_flush(&fb);
    309 		tp_flush(tp);
    310 		res = tp_get(tp, &x, &y, check_esc, 0 /* stdin */);
    311 		if (res < 0) {
    312 			error = errno;
    313 			break;
    314 		}
    315 		if (0 < res) {
    316 			fb_dispmode(&fb, WSDISPLAYIO_MODE_EMUL);
    317 			return (-1); /* aborted by user */
    318 		}
    319 		coords->samples[i].rawx = x;
    320 		coords->samples[i].rawy = y;
    321 		drawcross(&fb,
    322 		    coords->samples[i].x,
    323 		    coords->samples[i].y,
    324 		    cursize, fb.black);
    325 		fb_flush(&fb);
    326 		tp_waitup(tp, 200, check_esc, 0 /* stdin */);
    327 	}
    328 
    329 	fb_dispmode(&fb, WSDISPLAYIO_MODE_EMUL);
    330 	close(fbfd);
    331 
    332 	if (opt_verbose) {
    333 		printf("%s: %dx%d (%dbytes/line) %dbit offset=0x%lx\n",
    334 		    getprogname(),
    335 		    fb.conf.hf_width,
    336 		    fb.conf.hf_height,
    337 		    fb.conf.hf_bytes_per_line,
    338 		    fb.conf.hf_pixel_width,
    339 		    fb.conf.hf_offset);
    340 	}
    341 
    342 	if (error) {
    343 		errno = error;
    344 		errx(EXIT_FAILURE, "can't get samples");
    345 	}
    346 
    347 	return (0);
    348 }
    349 
    350 /*
    351  * draw cross cursor on frame buffer
    352  *
    353  * return:	none
    354  */
    355 void
    356 drawcross(struct fb *fb, int x, int y, int size, fb_pixel_t pixel)
    357 {
    358 	size /= 2;
    359 
    360 	fb_drawline(fb, x,     y - size + 1, x,     y - 1,    pixel);
    361 	fb_drawline(fb, x + 1, y - size + 1, x + 1, y - 1,    pixel);
    362 	fb_drawline(fb, x,     y + 2,        x,     y + size, pixel);
    363 	fb_drawline(fb, x + 1, y + 2,        x + 1, y + size, pixel);
    364 
    365 	fb_drawline(fb, x - size + 1, y,     x - 1,    y,     pixel);
    366 	fb_drawline(fb, x - size + 1, y + 1, x - 1,    y + 1, pixel);
    367 	fb_drawline(fb, x + 2,        y,     x + size, y,     pixel);
    368 	fb_drawline(fb, x + 2,        y + 1, x + size, y + 1, pixel);
    369 }
    370 
    371 /*
    372  * check ESC key
    373  *
    374  * date:	input file descriptor
    375  *
    376  * return:	0	nothing has occurred
    377  *		1	ESC key was pressed
    378  *		-1	error
    379  */
    380 int
    381 check_esc(void *data)
    382 {
    383 	int fd = (int)(intptr_t)data;
    384 	int flg, n, error;
    385 	char buf[1];
    386 	struct termios tm, raw;
    387 
    388 	if (tcgetattr(fd, &tm) < 0)
    389 		return (-1);
    390 	raw = tm;
    391 	cfmakeraw(&raw);
    392 	if (tcsetattr(fd, TCSANOW, &raw) < 0)
    393 		return (-1);
    394 	if ((flg = fcntl(fd, F_GETFL)) == -1)
    395 		return (-1);
    396 	if (fcntl(fd, F_SETFL, flg | O_NONBLOCK) == -1)
    397 		return (-1);
    398 	n = read(fd, buf, 1);
    399 	error = errno;
    400 	fcntl(fd, F_SETFL, flg);
    401 	tcsetattr(fd, TCSANOW, &tm);
    402 	if (n < 0)
    403 		return (error == EWOULDBLOCK ? 0 : -1);
    404 	if (n == 0)
    405 		return (0); /* EOF */
    406 	if (*buf == 0x1b)
    407 		return (1); /* ESC */
    408 
    409 	return (0);
    410 }
    411