#include <Xm/DrawingA.h>
#include <Xm/DrawnB.h>
#include <Xm/BulletinB.h>
#include <Xm/PushB.h>
#include <Xm/Form.h>
#include <Xm/Label.h>
#include <Xm/List.h>
#include <Xm/Protocols.h>
#include <Xm/Scale.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <linux/input.h>
#include <strings.h>
#include <errno.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
    
/* XPM Images */
#include <X11/xpm.h>
#include <cross3.xpm>
#include <star3.xpm>
#include <blank3.xpm>

#define DEBUG_OUT   1
extern int errno;

//#define ICON_SIZE 16
#define ICON_SIZE 32
#define MAX_DEVS  32
#define DEFAULT_ACCURACY  32
#define DEFAULT_TIMEOUT    30
#define DEFAULT_DEVLIST_FILE  "/etc/X11/EloX.conf"
#define USE_NEW_UI   1

char *corners[] = { "Top Left", "Top Right", "Bottom Left", "Bottom Right" };
char *predef_devs[] = {"/dev/ttyS0", "/dev/ttyS1", "/dev/input/event0", "/dev/input/event1", 
		"/dev/input/event2"
		};
char *predef_ser_speed[] = {"B9600", "B9600", NULL, NULL, NULL};
char *predef_ser_parms[] = {"8N1", "8N1", NULL, NULL, NULL};
char *devs[MAX_DEVS];
char *ser_speed[MAX_DEVS];
char *ser_parms[MAX_DEVS];
char *input_dev = NULL;
int accuracy = (-1);

int nDevs = 0;
int use_serial = 0;
int use_usb = 0;
char *selected_device = NULL;
char *selected_speed = NULL;
char *selected_parms = NULL;

// ----- Constants for Elo touchscreen ----
#define X_CENTER_LOCAL 	36
#define Y_CENTER_LOCAL  33
#define TOUCH_DELTA	accuracy
#define TOUCH_DELTA_S	2
// in the Motif axes - origin (0,0) @ top left corner. 
int screen_width, screen_height;

int x_centers_offsets[4] = { 0, 0, 0, 0};
int y_centers_offsets[4] = { 0, 0, 0, 0};

int x_touch_centers[4] = { 0, 0, 0, 0};
int y_touch_centers[4] = { 0, 0, 0, 0};
int touch_maxmin[4]  = { 0, 0, 0, 0};
int full_screen_mode = 1;
int timeout = DEFAULT_TIMEOUT;
static   struct sigaction saio;               //definition of signal action
int timeout_value = 0;
int debug_flag = 0;
char *devlist = DEFAULT_DEVLIST_FILE;
int use_devlist = 0;
int wait_bar_flag = 0;

// -----------------------------
// States: 
//  0 - initial, mice calibration for top-left
//  1 - mice calibration for top-right
//  2 - mice calibration for bottom-left
//  3 - mice calibration for bottom-right
//  4 - device driver select
//  5 - touch calibration for top-left
//  6 - touch calibration for top-right
//  7 - touch calibration for bottom-left
//  8 - final calculations, exit

int state =0;

// interprocess communication stuff ..
#define MSG_READ 			0x01
#define MSG_STOP			0xff
#define MSG_PRESS			0x02
#define MSG_READY    		0x03
#define MSG_OPEN_USB  		0x04
#define MSG_OPEN_SERIAL 	0x05
#define MSG_OPEN_OK		0x06
#define MSG_MAXMIN			0x07
#define MSG_TIMEOUT		0x08
#define MSG_ERROR			0x7f
#define MSG_TYPE			1

#define PROJ_PATH	"."
#define PROJ_ID_ELO          0x00454c4f         

key_t  ipc_key_up;
key_t  ipc_key_down;


typedef struct {
	char sx[8];
	char sy[8];
	char sz[8];
} ca_point_t;

typedef struct {
	unsigned char op;
	union  {
		ca_point_t point;
		char data[64];
		} body;
} ca_message_t;

typedef struct {
	long mtype;
	ca_message_t ca_mbuf;
} ca_msgbuf_t;

static   	int x_min = 4000;
static   	int x_max = 0;
static   	int y_min = 4000;
static   	int y_max = 0;

int msg_upstream_id;     // EloReader -> Motif app
int msg_downstream_id;    // Motif App -> Elo Reader 
int elo_reader_pid;

Pixmap pixmap_X0 = (Pixmap) 0 ;
Pixmap pixmap_X1 = (Pixmap) 0 ;
Pixmap pixmap_S = (Pixmap) 0 ;
Pixmap pixmap_B = (Pixmap) 0 ;
Widget Label;
Widget form;
Widget list;
Widget X_corner[4];
Widget progress_bar;
XtAppContext app; /* application context for the whole program */
XmRenderTable  render_table;
XmRendition rendition;

// --------------- Forward declarations ---------------
void destroy_it (Widget w, XtPointer client_data, XtPointer call_data);
void app_stop(int);
static Boolean read_proc(XtPointer client_data); 
void createDevList(Widget form,  int nDevs);  
void sel_callback (Widget list_w, XtPointer client_data, XtPointer call_data);
void pushed(Widget, XtPointer, XtPointer); /* callback for each corners buttons */
void signal_handler_bar (int signum);
static void Transparent_Object ( Widget The_Object, char *Transparent_icon[], Pixmap *Test, Pixel nbg);
void finalOutput(void);
void eloReader(void);
int eloUSBDriverOpen(char *devname);
void eloUSBDriverClose(void);
int eloUSBRead(void); 
static void xf86EloInputReadInput(unsigned char *buf, int *x, int *y, int *z);

static long get_BAUD(int Baud_Rate);                       // derived baud rate from selected line
static long get_DATABITS(int Data_Bits);
static long get_STOPBITS(int Stop_Bits);
static long get_PARITY(char Parity, long *PARITYON);
int eloSerialDriverOpen(char *devname, char *speed, char *parms);
void eloSerialDriverClose(void);
int eloSerialRead(void); 
static int xf86EloGetPacket(unsigned char	*buffer, 	 int *buffer_p,  int *checksum);
void usage(char *name);
int load_conf_file(int argc, char *argv[]); 
void parse_args(int argc, char *argv[]); 
int addDev(char *newdev, int add2file); 
void addToDevList(char *newdev);
int inDevParse(void);
#if DEBUG_OUT == 1
void hexdump(unsigned long start, int size);
#endif

void printCalibrationError(void);
void printMSGstreamError(void);

main (int argc, char *argv[])
{


	if ((ipc_key_up = ftok(PROJ_PATH, PROJ_ID_ELO)) < 0) {
		perror("ftok");
		fprintf(stderr, "Can't create the IPC key_up. Abort.\n");
		exit(1);
	}
	if ((ipc_key_down = ftok(PROJ_PATH, (PROJ_ID_ELO + 0x1f))) < 0) {
		perror("ftok");
		fprintf(stderr, "Can't create the IPC key_down. Abort.\n");
		exit(1);
	}
	if ((msg_upstream_id = msgget(ipc_key_up, IPC_CREAT| IPC_EXCL |0660)) == (-1)) {
		perror("msgget");
		fprintf(stderr, "Can't create the upstream message queue. Abort.\n");
		exit(1);
	}
	if ((msg_downstream_id = msgget(ipc_key_down, IPC_CREAT| IPC_EXCL |0660)) == (-1)) {
		perror("msgget");
		fprintf(stderr, "Can't create the downstream message queue. Abort.\n");
		if (msgctl(msg_upstream_id, IPC_RMID, NULL) == (-1)) {
			perror("msgctl");
			printMSGstreamError();
		}
	}

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "MGS streams created OK, start  \n"); fflush(stderr);
}
#endif
	if ((elo_reader_pid = fork()) == (-1)) {
		perror("fork");
		fprintf(stderr, "Can't create the Elo reader process. Abort.\n"); 
	}else  
		if (elo_reader_pid == 0) {
			eloReader();   
		}else {
		// Start the Motif App ...
		Widget       toplevel, button; 
		Screen *screen;
		Widget diashell, topshell;
		Pixel        fg, bg, nbg;
		Dimension    ht, st;
		Arg          args[10];
		int n;
		XmString str;
		Atom    property = (Atom)0;
		Atom    protocol   = (Atom)0;
		
		
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "The Elo Reader process created (pid=%d)\n", elo_reader_pid); fflush(stderr);
}
#endif		

		XtSetLanguageProc (NULL, NULL, NULL);

	
		/* Initialize toolkit and create toplevel shell */
		toplevel = XtVaOpenApplication (&app, "Demos", NULL, 0, &argc, argv, NULL, 
					 sessionShellWidgetClass, NULL);

		use_devlist = load_conf_file(argc, argv);

		if (use_devlist == 0 || nDevs == 0) {
			for (n =0; n < XtNumber(predef_devs); n++) {
				devs[ n] = predef_devs[ n];
				ser_speed[ n] = predef_ser_speed[ n];
				ser_parms[ n] = predef_ser_parms[n];
			}

			nDevs =	 XtNumber(predef_devs);	
		}

		parse_args(argc, argv);
		
			
		for(diashell = toplevel; !XtIsShell(diashell); diashell = XtParent(diashell));
		for(topshell = diashell; !XtIsTopLevelShell(topshell); topshell= XtParent(topshell));

		if ((property = XmInternAtom(XtDisplay (toplevel), "WM_PROTOCOLS", False)) == (Atom)0) {
			fprintf(stderr, "Can't create a property pointer. Abotr.\n");
			app_stop(1);
		}

		if ((protocol = XmInternAtom(XtDisplay (toplevel), "WM_DELETE_WINDOW", True)) == (Atom)0) {
			fprintf(stderr, "Can't create a protocol pointer. Abotr.\n");
			app_stop(1);
		}

		XmAddProtocols(diashell, property, &protocol, 1);
		XmAddProtocolCallback (diashell, property, protocol, destroy_it, NULL);
		

		n = 0;
		XtSetArg (args[n], XmNfractionBase, 60); n++;
		form = XmCreateForm (toplevel, "form",   args, n);
		screen = XtScreen(form);
		screen_width = screen->width;
		screen_height = screen->height;

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "screen: %d x %d\n", screen_width, screen_height); fflush(stderr);
}
#endif
		XtVaSetValues(toplevel, XmNwidth, screen->width, XmNheight, screen->height, NULL);

 		if (full_screen_mode) {
    			XtVaSetValues(topshell, XmNoverrideRedirect, TRUE, NULL);
			x_centers_offsets[0] = X_CENTER_LOCAL;
			x_centers_offsets[1] = screen_width -X_CENTER_LOCAL;
			x_centers_offsets[2] = X_CENTER_LOCAL;
			x_centers_offsets[3] = screen_width -X_CENTER_LOCAL;
			
			y_centers_offsets[0] = Y_CENTER_LOCAL;
			y_centers_offsets[1] = Y_CENTER_LOCAL;
			y_centers_offsets[2] = screen_height -Y_CENTER_LOCAL;
			y_centers_offsets[3] = screen_height -Y_CENTER_LOCAL;
				
		}

		button = XmCreateDrawnButton (form, corners[0], NULL, 0);
		X_corner[ 0] = button;
		XtVaSetValues (button, 
			XmNtopAttachment, XmATTACH_POSITION, XmNtopPosition,  1,
			XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition,  1,
			NULL);
		XtManageChild (button);
	
		XtVaGetValues (button, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
		XtVaSetValues (button, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
		XtAddCallback (button, XmNactivateCallback, pushed, NULL);
		XtAddCallback (button, XmNexposeCallback, pushed, NULL);
		XtAddCallback (button, XmNresizeCallback, pushed, NULL);

		button = XmCreateDrawnButton (form, corners[1], NULL, 0);
		X_corner[ 1] = button;
		XtVaSetValues (button,
			XmNtopAttachment, XmATTACH_POSITION, XmNtopPosition,  1,
			XmNrightAttachment, XmATTACH_POSITION , XmNrightPosition,  59,
			NULL);
		XtManageChild (button);
	
		XtVaGetValues (button, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
		XtVaSetValues (button, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
		XtAddCallback (button, XmNactivateCallback, pushed, NULL);
		XtAddCallback (button, XmNexposeCallback, pushed, NULL);
		XtAddCallback (button, XmNresizeCallback, pushed, NULL);

#if USE_NEW_UI == 1
		button = XmCreateDrawnButton (form, corners[3], NULL, 0);
		X_corner[ 3] = button;
		XtVaSetValues (button, 
			XmNbottomAttachment, XmATTACH_POSITION, XmNbottomPosition,  59,
			XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition,  59,
			NULL);
		XtManageChild (button);

		XtVaGetValues (button, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
		XtVaSetValues (button, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);

		XtAddCallback (button, XmNactivateCallback, pushed, NULL);
		XtAddCallback (button, XmNexposeCallback, pushed, NULL);
		XtAddCallback (button, XmNresizeCallback, pushed, NULL);
#else

		button = XmCreateDrawnButton (form, corners[2], NULL, 0);
		X_corner[ 2] = button;
		XtVaSetValues (button, 
			XmNbottomAttachment, XmATTACH_POSITION, XmNbottomPosition,  59,
			XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition,  1,
			NULL);
		XtManageChild (button);
	
		XtVaGetValues (button, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
		XtVaSetValues (button, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
		XtAddCallback (button, XmNactivateCallback, pushed, NULL);
		XtAddCallback (button, XmNexposeCallback, pushed, NULL);
		XtAddCallback (button, XmNresizeCallback, pushed, NULL);
#endif
		
		if (full_screen_mode == 0)  {
			button = XmCreateDrawnButton (form, corners[3], NULL, 0);
			X_corner[ 3] = button;
			XtVaSetValues (button, 
				XmNbottomAttachment, XmATTACH_POSITION, XmNbottomPosition,  59,
				XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition,  59,
				NULL);
			XtManageChild (button);
	
			XtVaGetValues (button, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
			XtVaSetValues (button, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
			XtAddCallback (button, XmNactivateCallback, pushed, NULL);
			XtAddCallback (button, XmNexposeCallback, pushed, NULL);
			XtAddCallback (button, XmNresizeCallback, pushed, NULL);
		}
		
		if (inDevParse() == 0) {
			createDevList(form, nDevs);
			input_dev = NULL;
		}else{
			if (full_screen_mode)
				XtAppAddWorkProc(app, read_proc, 0);
		}

		n=0;
		XtSetArg(args[n], XmNfontName, "-*-courier-bold-r-*--14-*"); n++; 
		XtSetArg(args[n], XmNfontType, XmFONT_IS_FONT); n++; 
		XtSetArg(args[n], XmNloadModel, XmLOAD_IMMEDIATE); n++; 
		rendition = XmRenditionCreate(toplevel, "tag1", args, n);
		render_table = XmRenderTableAddRenditions(NULL, &rendition, 1, XmMERGE_NEW);
		XmRenditionFree(rendition);
		

		n=0;
		str = XmStringCreateLocalized("Step 1: Use mouse for click center of 'X' at top left corner.");
		XtSetArg(args[n], XmNlabelString, str); n++; 
		XtSetArg(args[n], XmNrenderTable, render_table); n++; 
		Label = XmCreateLabel(form, "Msgs", args, n);
		XmStringFree(str);
		XtVaSetValues (Label, XmNtopAttachment,
			XmATTACH_POSITION, XmNtopPosition,  30,
			XmNleftAttachment, XmATTACH_POSITION,
			XmNleftPosition, 15, NULL);
		XtManageChild (Label);

		

		n=0;
		str = XmStringCreateLocalized("Wait for touch ...");
    		XtSetArg (args[n], XmNtitleString, str); n++;
    		XtSetArg (args[n], XmNmaximum, timeout+4);     n++;
    		XtSetArg (args[n], XmNminimum, 0);     n++;
    		XtSetArg (args[n], XmNvalue, timeout_value);     n++;
	       XtSetArg (args[n], XmNshowValue, True);  n++;
	       XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++;		   
	       XtSetArg (args[n], XmNprocessingDirection, XmMAX_ON_RIGHT); n++;
	       XtSetArg (args[n], XmNslidingMode, XmTHERMOMETER); n++;

    		progress_bar= XmCreateScale (form, "wait bar", args, n);
		XtVaSetValues (progress_bar, XmNtopAttachment, XmATTACH_WIDGET, 
		XmNtopWidget, Label,
		XmNleftAttachment, XmATTACH_POSITION,
		XmNleftPosition, 20, NULL);
		XmStringFree(str);
       		XtManageChild (progress_bar);

		saio.sa_handler = signal_handler_bar;
      		sigemptyset(&saio.sa_mask);   //saio.sa_mask = 0;
      		saio.sa_flags = 0;
      		saio.sa_restorer = NULL;
      		sigaction(SIGALRM,&saio,NULL);

			

#if 0
// We have timeout parameter ....
		if (full_screen_mode) {
			button = XmCreatePushButton (form, "Cancel",  NULL, 0);
			XtAddCallback (button, XmNactivateCallback, cancel_pushed, NULL);
			XtVaSetValues (button, XmNbottomAttachment, XmATTACH_WIDGET, 
			XmNbottomWidget, Label,
			XmNleftAttachment, XmATTACH_POSITION,
			XmNleftPosition, 4, NULL);
			XtManageChild (button);
		}
#endif

			
		if (full_screen_mode) {
			str = XmStringCreateLocalized("Step 1: Select the input device for the Elo touchscreen.");
			XtVaSetValues (Label, XmNlabelString, str, NULL);
			XmStringFree(str);
			state =4;
		}


		XtManageChild (form);
		XtRealizeWidget (toplevel);
		Transparent_Object(toplevel, cross3_xpm, &pixmap_X0, 0x00ff0000);
		Transparent_Object(toplevel, cross3_xpm, &pixmap_X1, 0x0000ff00);
		Transparent_Object(toplevel, star3_xpm, &pixmap_S, 0x00000000);
		Transparent_Object(toplevel, blank3_xpm, &pixmap_B, 0x00000000);

		XRaiseWindow(XtDisplay(topshell), XtWindow(topshell));
		XtAppMainLoop (app);
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "Motif App done ..\n"); fflush(stderr);
}
#endif
		app_stop(0);
		}
errors:
	if (msgctl(msg_upstream_id, IPC_RMID, NULL) == (-1)) {
		perror("msgctl");
		printMSGstreamError();
	}
	if (msgctl(msg_downstream_id, IPC_RMID, NULL) == (-1)) {
		perror("msgctl");
		printMSGstreamError();
	}
}


void signal_handler_bar (int signum)
{
	Widget    w;
	Dimension ht, st; 
/*
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "got signal %d\n", signum);
}
#endif
*/
   if (signum == SIGALRM) {    	
#if USE_NEW_UI == 1
	if (wait_bar_flag) {
		timeout_value+=2;
		XmScaleSetValue (progress_bar, timeout_value);
		XmUpdateDisplay(progress_bar);
		wait_bar_flag = 0;
		switch(state) {
			case 5: 
				w = X_corner[0];
				XtVaGetValues (w, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
				XtVaSetValues (w, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
				XCopyArea (XtDisplay (w), pixmap_X0, XtWindow (w),
				XDefaultGCOfScreen (XtScreen (w)), 0, 0, ICON_SIZE, ICON_SIZE, ht + st, ht + st);
				XmUpdateDisplay(w);
				break;
			case 6: 
				w = X_corner[3];
				XtVaGetValues (w, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
				XtVaSetValues (w, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
				XCopyArea (XtDisplay (w), pixmap_X0, XtWindow (w),
				XDefaultGCOfScreen (XtScreen (w)), 0, 0, ICON_SIZE, ICON_SIZE, ht + st, ht + st);
				XmUpdateDisplay(w);
				break;
			case 7: 
				w = X_corner[1];
				XtVaGetValues (w, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
				XtVaSetValues (w, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
				XCopyArea (XtDisplay (w), pixmap_X0, XtWindow (w),
				XDefaultGCOfScreen (XtScreen (w)), 0, 0, ICON_SIZE, ICON_SIZE, ht + st, ht + st);
				XmUpdateDisplay(w);
				break;
		}
	}else{
		wait_bar_flag = 1;
		switch(state) {
			case 5: 
				w = X_corner[0];
				XtVaGetValues (w, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
				XtVaSetValues (w, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
				XCopyArea (XtDisplay (w), pixmap_B, XtWindow (w),
				XDefaultGCOfScreen (XtScreen (w)), 0, 0, ICON_SIZE, ICON_SIZE, ht + st, ht + st);
				XmUpdateDisplay(w);
				break;
			case 6: 
				w = X_corner[3];
				XtVaGetValues (w, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
				XtVaSetValues (w, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
				XCopyArea (XtDisplay (w), pixmap_B, XtWindow (w),
				XDefaultGCOfScreen (XtScreen (w)), 0, 0, ICON_SIZE, ICON_SIZE, ht + st, ht + st);
				XmUpdateDisplay(w);
				break;
			case 7: 
				w = X_corner[1];
				XtVaGetValues (w, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
				XtVaSetValues (w, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
				XCopyArea (XtDisplay (w), pixmap_B, XtWindow (w),
				XDefaultGCOfScreen (XtScreen (w)), 0, 0, ICON_SIZE, ICON_SIZE, ht + st, ht + st);
				XmUpdateDisplay(w);
				break;
		}
	}
	alarm(1);
#else
	timeout_value+=2;
	XmScaleSetValue (progress_bar, timeout_value);
	XmUpdateDisplay(progress_bar);
	alarm(2);
#endif
   }
}

static void Transparent_Object ( Widget The_Object,
			 char *Transparent_icon[], Pixmap *Test, Pixel nbg)
{
    XpmAttributes XpmAttr;
    int Depth;
    Pixel Background= 0;
    static XpmColorSymbol XpmTransparentColor[1] =
					   {{ NULL, "none", 0 }};

    XtVaGetValues(The_Object, XmNdepth,&Depth, XmNbackground,
					       &Background,NULL);
    XpmTransparentColor[0].pixel = (Background | nbg);

    XpmAttr.valuemask    = XpmColorSymbols | XpmCloseness | XpmDepth;
    XpmAttr.colorsymbols = XpmTransparentColor;
    XpmAttr.numsymbols   = 1;
    XpmAttr.closeness    = 65535;
    XpmAttr.depth        = Depth;
    XpmCreatePixmapFromData( XtDisplay( The_Object ), DefaultRootWindow( XtDisplay(The_Object) ),
			 Transparent_icon, Test, NULL, &XpmAttr );
}


void usage(char *name) {
	printf("\nUsage:\n%s [X-args] [-help] [-full-screen |-max-window] [-input-dev devname] [[device_description] ...]\n", name);
	printf("\t-help\t\t-print this message\n");
	printf("\t-full-screen  -enable the full screen calibration window (default mode)\n");
	printf("\t-max-window - enable the calibration window with to maximum size\n");
	printf("\t-input-dev devname  - use the devname for input.\n");
	printf("\t-accurancy n  - use an accurancy of +/-n touchscreen pixels (default  12 pixels).\n");
	printf("\t-timeout n  - let timeout to read from an Elo touchscreen be n secs (default  30 secs).\n");
	printf("\t-dev-list file   - use 'file' for the read list of devices (default  %s).\n", DEFAULT_DEVLIST_FILE);
#if DEBUG_OUT == 1
	printf("\t-debug-out n  - use debugging printing level n (default  0).\n");
#endif	
	printf("\tdevice_description:   -newdev devname[@speed-parms] \n");
	printf("\tfor USB:\t\t-newdev /dev/input/event8\n");
	printf("\tfor Serial:\t-newdev /dev/ttyS2@B19200-8N1\n");
}

 int load_conf_file(int argc, char *argv[]) {
	int idx, rc;
	int fd;
	char *buf = NULL;
	
	idx =1;
	while(idx < argc) {
		if (*(argv[ idx] + 0) == '-') {
			if (!strcmp(argv[ idx], "-dev-list")) {
				if (idx >= argc) return;
				idx++;
				devlist= argv[ idx];
				}
		}
		idx++;
	}
	
#if DEBUG_OUT == 1
if (debug_flag)  {
	fprintf(stderr, "load_conf_file %s \n", devlist);
}
#endif
	if ((fd=open(devlist, O_RDONLY)) < 0) {
#if DEBUG_OUT == 1
if (debug_flag)  {
	fprintf(stderr, "Can't open devlist %s \n", devlist);
	perror("open devlist");
	fflush(stderr);
}
#endif
		return 0;
	}

// Read lines .conf file and add diveces ...	
	idx =0;
	if ((buf = (char *)malloc(128)) == NULL) return 0;

	while(1) {
	rc = read(fd, (buf + idx), 1)	;	
/*
#if DEBUG_OUT == 1
if (debug_flag)  {
	fprintf(stderr, "%c.", *(buf + idx));
	fflush(stderr);
}
#endif
*/
		if (rc != 1) {
			if (idx) { // we have something in the last line ...
				if (*buf != '#') {
					*(buf + idx) = '\0';
					if (strlen(buf) > 1) {
#if DEBUG_OUT == 1
if (debug_flag)  {
	fprintf(stderr, "Try add device [%s] to the list ...\n", buf);
}
#endif
						if ((rc = addDev(buf, 0)) == 0) free(buf);		
					}else
						free(buf);
				}else
					free(buf);
			}
			close(fd);
			return 1;
		}
		if (*(buf + idx) == '\r') continue;
		if (*(buf + idx) == '\n') {
			if (*buf == '#') {
				idx = 0;
				continue;
			}
			*(buf + idx) = '\0';
			if (!strlen(buf)) {
				idx = 0;
				continue;
			}
#if DEBUG_OUT == 1
if (debug_flag)  {
	fprintf(stderr, "Try add device [%s] to the list\n", buf);
}
#endif
			if ((rc = addDev(buf, 0)) == 0) free(buf);		
			idx =0;
			if ((buf = (char *)malloc(128)) == NULL) return 0;
		}else
		idx++;	
	}
	return 1;
}

void addToDevList(char *newdev) {
	int idx, rc;
	int fd;
	char buf[128];

#if DEBUG_OUT == 1
if (debug_flag)  {
	fprintf(stderr, "addToDevList  %s a new device [%s]\n", devlist, newdev);
}
#endif
	if ((fd=open(devlist, O_RDONLY)) < 0) {

#if DEBUG_OUT == 1
if (debug_flag)  {
	fprintf(stderr, "Can't open devlist %s \n", devlist);
	perror("open devlist");
	fflush(stderr);
}
#endif
		goto create_file;
	}
	
	idx =0;
	while(1) {
		rc = read(fd, (buf + idx), 1)	;	
		if (rc != 1) {
			if (idx) { // we have something in the last line ...
				if (*buf != '#') {
					*(buf + idx) = '\0';
					if (strlen(buf) > 1) {
#if DEBUG_OUT == 1
if (debug_flag)  {
	fprintf(stderr, "+Cmp device [%s] ...\n", buf);
}
#endif
						if (!strcmp(buf, newdev)) {		
							close(fd);
							return;
						}			
					}
				}
			}
			close(fd);
			break;
		}
		if (*(buf + idx) == '\r') continue;
		if (*(buf + idx) == '\n') {
			if (*buf == '#') {
				idx = 0;
				continue;
			}
			*(buf + idx) = '\0';
			if (!strlen(buf)) {
				idx = 0;
				continue;
			}
#if DEBUG_OUT == 1
if (debug_flag)  {
	fprintf(stderr, "-Cmp device [%s] ...\n", buf);
}
#endif
			if (!strcmp(buf, newdev)) {		
				close(fd);
				return;
			}
			idx = 0;
		}else
		idx++;	
	}

// OK, we here becouse no such device in the list ...	
	

	if ((fd=open(devlist, O_WRONLY | O_APPEND)) < 0) {

#if DEBUG_OUT == 1
if (debug_flag)  {
	fprintf(stderr, "Can't open devlist %s for append .. \n", devlist);
	perror("open devlist");
	fflush(stderr);
}
#endif
		return;
	}

	write(fd, newdev, strlen(newdev));
	buf[0] = '\n';
	write(fd, buf,1);
	close(fd);
	return;

create_file:

	if ((fd=open(devlist, O_WRONLY | O_CREAT |O_TRUNC)) < 0) {

#if DEBUG_OUT == 1
if (debug_flag)  {
	fprintf(stderr, "Can't open devlist %s for append .. \n", devlist);
	perror("open devlist");
	fflush(stderr);
}
#endif
		return;
	}

	strcpy(buf, "# ###########################################\n");
	write(fd, buf, strlen(buf));

	strcpy(buf, "# Elo X Configuration device list\n");
	write(fd, buf, strlen(buf));
	
	strcpy(buf, "# ###########################################\n");
	write(fd, buf, strlen(buf));

	write(fd, newdev, strlen(newdev));
	buf[0] = '\n';
	write(fd, buf,1);
	close(fd);
	return;

}


void parse_args(int argc, char *argv[]) {
	int idx;

#if DEBUG_OUT == 1
if (debug_flag)  {
	fprintf(stderr, "parse_args: argc=%d\n", argc);
	for (idx =0; idx <argc; idx++) {
		fprintf(stderr, "%d:  [%s]\n", idx, argv[ idx]);	
	}
}
#endif
	idx =1;
	while(idx < argc) {
		if (*(argv[ idx] + 0) == '-') {
			if (!strcmp(argv[ idx], "-help")) {
				usage(argv[0]); idx++;}
			else
			if (!strcmp(argv[ idx], "-full-screen")) {
				full_screen_mode = 1; idx++;}
			else
			if (!strcmp(argv[ idx], "-max-window")) {
				full_screen_mode = 0; idx++;}
			else
			if (!strcmp(argv[ idx], "-input-dev")) {
				if (idx >= argc) return;
				idx++;
				input_dev = argv[ idx];
				}
			else
			if (!strcmp(argv[ idx], "-accuracy")) {
				if (idx >= argc) return;
				idx++;
				accuracy= atoi(argv[ idx]);
				if (accuracy <=0) accuracy = DEFAULT_ACCURACY;
				}
			else
			if (!strcmp(argv[ idx], "-timeout")) {
				if (idx >= argc) return;
				idx++;
				timeout= atoi(argv[ idx]);
				if (timeout <0) timeout = DEFAULT_TIMEOUT;
				}
			else
			if (!strcmp(argv[ idx], "-dev-list")) {
				if (idx >= argc) return;
				idx++;
//				devlist= argv[ idx];
				}
			else
#if DEBUG_OUT == 1
			if (!strcmp(argv[ idx], "-debug-out")) {
				if (idx >= argc) return;
				idx++;
				debug_flag= atoi(argv[ idx]);
			}else
#endif
			if (!strcmp(argv[ idx], "-newdev")) {
				if (idx >= argc) return;
				idx++;
				addDev(argv[ idx], 1);
			}else
			        idx++;
		}else
		    idx++;
	}
	if (accuracy <=0) accuracy = DEFAULT_ACCURACY;
}

int addDev(char *newdev, int add2file) {
	int idx;
	char *sdev = NULL;
	char *sep, *sm;

#if DEBUG_OUT == 1
if (debug_flag)  {
 	fprintf(stderr, "addDev(%s, %d)\n", newdev, add2file);
}
#endif		
	if (newdev == NULL) return 0;
	if (add2file) addToDevList(newdev);
	
	if (nDevs >= MAX_DEVS) return 0;

	ser_speed[ nDevs] = NULL;
	ser_parms[ nDevs] = NULL;
	
	// Format input_dev: devname[@speed-parms]
	if ((sep = index(newdev, '@')) == NULL ) {
		devs[ nDevs]= newdev;
	}else{
		*sep = '\0';
		devs[ nDevs]= newdev;
		sep++;
		if ((sm=index(sep, '-')) == NULL) {
			fprintf(stderr, "Uncorrect input device format `%s@%s'. Ignored.\n", newdev, sep);
			return 0;
		}
		*sm = '\0';
		sm++;
		ser_speed[ nDevs] = sep;
		ser_parms[ nDevs] = sm;
	}
	nDevs++;
       return 1;
}

int inDevParse(void) {
	int idx;
	char *sdev = NULL;
	char *sep, *sm;
		
	if (input_dev == NULL) return 0;
		
	// Format input_dev: devname[@speed-parms]
	if ((sep = index(input_dev, '@')) == NULL ) {
		selected_device = input_dev;
		use_usb = 1;
	}else{
		selected_device = input_dev;
		*sep = '\0';
		sep++;
		if ((sm=index(sep, '-')) == NULL) {
			fprintf(stderr, "Uncorrect input device format. Ignored.\n");
			return 0;
		}
		*sm = '\0';
		sm++;
		selected_speed = sep;
		selected_parms = sm;
		use_serial = 1;
	}
       return 1;
}

void finalOutput(void) {
	int x_scale, y_scale, idx;
	int diff1, diff2, diff3;
	int delta;
	int Xmin, Xmax, Ymin, Ymax;
	float f1, f2, f3;
	int revx =0, revy =0;
	float fx_scale, fy_scale;

//    Motif has the origin point (0,0) @ top left corner.
// 1. Origin point for X axis.

	if (x_touch_centers[ 1] < x_touch_centers[ 0]) 
		// Touch X axis origin point on right side, we need "reverse" that ... 
		revx =1;

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "X reverse=%d\n", revx); fflush(stderr);
}
#endif

// 2. Origin point for Y axis.
#if USE_NEW_UI == 1
	if (y_touch_centers[1] > y_touch_centers[0])
		// Touch Y axis origin point on top side, we need "reverse" that ... 
		revy =1;
#else
	if (y_touch_centers[2] > y_touch_centers[0])
		// Touch Y axis origin point on top side, we need "reverse" that ... 
		revy =1;
#endif /* USE_NEW_UI */

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "Y reverse=%d\n", revy); fflush(stderr);
}
#endif


//	3. Define scale for the X (horizontal) axis.

#if USE_NEW_UI == 1
	diff1 = x_centers_offsets[ 1] - x_centers_offsets[ 0]; 
#else
	diff1 = x_centers_offsets[ 1] - x_centers_offsets[ 0]; 
#endif /* USE_NEW_UI */
	diff2 = x_centers_offsets[ 3] - x_centers_offsets[ 2]; 

	if ( diff1 != diff2) {
		if (abs((diff1 - diff2)) >	TOUCH_DELTA) {
			printCalibrationError();
			return;
		}
	   	diff1 = (diff1 > diff2)? diff1: diff2;
	}

	diff2 = abs((x_touch_centers[0] - ((x_touch_centers[1] > x_touch_centers[0])? x_touch_centers[0]: x_touch_centers[1])));
	diff3 = touch_maxmin[1] - touch_maxmin[0];

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "diff1=%d, diff2=%d, diff3 = %d\n",
		diff1, diff2, diff3); fflush(stderr);
}
#endif
	
	if ( diff3 != diff2) {
		if (abs((diff3 - diff2)) >	TOUCH_DELTA) {
			if (full_screen_mode) {
					printCalibrationError();
				}else
					printCalibrationError();
			return;
		}
	   	diff2 = (diff3 > diff2)? diff3: diff2;
	}

	f2 = diff2; f3 = diff1;

	f1 = (float)(f2/f3);

	
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "f_scale=%g (touch pixels for one screen pixel)\n",
		f1); fflush(stderr);
}
#endif
	fx_scale = f1;
	x_scale =(int)rintf(f1);
	
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "touch diff=%d, screen diff=%d, scale=%d (touch pixels for one screen pixel)\n",
		diff2, diff1, x_scale); fflush(stderr);
}
#endif

// 4. Calculate X_min.

	if (revx) {
		 Xmin = (x_centers_offsets[ 1] > x_centers_offsets[ 3])? x_centers_offsets[ 1] : x_centers_offsets[ 3] ;
		 Xmin = screen_width - Xmin;
	}else{
		 Xmin = (x_centers_offsets[ 0] < x_centers_offsets[ 2])? x_centers_offsets[ 0] : x_centers_offsets[ 2] ;
		}

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "screen Xmin=%d\n", Xmin); fflush(stderr);
}
#endif
	f1 = Xmin;
	f1 *=fx_scale;
	Xmin = (int)rintf(f1);
	Xmin = touch_maxmin[ 0] - Xmin;

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "Xmin=%d, touch Xmin=%d\n", Xmin, touch_maxmin[ 0]); fflush(stderr);
}
#endif

// 5. Calculate Xmax

	f1 = screen_width;
	f1 *= fx_scale;
	Xmax = Xmin + (int)rintf(f1);

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "Xmax=%d\n", Xmax); fflush(stderr);
}
#endif

//	6. Define scale for the Y (vertical) axis.

	diff1 = y_centers_offsets[ 2] - y_centers_offsets[ 0]; 
	diff2 = y_centers_offsets[ 3] - y_centers_offsets[ 1]; 

	if ( diff1 != diff2) {
		if (abs((diff1 - diff2)) >	TOUCH_DELTA) {
			printCalibrationError();
			return;
		}
	   	diff1 = (diff1 > diff2)? diff1: diff2;
	}

#if USE_NEW_UI == 1
	diff2 = abs((y_touch_centers[1] -((y_touch_centers[2] >y_touch_centers[0])? y_touch_centers[2] : y_touch_centers[0])));
#else
	diff2 = abs((y_touch_centers[2] - y_touch_centers[0]));
#endif
	diff3 = touch_maxmin[3] - touch_maxmin[2];


#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "diff1=%d, diff2=%d, diff3=%d\n", diff1, diff2, diff3); fflush(stderr);
	fprintf(stderr, "y: <0>=%d, <1>=%d, <2>=%d\n", y_touch_centers[0], y_touch_centers[1], y_touch_centers[2]);
	fprintf(stderr, "y min-max: %d, %d\n",  touch_maxmin[2], touch_maxmin[3]);
	fflush(stderr);
}
#endif
	
	if ( diff3 != diff2) {
		if (abs((diff3 - diff2)) >	TOUCH_DELTA) {
			if (full_screen_mode) {
					printCalibrationError();
				}else
					printCalibrationError();
			return;
		}
	   	diff2 = (diff3 > diff2)? diff3: diff2;
	}

	f2 = diff2; f3 = diff1;

	f1 = (float)(f2/f3);
	
	fy_scale = f1;
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "f_scale=%g (touch pixels for one screen pixel)\n",
		f1); fflush(stderr);
}
#endif
	y_scale =(int)rintf(f1);
	
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "touch diff=%d, screen diff=%d, scale=%d (touch pixels for one screen pixel)\n",
		diff2, diff1, y_scale); fflush(stderr);
}
#endif

// 7. Calculate Y_min.

	if (revy) {
		Ymin = (y_centers_offsets[ 0] > y_centers_offsets[ 1])? y_centers_offsets[ 0] : y_centers_offsets[ 1] ;
// not for Motif!	Ymin = screen_height - Ymin;
	}else{
		Ymin = (y_centers_offsets[ 2] < y_centers_offsets[ 3])? y_centers_offsets[ 2] : y_centers_offsets[ 3] ;
		Ymin = screen_height - Ymin;
	}

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "screen Ymin=%d\n", Ymin); fflush(stderr);
}
#endif
	
//	Ymin *= x_scale;
	f1 = Ymin;
	f1 *= fy_scale;
	Ymin = (int)rintf(f1);
	Ymin = touch_maxmin[ 2] - Ymin;

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "Ymin=%d, touch Ymin=%d\n", Ymin, touch_maxmin[ 2]); fflush(stderr);
}
#endif

// 8. Calculate Ymax

	f1 = screen_height;
	f1 *= fy_scale;
	Ymax = Ymin + (int)rintf(f1);

#if DEBUG_OUT == 1
if (debug_flag) {
fprintf(stderr, "Ymax=%d\n", Ymax); fflush(stderr);
}
#endif


// 9. And now - final output ....

		printf("Section \"Inputdevice\"\n");
		printf("\t\tIdentifier \"touchscreen1\"\n");
		printf("\t\tDriver \"%s\"\n",((use_usb)?"eloinput" : "elographics"));
		printf("\t\tOption \"AlwaysCore\"\n");
		printf("\t\tOption \"screenno\" \"0\"\n");
		printf("\t\tOption \"Device\" \"%s\"\n", selected_device);
		printf("\t\tOption \"MinX\" \"%d\"\n", (revx)? Xmax : Xmin);
		printf("\t\tOption \"MaxX\" \"%d\"\n", (revx)? Xmin : Xmax);
		printf("\t\tOption \"MinY\" \"%d\"\n",  (revy)? Ymax : Ymin);
		printf("\t\tOption \"MaxY\" \"%d\"\n", (revy)? Ymin : Ymax);
		printf("\t\tOption \"UntouchDelay\" \"3\"\n");
		printf("\t\tOption \"ReportDelay\" \"1\"\n");
		printf("EndSection\n");


#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "finalOutput() done OK.\n"); fflush(stderr);
}
#endif

}

void destroy_it (Widget w, XtPointer client_data, XtPointer call_data) {
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "destroy_it() ....\n"); fflush(stderr);
}
#endif
	app_stop(0xff);
}

void app_stop(int rc) {
	
	kill(elo_reader_pid, SIGKILL);

	if (msgctl(msg_upstream_id, IPC_RMID, NULL) == (-1)) {
		perror("msgctl");
		printMSGstreamError();
	}
	if (msgctl(msg_downstream_id, IPC_RMID, NULL) == (-1)) {
		perror("msgctl");
		printMSGstreamError();
	}
	if (rc != 0xff)
		exit(rc);
}

static Boolean read_proc(XtPointer client_data) {
	XmString     str;
	Widget    w;
	Dimension ht, st; 
	ca_msgbuf_t  msgbuf;
	int rc;
	char sbuf[256];

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "read_proc(), state %d\n", state);
	fflush(stderr);
}
#endif
	switch(state) {
		default: app_stop(1); break;
		case 4: 
			if ((rc = msgrcv(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0, 0)) ==(-1)){
					perror("msgrcv READY");
					fprintf(stderr, "Can't read READY message. Abort. (errno = %d)\n", errno);
					fflush(stderr);
					app_stop(1);
			}
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "Got a message with %d bytes...\n", rc); 						
	fflush(stderr);
}
#endif
			if (rc != sizeof(ca_message_t)) {
					fprintf(stderr, "Got a wrong length message (%d bytes, expect %d bytes) ...Abort.\n", rc, sizeof(ca_message_t));
					fflush(stderr);
					app_stop(1);
			}else{
			   	if (msgbuf.ca_mbuf.op == MSG_READY)
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "Try open %s\n", selected_device); 						
	fflush(stderr);
}
#endif
				if (use_usb) {
					msgbuf.ca_mbuf.op = MSG_OPEN_USB;
					msgbuf.mtype = MSG_TYPE;
					memset(msgbuf.ca_mbuf.body.data, 0x00, 64);
					strcpy(msgbuf.ca_mbuf.body.data, selected_device);
					if (msgsnd(msg_downstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
						perror("msgsnd OPEN USB");
						fprintf(stderr, "Can't send OPEN USB message. Abort.\n");
						fflush(stderr);
						app_stop(1);
					}
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "1. Send a message, wait response ...\n"); 						
	fflush(stderr);
}
#endif
					if ((rc = msgrcv(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0, 0)) ==(-1)) {
						perror("(reader) msgrcv OPEN_OK");
						fprintf(stderr, "Can't read OPEN_OK message. Abort.\n");
						fflush(stderr);
						app_stop(1);
					}
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "2. Got response ....\n"); 						
	fflush(stderr);
}
#endif
					if (msgbuf.ca_mbuf.op != MSG_OPEN_OK) {
						fprintf(stderr, "Can't open device `%s'. Abort.\n", selected_device);
						fflush(stderr);
						app_stop(1);
					}
					
				}else
				if (use_serial) {
					msgbuf.ca_mbuf.op = MSG_OPEN_SERIAL;
					msgbuf.mtype = MSG_TYPE;
					memset(msgbuf.ca_mbuf.body.data, 0x00, 64);
					strcpy(msgbuf.ca_mbuf.body.data, selected_device);
					strcat(msgbuf.ca_mbuf.body.data, "@");	
					strcat(msgbuf.ca_mbuf.body.data, selected_speed);
					strcat(msgbuf.ca_mbuf.body.data, "@");	
					strcat(msgbuf.ca_mbuf.body.data, selected_parms);
					if (msgsnd(msg_downstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
						perror("msgsnd OPEN SERIAL");
						fprintf(stderr, "Can't send OPEN SERIAL message. Abort.\n");
						fflush(stderr);
						app_stop(1);
					}
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "1s. Send a message, wait response ...\n"); 						
	fflush(stderr);
}
#endif
					if ((rc = msgrcv(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0, 0)) ==(-1)) {
						perror("(reader) msgrcv OPEN_OK");
						fprintf(stderr, "Can't read OPEN_OK message. Abort.\n");
						fflush(stderr);
						app_stop(1);
					}
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "2s. Got response ....\n"); 						
	fflush(stderr);
}
#endif
					if (msgbuf.ca_mbuf.op != MSG_OPEN_OK) {
						fprintf(stderr, "Can't open device `%s'. Abort.\n", selected_device);
						fflush(stderr);
						app_stop(1);
					}
					
				}
				sprintf(sbuf, "Step %d. Device %s open OK.\nStep %d: Touch and release the center of the \"X\" at the top left corner.", 
					((full_screen_mode)? 1: 5), selected_device, ((full_screen_mode)? 2: 6));
				str = XmStringCreateLocalized(sbuf);
				XtVaSetValues (Label, XmNlabelString, str, NULL);
				XmStringFree(str);

				timeout_value = 0;
				XmScaleSetValue (progress_bar, 0);
				XmUpdateDisplay(progress_bar);

				state = 5;
				return False;
				}
				break;
			case 5:
				
				/* Top Left */
				msgbuf.ca_mbuf.op = MSG_READ;
				msgbuf.mtype = MSG_TYPE;
				memset(msgbuf.ca_mbuf.body.data, 0x00, 64);
				sprintf(msgbuf.ca_mbuf.body.data,  "%d", timeout);
				if (msgsnd(msg_downstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
					perror("msgsnd READ");
					fprintf(stderr, "Can't send READ message. Abort.\n");
					fflush(stderr);
					app_stop(1);
				}
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "3. Send a message, wait response ...\n"); 						
	fflush(stderr);
}
#endif
#if USE_NEW_UI == 1
				alarm(1);
#else
				alarm(2);
#endif
				while (1) {
					if ((rc = msgrcv(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0, 0)) ==(-1)) {
						if (errno != EINTR) {
							perror("(reader) msgrcv PRESS");
							fprintf(stderr, "Can't read PRESS message (errno=%d). Abort.\n", errno);
							fflush(stderr);
							app_stop(1);
						}
					}else
					  break;
				}
				alarm(0);
				timeout_value = 0;
				XmScaleSetValue (progress_bar, 0);
				XmUpdateDisplay(progress_bar);

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "4. Got response ....\n"); 						
	fflush(stderr);
}
#endif
				if (msgbuf.ca_mbuf.op != MSG_PRESS) {
					fprintf(stderr, "Can't read information from device `%s'. Abort.\n", selected_device);
					fflush(stderr);
					app_stop(1);
				}
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "--got coordinates ---");
	hexdump((unsigned long)msgbuf.ca_mbuf.body.data, 32);
}
#endif
				sscanf(msgbuf.ca_mbuf.body.point.sx, "%d", &x_touch_centers[0]);
				sscanf(msgbuf.ca_mbuf.body.point.sy, "%d", &y_touch_centers[0]);

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "0: x=%d, y=%d\n",x_touch_centers[0], y_touch_centers[0]);
	fflush(stderr);
}
#endif

				w = X_corner[0];
				XtVaGetValues (w, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
				XtVaSetValues (w, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
				XCopyArea (XtDisplay (w), pixmap_S, XtWindow (w),
				XDefaultGCOfScreen (XtScreen (w)), 0, 0, ICON_SIZE, ICON_SIZE, ht + st, ht + st);

#if USE_NEW_UI == 1
				w = X_corner[3];
				XtVaGetValues (w, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
				XtVaSetValues (w, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
				XCopyArea (XtDisplay (w), pixmap_X0, XtWindow (w),
				XDefaultGCOfScreen (XtScreen (w)), 0, 0, ICON_SIZE, ICON_SIZE, ht + st, ht + st);

				sprintf(sbuf, "Step %d: Touch and release the center of the \"X\" at the bottom right corner.\n",
					((full_screen_mode)? 3: 7));
#else
				sprintf(sbuf, "Step %d: Touch and release the center of the \"X\" at the top right corner.\n",
					((full_screen_mode)? 3: 7));

#endif /* USE_NEW_UI */


				str = XmStringCreateLocalized(sbuf);
				XtVaSetValues (Label, XmNlabelString, str, NULL);
				XmStringFree(str);
				
				state = 6;
				return False;
			break;
		case 6:
			/* Top Right */
			msgbuf.ca_mbuf.op = MSG_READ;
			msgbuf.mtype = MSG_TYPE;
			memset(msgbuf.ca_mbuf.body.data, 0x00, 64);
			sprintf(msgbuf.ca_mbuf.body.data,  "%d", timeout);
			if (msgsnd(msg_downstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
				perror("msgsnd READ");
				fprintf(stderr, "Can't send READ message. Abort.\n");
				fflush(stderr);
				app_stop(1);
			}
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "5. Send a message, wait response ...\n"); 						
	fflush(stderr);
}
#endif
#if USE_NEW_UI == 1
				alarm(1);
#else
				alarm(2);
#endif
				while (1) {
					if ((rc = msgrcv(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0, 0)) ==(-1)) {
						if (errno != EINTR) {
							perror("(reader) msgrcv PRESS");
							fprintf(stderr, "Can't read PRESS message (errno=%d). Abort.\n", errno);
							fflush(stderr);
							app_stop(1);
						}
					}else
					  break;
				}
				alarm(0);
				timeout_value = 0;
				XmScaleSetValue (progress_bar, 0);
				XmUpdateDisplay(progress_bar);
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "6. Got response ....\n"); 						
	fflush(stderr);
}
#endif
			if (msgbuf.ca_mbuf.op != MSG_PRESS) {
				fprintf(stderr, "Can't read information from device `%s'. Abort.\n", selected_device);
				fflush(stderr);
				app_stop(1);
			}
#if DEBUG_OUT== 1
if (debug_flag) {
	fprintf(stderr, "--got coordinates ---");
	hexdump((unsigned long)msgbuf.ca_mbuf.body.data, 32);
}
#endif
				sscanf(msgbuf.ca_mbuf.body.point.sx, "%d", &x_touch_centers[1]);
				sscanf(msgbuf.ca_mbuf.body.point.sy, "%d", &y_touch_centers[1]);

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "1: x=%d, y=%d\n",x_touch_centers[1], y_touch_centers[1]);
	fflush(stderr);
}
#endif
#if USE_NEW_UI == 0
				if (abs(y_touch_centers[1] - y_touch_centers[0]) > TOUCH_DELTA) {
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "1d: diff (%d) too big ...\n",abs(y_touch_centers[1] - y_touch_centers[0]));
	fflush(stderr);
}
#endif
				sprintf(sbuf, "Repeat the touch and release of the center of the \"X\" at the top right corner.", 
						((full_screen_mode)? 3: 7));
					str = XmStringCreateLocalized(sbuf);
					XtVaSetValues (Label, XmNlabelString, str, NULL);
					XmStringFree(str);
				  	return False;	
				}
				w = X_corner[1];
#else
	   			w = X_corner[3];
#endif /* USE_NEW_UI */
				XtVaGetValues (w, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
				XtVaSetValues (w, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
				XCopyArea (XtDisplay (w), pixmap_S, XtWindow (w),
				XDefaultGCOfScreen (XtScreen (w)), 0, 0, ICON_SIZE, ICON_SIZE, ht + st, ht + st);
#if USE_NEW_UI == 1
				w = X_corner[1];
				XtVaGetValues (w, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
				XtVaSetValues (w, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
				XCopyArea (XtDisplay (w), pixmap_X0, XtWindow (w),
				XDefaultGCOfScreen (XtScreen (w)), 0, 0, ICON_SIZE, ICON_SIZE, ht + st, ht + st);

				sprintf(sbuf, "Step %d (final): Touch and release the center of the \"X\" at the top right corner.",
					((full_screen_mode)? 4: 8));
#else
				sprintf(sbuf, "Step %d (final): Touch and release the center of the \"X\" at the bottom left corner.",
					((full_screen_mode)? 4: 8));
#endif /* USE_NEW_UI */
				str = XmStringCreateLocalized(sbuf);
				XtVaSetValues (Label, XmNlabelString, str, NULL);
				XmStringFree(str);
			state = 7;
			return False;
			break;
		case 7:
			/* Bottom Left */
			msgbuf.ca_mbuf.op = MSG_READ;
			msgbuf.mtype = MSG_TYPE;
			memset(msgbuf.ca_mbuf.body.data, 0x00, 64);
			sprintf(msgbuf.ca_mbuf.body.data,  "%d", timeout);
			if (msgsnd(msg_downstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
				perror("msgsnd READ");
				fprintf(stderr, "Can't send READ message. Abort.\n");
				fflush(stderr);
				app_stop(1);
			}
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "7. Send a message, wait response ...\n"); 						
	fflush(stderr);
}
#endif
#if USE_NEW_UI == 1
				alarm(1);
#else
				alarm(2);
#endif
				while (1) {
					if ((rc = msgrcv(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0, 0)) ==(-1)) {
						if (errno != EINTR) {
							perror("(reader) msgrcv PRESS");
							fprintf(stderr, "Can't read PRESS message (errno=%d). Abort.\n", errno);
							fflush(stderr);
							app_stop(1);
						}
					}else
					  break;
				}
				alarm(0);
				timeout_value = 0;
				XmScaleSetValue (progress_bar, 0);
				XmUpdateDisplay(progress_bar);
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "8. Got response ....\n"); 						
	fflush(stderr);
}
#endif
			if (msgbuf.ca_mbuf.op != MSG_PRESS) {
				fprintf(stderr, "Can't read information from device `%s'. Abort.\n", selected_device);
				fflush(stderr);
				app_stop(1);
			}
#if DEBUG_OUT== 1
if (debug_flag) {
	fprintf(stderr, "--got coordinates ---");
	hexdump((unsigned long)msgbuf.ca_mbuf.body.data, 32);
}
#endif
				sscanf(msgbuf.ca_mbuf.body.point.sx, "%d", &x_touch_centers[2]);
				sscanf(msgbuf.ca_mbuf.body.point.sy, "%d", &y_touch_centers[2]);

#if DEBUG_OUT == 1
if (debug_flag) {
fprintf(stderr, "2: x=%d, y=%d\n",x_touch_centers[2], y_touch_centers[2]);
}
#endif
#if USE_NEW_UI == 1
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "Final:\n\t[0]: %d, %d\n\t[1]: %d, %d\n\t[2]: %d, %d\n",
		x_touch_centers[0], y_touch_centers[0],
		x_touch_centers[1], y_touch_centers[1],
		x_touch_centers[2], y_touch_centers[2]
		);
	fflush(stderr);
}
#endif
				if ((abs(x_touch_centers[2] - x_touch_centers[1]) > TOUCH_DELTA) ||
				     (abs(y_touch_centers[2] - y_touch_centers[0]) > TOUCH_DELTA)) {
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "2d: diff (%d, %d) too big ...\n",abs(x_touch_centers[2] - x_touch_centers[1]),
		abs(y_touch_centers[2] - y_touch_centers[0]));
	fflush(stderr);
}
#endif
 
					sprintf(sbuf, "Step %d : Please, repeat touch 'X' at top right corner.", 
						((full_screen_mode)? 4: 8));
					str = XmStringCreateLocalized(sbuf);
					XtVaSetValues (Label, XmNlabelString, str, NULL);
					XmStringFree(str);
				  	return False;	
				}
				w = X_corner[1];
#else /* USE_NEW_UI  */
				if (abs(x_touch_centers[2] - x_touch_centers[0]) > TOUCH_DELTA) {
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "2d: diff (%d) too big ...\n",abs(x_touch_centers[2] - x_touch_centers[0]));
	fflush(stderr);
}
#endif
 
					sprintf(sbuf, "Step %d : Please, repeat touch 'X' at top right corner.", 
						((full_screen_mode)? 4: 8));
					str = XmStringCreateLocalized(sbuf);
					XtVaSetValues (Label, XmNlabelString, str, NULL);
					XmStringFree(str);
				  	return False;	
				}
				w = X_corner[2];
#endif /* USE_NEW_UI */

				XtVaGetValues (w, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
				XtVaSetValues (w, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
				XCopyArea (XtDisplay (w), pixmap_S, XtWindow (w),
				XDefaultGCOfScreen (XtScreen (w)), 0, 0, ICON_SIZE, ICON_SIZE, ht + st, ht + st);
			state = 8;
			return False;
			break;	
		case 8:
			/* stop reader, final calculations ... */
			msgbuf.ca_mbuf.op = MSG_MAXMIN;
			msgbuf.mtype = MSG_TYPE;
			memset(msgbuf.ca_mbuf.body.data, 0x00, 64);
			if (msgsnd(msg_downstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
				perror("msgsnd MAXMIN");
				fprintf(stderr, "Can't send MAXMIN message. Abort.\n");
				fflush(stderr);
				app_stop(1);
			}

			if ((rc = msgrcv(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0, 0)) ==(-1)) {
				perror("(reader) msgrcv MAXMIN");
				fprintf(stderr, "Can't read MAXMIN message. Abort.\n");
				fflush(stderr);
				app_stop(1);
			}

			if (msgbuf.ca_mbuf.op != MSG_MAXMIN) {
				fprintf(stderr, "Can't read max- min information from device `%s'. Abort.\n", selected_device);
				fflush(stderr);
				app_stop(1);
			}

#if DEBUG_OUT== 1
if (debug_flag) {
	fprintf(stderr, "--got max min coordinates ---");
	hexdump((unsigned long)msgbuf.ca_mbuf.body.data, 32);
}
#endif
				sscanf(msgbuf.ca_mbuf.body.data, "%d", &touch_maxmin[0]);
				sscanf((&msgbuf.ca_mbuf.body.data[8]), "%d", &touch_maxmin[1]);
				sscanf((&msgbuf.ca_mbuf.body.data[16]), "%d", &touch_maxmin[2]);
				sscanf((&msgbuf.ca_mbuf.body.data[24]), "%d", &touch_maxmin[3]);

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, " xmin=%d, xmax=%d\n",touch_maxmin[0], touch_maxmin[1]);
	fprintf(stderr, " ymin=%d, ymax=%d\n",touch_maxmin[2], touch_maxmin[3]);
	fflush(stderr);
}
#endif

			finalOutput();

			msgbuf.ca_mbuf.op = MSG_STOP;
			msgbuf.mtype = MSG_TYPE;
			memset(msgbuf.ca_mbuf.body.data, 0x00, 64);
			if (msgsnd(msg_downstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
				perror("msgsnd STOP");
				fprintf(stderr, "Can't send STOP message. Abort.\n");
				fflush(stderr);
				app_stop(1);
			}
			app_stop(0);
		break;	
	}
	return True;   // do not include this proc to the app queue ...
}

void createDevList(Widget form,  int nDevs)  {
	XmString     str[32];
	Arg          args[10];
	int         i, n;
	XmStringTable str_list;
	Widget  dlabel;
	char buf[128];

	n=0;
	str[0] = XmStringCreateLocalized("Devices");
	XtSetArg(args[0], XmNlabelString, str[0]); n++; 
	dlabel = XmCreateLabel(form, "List", args, n);
	XmStringFree(str[0]);
	XtVaSetValues (dlabel, XmNtopAttachment,XmATTACH_FORM, 
		XmNleftAttachment, XmATTACH_POSITION,
		XmNleftPosition, 20, NULL);
	XtManageChild (dlabel);

	n = nDevs;
	str_list = (XmStringTable) XtMalloc (n * sizeof (XmString));

	for (i = 0; i < n; i++) {
		if (ser_speed[ i] != NULL)
			sprintf(buf, "%s @ %s-%s", devs[ i], ser_speed[ i], ser_parms[ i]);
		else
			sprintf(buf, "%s", devs[ i]);
		str_list[i] = XmStringCreateLocalized (buf);
	}
		
	i = 0;
	XtSetArg (args[i], XmNvisibleItemCount, n); i++;
	XtSetArg (args[i], XmNitemCount, n); i++;
	XtSetArg (args[i], XmNitems, str_list); i++;
	list = XmCreateList (form, "Devices", args, i);
	
	XtVaSetValues (list, XmNtopAttachment,XmATTACH_WIDGET,
		XmNtopWidget, dlabel,
		XmNleftAttachment, XmATTACH_POSITION,
		XmNleftPosition, 20, NULL);


	XtAddCallback (list, XmNdefaultActionCallback, sel_callback, NULL);
	XtAddCallback (list, XmNbrowseSelectionCallback, sel_callback, NULL);

	for (i = 0; i < n; i++)
		XmStringFree (str_list[i]);
	XtFree ((char *) str_list);
	
	XtManageChild (list);

}

#if 0
void cancel_pushed ( Widget    w, /* The PushButton that got activated */
	      XtPointer client_data, /* unused -- NULL was passed to XtAddCallback() */
	      XtPointer call_data)
{
	app_stop(0);
}
#endif

void pushed ( Widget    w, /* The PushButton that got activated */
	      XtPointer client_data, /* unused -- NULL was passed to XtAddCallback() */
	      XtPointer call_data)
{
	XmDrawnButtonCallbackStruct *cbs = (XmDrawnButtonCallbackStruct *)call_data;
	Dimension ht, st; 
	int delta;
	XmString     str;
	
	
	if (cbs->reason == XmCR_ACTIVATE) {
#if DEBUG_OUT == 1
if (debug_flag) {
		fprintf(stderr, "%s: pushed %d times\n", XtName(w), cbs->click_count);
		fprintf(stderr, "x=%d, y=%d, x_root=%d, y_root=%d\n",
		cbs->event->xbutton.x, cbs->event->xbutton.y,
		cbs->event->xbutton.x_root, cbs->event->xbutton.y_root);
		fflush(stderr);
		fprintf(stderr, "0: %d - %d\n", x_centers_offsets[0], y_centers_offsets[0]);
		fprintf(stderr, "1: %d - %d\n", x_centers_offsets[1], y_centers_offsets[1]);
		fprintf(stderr, "2: %d - %d\n", x_centers_offsets[2], y_centers_offsets[2]);
		fprintf(stderr, "3: %d - %d\n", x_centers_offsets[3], y_centers_offsets[3]);
		fflush(stderr);
}
#endif
	switch (state) {
		case 0:
				if (strcmp(XtName(w), corners[0])) break;

				x_centers_offsets[0] = cbs->event->xbutton.x_root;
				y_centers_offsets[0]	= cbs->event->xbutton.y_root;			

/*							
				if (cbs->event->xbutton.x < (X_CENTER_LOCAL - TOUCH_DELTA_S) || 
	                          cbs->event->xbutton.x > (X_CENTER_LOCAL + TOUCH_DELTA_S) )
	                      break;    
				if (cbs->event->xbutton.y < (Y_CENTER_LOCAL - TOUCH_DELTA_S) || 
	                          cbs->event->xbutton.y > (Y_CENTER_LOCAL + TOUCH_DELTA_S) )
	                      break;    
*/
				 delta = cbs->event->xbutton.x -X_CENTER_LOCAL;  
				 x_centers_offsets[0] -= delta;
				 delta = cbs->event->xbutton.y -Y_CENTER_LOCAL;  
				 y_centers_offsets[0] -= delta;
				
				XtVaGetValues (w, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
				XtVaSetValues (w, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
				XCopyArea (XtDisplay (w), pixmap_X1, XtWindow (w),
				XDefaultGCOfScreen (XtScreen (w)), 0, 0, ICON_SIZE, ICON_SIZE, ht + st, ht + st);

				str = XmStringCreateLocalized("Step 2: Use mouse for click center of 'X' at top right corner.");
				XtVaSetValues (Label, XmNlabelString, str, NULL);
				XmStringFree(str);

				state =1;
			break;	
		case 1:
				if (strcmp(XtName(w), corners[1])) break;
				
				x_centers_offsets[1] = cbs->event->xbutton.x_root;
				y_centers_offsets[1]	= cbs->event->xbutton.y_root;			

/*							
				if (cbs->event->xbutton.x < (X_CENTER_LOCAL - TOUCH_DELTA_S) || 
	                          cbs->event->xbutton.x > (X_CENTER_LOCAL + TOUCH_DELTA_S) )
	                      break;    
				if (cbs->event->xbutton.y < (Y_CENTER_LOCAL - TOUCH_DELTA_S) || 
	                          cbs->event->xbutton.y > (Y_CENTER_LOCAL + TOUCH_DELTA_S) )
	                      break;    
*/
				 delta = cbs->event->xbutton.x -X_CENTER_LOCAL;  
				 x_centers_offsets[1] -= delta;
				 delta = cbs->event->xbutton.y -Y_CENTER_LOCAL;  
				 y_centers_offsets[1] -= delta;

				
				XtVaGetValues (w, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
				XtVaSetValues (w, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
				XCopyArea (XtDisplay (w), pixmap_X1, XtWindow (w),
				XDefaultGCOfScreen (XtScreen (w)), 0, 0, ICON_SIZE, ICON_SIZE, ht + st, ht + st);

				str = XmStringCreateLocalized("Step 3: Use mouse for click center of 'X' at bottom left corner.");
				XtVaSetValues (Label, XmNlabelString, str, NULL);
				XmStringFree(str);

				state =2;
			break;	
		case 2:
				if (strcmp(XtName(w), corners[2])) break;
				
				x_centers_offsets[2] = cbs->event->xbutton.x_root;
				y_centers_offsets[2]	= cbs->event->xbutton.y_root;			

/*							
				if (cbs->event->xbutton.x < (X_CENTER_LOCAL - TOUCH_DELTA_S) || 
	                          cbs->event->xbutton.x > (X_CENTER_LOCAL + TOUCH_DELTA_S) )
	                      break;    
				if (cbs->event->xbutton.y < (Y_CENTER_LOCAL - TOUCH_DELTA_S) || 
	                          cbs->event->xbutton.y > (Y_CENTER_LOCAL + TOUCH_DELTA_S) )
	                      break;    
*/
				 delta = cbs->event->xbutton.x -X_CENTER_LOCAL;  
				 x_centers_offsets[2] -= delta;
				 delta = cbs->event->xbutton.y -Y_CENTER_LOCAL;  
				 y_centers_offsets[2] -= delta;

				
				XtVaGetValues (w, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
				XtVaSetValues (w, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
				XCopyArea (XtDisplay (w), pixmap_X1, XtWindow (w),
				XDefaultGCOfScreen (XtScreen (w)), 0, 0, ICON_SIZE, ICON_SIZE, ht + st, ht + st);

				str = XmStringCreateLocalized("Step 4: Use mouse for click center of 'X' at bottom right corner.");
				XtVaSetValues (Label, XmNlabelString, str, NULL);
				XmStringFree(str);

				state =3;
			break;	
		case 3:
				if (strcmp(XtName(w), corners[3])) break;
				
				x_centers_offsets[3] = cbs->event->xbutton.x_root;
				y_centers_offsets[3]	= cbs->event->xbutton.y_root;			
/*

				if (cbs->event->xbutton.x < (X_CENTER_LOCAL - TOUCH_DELTA_S) || 
	                          cbs->event->xbutton.x > (X_CENTER_LOCAL + TOUCH_DELTA_S) )
	                      break;    
				if (cbs->event->xbutton.y < (Y_CENTER_LOCAL - TOUCH_DELTA_S) || 
	                          cbs->event->xbutton.y > (Y_CENTER_LOCAL + TOUCH_DELTA_S) )
	                      break;    
*/
				 delta = cbs->event->xbutton.x -X_CENTER_LOCAL;  
				 x_centers_offsets[3] -= delta;
				 delta = cbs->event->xbutton.y -Y_CENTER_LOCAL;  
				 y_centers_offsets[3] -= delta;

				
				XtVaGetValues (w, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
				XtVaSetValues (w, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
				XCopyArea (XtDisplay (w), pixmap_X1, XtWindow (w),
				XDefaultGCOfScreen (XtScreen (w)), 0, 0, ICON_SIZE, ICON_SIZE, ht + st, ht + st);

				str = XmStringCreateLocalized("Step 5: Select the input device for EloTouchscreen.");
				XtVaSetValues (Label, XmNlabelString, str, NULL);
				XmStringFree(str);

				state =4;
				if (input_dev != NULL) 
					 XtAppAddWorkProc(app, read_proc, 0);
			break;	
		}
	}
	else if (cbs->reason == XmCR_EXPOSE) {
#if DEBUG_OUT == 1
if (debug_flag) {
		fprintf(stderr, "EXPOSE %s ...\n", XtName(w));
		fflush(stderr);
}
#endif	

			XtVaGetValues (w, XmNhighlightThickness, &ht, XmNshadowThickness, &st, NULL);
			XtVaSetValues (w, XmNwidth, 2 * ht + 2 * st + ICON_SIZE, XmNheight, 2 * ht + 2 * st + ICON_SIZE, NULL);
	
		if (!strcmp(XtName(w), corners[0])) {
			XCopyArea (XtDisplay (w), pixmap_X0, XtWindow (w),
			XDefaultGCOfScreen (XtScreen (w)), 0, 0, ICON_SIZE, ICON_SIZE, ht + st, ht + st);
			}
		else	{
			XCopyArea (XtDisplay (w), pixmap_B, XtWindow (w),
			XDefaultGCOfScreen (XtScreen (w)), 0, 0, ICON_SIZE, ICON_SIZE, ht + st, ht + st);
			}
		
	}
#if DEBUG_OUT == 1
	else 
if (debug_flag) {
	 /* XmCR_RESIZE */
		fprintf(stderr, "Resize");
	}
#endif
}

void sel_callback (Widget list_w, XtPointer client_data, XtPointer call_data)
{
	XmListCallbackStruct *cbs = (XmListCallbackStruct *) call_data;
	char *choice;
	struct msqid_ds msgstat;
	int rc;
	
#if DEBUG_OUT == 1
if (debug_flag) {
	if (cbs->reason == XmCR_BROWSE_SELECT)
		fprintf(stderr, "Browse selection -- ");
	else
		fprintf(stderr, "Default action -- ");
	fflush(stderr);
}
#endif

	choice = (char *) XmStringUnparse (cbs->item, XmFONTLIST_DEFAULT_TAG, 
					   XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "selected item: %s (%d)\n", choice, cbs->item_position);
	fflush(stderr);
}
#endif

	if (state == 4) {
		selected_device = devs[cbs->item_position -1];
		if ((index(choice, '@')) == NULL) { 
			use_usb = 1;
#if DEBUG_OUT == 1
if (debug_flag) {
fprintf(stderr, "Use USB driver for %s\n", selected_device);
fflush(stderr);
}
#endif
		}else{
			use_serial = 1;
			selected_speed = ser_speed[cbs->item_position -1];
			selected_parms = ser_parms[cbs->item_position -1];
#if DEBUG_OUT == 1
if (debug_flag) {
fprintf(stderr, "use serial driver for %s %s %s\n", selected_device, selected_speed, selected_parms);
fflush(stderr);
}
#endif
		}
	 XtFree (choice);
	 XtAppAddWorkProc(app, read_proc, 0);
	}
}

void eloReader(void) {
	int rc;
	ca_msgbuf_t  msgbuf;
	struct msqid_ds msgstat;
	char sel_dev[64];


	if ((msg_upstream_id = msgget(ipc_key_up,  IPC_EXCL |0660)) == (-1)) {
			perror("msgget");
			fprintf(stderr, "Can't attach the message up stream (errno=%d). Abort.\n", errno);
			exit(1);
	}
	if ((msg_downstream_id = msgget(ipc_key_down,  IPC_EXCL |0660)) == (-1)) {
			perror("msgget");
			fprintf(stderr, "Can't attach the message down stream (errno=%d) . Abort.\n", errno);
			exit(1);
	}
	

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "eloReader started... \n");	fflush(stderr);
}
#endif
	msgbuf.ca_mbuf.op = MSG_READY;
	msgbuf.mtype = MSG_TYPE;
	if (msgsnd(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
		perror("msgsnd READY");
		fprintf(stderr, "Can't send READY message. Abort.\n");
		exit(1);
	}

#if DEBUG_OUT == 1
if (debug_flag) {
	if ((rc = msgctl(msg_upstream_id, MSG_STAT, &msgstat)) ==(-1)) {
		perror("--msgctl");
	}
}
#endif
/* Linux is not good with RMID IPC call ... but it works ...
#if DEBUG_OUT == 1
fprintf(stderr, "USB Reader ready (%d messages in the upstream queue)\n", msgstat.msg_qnum);
fflush(stderr);
#endif

	while (1){
		if ((rc = msgctl(msg_upstream_id, MSG_STAT, &msgstat)) ==(-1)) {
			perror("msgctl");
		}
		if (msgstat.msg_qnum == 0) break;
	};
*/
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "USB/Serial Reader continue ...\n");
	fflush(stderr);
}
#endif
	while(1) {
		if ((rc = msgrcv(msg_downstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0, 0)) ==(-1)){
			perror("(reader) msgrcv");
			fprintf(stderr, "Can't read a message. Abort.\n");
			fflush(stderr);
			exit(1);
		}
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "Got op 0x%02x\n", msgbuf.ca_mbuf.op);
	fflush(stderr);
}
#endif

		switch (msgbuf.ca_mbuf.op) {
			default: 
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "Its a bad op: 0x%02x\n", msgbuf.ca_mbuf.op);
	fflush(stderr);
}
#endif
				msgbuf.ca_mbuf.op = MSG_ERROR;
				msgbuf.mtype = MSG_TYPE;
				if (msgsnd(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
					perror("msgsnd ERROR");
					fprintf(stderr, "Can't send ERROR message. Abort.\n");
					fflush(stderr);
					exit(1);
				}
				break;
			case MSG_STOP:
				if (use_usb)
					eloUSBDriverClose();
				if (use_serial)
					eloSerialDriverClose();
				if (msgctl(msg_upstream_id, IPC_RMID, NULL) == (-1)) {
					perror("msgctl");
					printMSGstreamError();
				}
				if (msgctl(msg_downstream_id, IPC_RMID, NULL) == (-1)) {
					perror("msgctl");
					printMSGstreamError();
				}
				exit(0);
				break;
			case MSG_OPEN_USB:
			    	strcpy(sel_dev, msgbuf.ca_mbuf.body.data);
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "Start eloUSBDriverOpen for [%s]\n", sel_dev);
	fflush(stderr);
}
#endif
			    	if (eloUSBDriverOpen(sel_dev)) {
					msgbuf.ca_mbuf.op = MSG_OPEN_OK;
					use_usb = 1;
			    	}
			    	else		
					msgbuf.ca_mbuf.op = MSG_ERROR;
			    	msgbuf.mtype = MSG_TYPE;
				if (msgsnd(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
					perror("msgsnd OPEN_OK");
					fprintf(stderr, "Can't send OPEN_OK message. Abort.\n");
					fflush(stderr);
					exit(1);
				}
				break;
			case MSG_OPEN_SERIAL: 
				{
					char *pc, *ps;		
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "Start eloSerialDriverOpen for [%s]\n", msgbuf.ca_mbuf.body.data);
	fflush(stderr);
}
#endif	
					pc = index(msgbuf.ca_mbuf.body.data, '@');
					*pc = '\0'; pc++;
			    		strcpy(sel_dev, msgbuf.ca_mbuf.body.data);
					ps = index(pc, '@');
					*ps = '\0'; ps++;
			    		if (eloSerialDriverOpen(sel_dev, pc, ps)) {
						msgbuf.ca_mbuf.op = MSG_OPEN_OK;
						use_serial = 1;
			    		}
			    		else		
						msgbuf.ca_mbuf.op = MSG_ERROR;
			    		msgbuf.mtype = MSG_TYPE;
					if (msgsnd(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
						perror("msgsnd OPEN_OK");
						fprintf(stderr, "Can't send OPEN_OK message. Abort.\n");
						fflush(stderr);
						exit(1);
					}
				}
				break;
			case MSG_READ:
				timeout = DEFAULT_TIMEOUT;
				sscanf(msgbuf.ca_mbuf.body.data, "%d", &timeout);
				if ( use_usb) {
					eloUSBRead();							
				}else
				if ( use_serial) {
					eloSerialRead();
				}else{
					msgbuf.ca_mbuf.op = MSG_ERROR;
			    		msgbuf.mtype = MSG_TYPE;
					if (msgsnd(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
						perror("msgsnd READ ERROR");
						fprintf(stderr, "Can't send READ ERROR message. Abort.\n");
						fflush(stderr);
						exit(1);
					}
				}
				break;
			case MSG_MAXMIN:
				msgbuf.ca_mbuf.op = MSG_MAXMIN;
			    	msgbuf.mtype = MSG_TYPE;
				memset(msgbuf.ca_mbuf.body.data, 0x00, 64);
				sprintf(msgbuf.ca_mbuf.body.data,  "%d", x_min);
				sprintf((&msgbuf.ca_mbuf.body.data[8]), "%d", x_max);
				sprintf((&msgbuf.ca_mbuf.body.data[16]), "%d", y_min);
				sprintf((&msgbuf.ca_mbuf.body.data[24]), "%d", y_max);
				if (msgsnd(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
					perror("msgsnd MAXMIN");
					fprintf(stderr, "Can't send MAXMIN message. Abort.\n");
					fflush(stderr);
					exit(1);
				}
				break;
	}
	}	
}


static int fd;     // device descriptor ...
static Boolean wait_flag=True;                  //TRUE while no signal received
volatile Boolean STOP=False;
static int touched =0; 
static  struct termios oldtio, newtio;       //place for old and new port settings for serial port
static char save_dev[254], save_speed[32], save_parms[16]; // for restart serial port ... 

static unsigned char serial_buf[255];                   //buffer for where data is put
static int  serial_idx = 0;
static int  serial_res;

#define WORD_ASSEMBLY(byte1, byte2)	(((byte2) << 8) | (byte1))
#define	ELO_USB_PRESS			0x01	/* Flags in ELO_TOUCH status byte	*/
#define	ELO_USB_STREAM		0x02
#define   ELO_USB_RELEASE		0x04

/*
 ***************************************************************************
 *
 * Protocol constants for Serial.
 *
 ***************************************************************************
 */
#define ELO_PACKET_SIZE		10

#define ELO_SYNC_BYTE		'U'	/* Sync byte. First of a packet.	*/
#define ELO_TOUCH		'T'	/* Report of touchs and motions. Not	*
					 * used by 2310.			*/
#define ELO_OWNER		'O'	/* Report vendor name.			*/
#define ELO_ID			'I'	/* Report of type and features.		*/
#define ELO_MODE		'M'	/* Set current operating mode.		*/
#define ELO_PARAMETER		'P'	/* Set the serial parameters.		*/
#define ELO_REPORT		'B'	/* Set touch reports timings.		*/
#define ELO_ACK			'A'	/* Acknowledge packet			*/

#define ELO_INIT_CHECKSUM	0xAA	/* Initial value of checksum.		*/

#define	ELO_PRESS		0x01	/* Flags in ELO_TOUCH status byte	*/
#define	ELO_STREAM		0x02
#define ELO_RELEASE		0x04

#define ELO_TOUCH_MODE		0x01	/* Flags in ELO_MODE command		*/
#define ELO_STREAM_MODE		0x02
#define ELO_UNTOUCH_MODE	0x04
#define ELO_RANGE_CHECK_MODE	0x40
#define ELO_TRIM_MODE		0x02
#define ELO_CALIB_MODE		0x04
#define ELO_SCALING_MODE	0x08
#define ELO_TRACKING_MODE	0x40


/***************************************************************************
* signal handler. sets wait_flag to FALSE, to indicate above loop that     *
* characters have been received.                                           *
***************************************************************************/

void signal_handler_IO (int signum)
{
//   fprintf(stderr, "signal_handler_IO(): received signal %d.\n", signum);
   switch (signum) {
   default :   wait_flag = False; break;
   case SIGIO:   		wait_flag = False; break;
   case SIGALRM:    	STOP=True;  break;
   }
}


// ------------- USB Driver --------------------

int eloUSBDriverOpen(char *devname)
{

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "eloUSBDriverOpen() for %s\n", devname);
	fflush(stderr);
}
#endif

     //open the device(USB port) to be non-blocking (read will return immediately)
      fd = open(devname, O_RDWR | O_NOCTTY | O_NONBLOCK);
      if (fd < 0)
      {
         perror(devname);
         return 0;
      }
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "open OK for %s\n", devname);
	fflush(stderr);
}
#endif

	//install the serial handler before making the device asynchronous
      saio.sa_handler = signal_handler_IO;
      sigemptyset(&saio.sa_mask);   //saio.sa_mask = 0;
      saio.sa_flags = 0;
      saio.sa_restorer = NULL;
      sigaction(SIGIO,&saio,NULL);
      sigaction(SIGALRM,&saio,NULL);

      // allow the process to receive SIGIO
      fcntl(fd, F_SETOWN, getpid());
      // Make the file descriptor asynchronous (the manual page says only
      // O_APPEND and O_NONBLOCK, will work with F_SETFL...)
      fcntl(fd, F_SETFL, FASYNC);

	return 1;
      		
}

void eloUSBDriverClose(void)
{

	close(fd);
	wait_flag = True;
	STOP=True;
	
}
int eloUSBRead(void) {
   	unsigned int ibuf[64], eibuf[64];                       //buffer for where data is put
   	unsigned char *elobuf;	   
   	unsigned char *buf;
	int linecnt =0, i, res, rc;
	ca_msgbuf_t  msgbuf;
	struct msqid_ds msgstat;
	int xc =1, yc = -1;
	int press_event_ok = 0;

	elobuf = (unsigned char *)&eibuf[0];
	buf = (unsigned char *)&ibuf[ 0];	
	STOP=False;
	wait_flag = True;
	alarm(timeout);
	

	// loop while waiting for input. normally we would do something useful here
      while (STOP==False) {
         if (wait_flag==False)  //if input is available
         {
		alarm(0);
		res = read(fd, buf, 255);

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "eloUSBRead(): res=%d\n", res);
	// hexdump((unsigned long)buf, res);
	fflush(stderr);
}
#endif
            if (res>0)
            {
               for (i=0; i<res; i++)  //for all chars in string
               {
			elobuf[linecnt] = buf[i];
	       	linecnt++;
               	if (linecnt == sizeof(struct input_event)) {
				int x,y, i_state;	
				linecnt =0;
/*
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "--- elobuf ----");
	hexdump((unsigned long)elobuf, sizeof(struct input_event));
	fflush(stderr);
}
#endif
*/
				xf86EloInputReadInput(elobuf, &x, &y, &i_state);
					if (x >= 0) {
						xc = x;
						x_min = (x < x_min)? x: x_min;
						x_max =(x > x_max)? x : x_max;
					}
					if (y >= 0) {
						yc = y;
						y_min = (y < y_min)? y : y_min;
						y_max =(y > y_max)? y : y_max;
					}
				if (i_state == ELO_USB_PRESS) {
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "eloUSBRead(): got ELO_USB_PRESS, xc=%d, yc=%d\n", xc, yc);
	fflush(stderr);
}
#endif
/*
					if ( xc > 0 && yc > 0)  {
						press_event_ok = 1;
						msgbuf.ca_mbuf.op=MSG_PRESS;
						msgbuf.mtype = MSG_TYPE;
						memset(msgbuf.ca_mbuf.body.data, 0x00, 64);
						sprintf(msgbuf.ca_mbuf.body.point.sx, "%d", xc);
						sprintf(msgbuf.ca_mbuf.body.point.sy, "%d", yc);
						sprintf(msgbuf.ca_mbuf.body.point.sz, "%d", 0);
						if (msgsnd(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
							perror("msgsnd PRESS");
							fprintf(stderr, "Can't send PRESS message. Abort.\n");
							exit(1);
						}
					   }	
*/					   
/*				
#if DEBUG_OUT == 1
	else { // if ( xc > 0 && yc > 0) 
if (debug_flag) {
	fprintf(stderr, "eloUSBRead(): got ELO_USB_PRESS, doesn't send a message (xc=%d, yc=%d)\n", xc, yc);
	fflush(stderr);
}
		}
#endif
*/
					}
				if (i_state == ELO_USB_RELEASE) {
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "eloUSBRead(): got ELO_USB_RELEASE, exit (xc=%d, yc=%d, press=%d)\n", xc, yc, press_event_ok);
	fflush(stderr);
}
#endif
					if ( xc > 0 && yc > 0 && press_event_ok == 0)  {
						msgbuf.ca_mbuf.op=MSG_PRESS;
						msgbuf.mtype = MSG_TYPE;
						memset(msgbuf.ca_mbuf.body.data, 0x00, 64);
						sprintf(msgbuf.ca_mbuf.body.point.sx, "%d", xc);
						sprintf(msgbuf.ca_mbuf.body.point.sy, "%d", yc);
						sprintf(msgbuf.ca_mbuf.body.point.sz, "%d", 0);
						if (msgsnd(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
							perror("msgsnd PRESS");
							fprintf(stderr, "Can't send PRESS message. Abort.\n");
							exit(1);
						}
					goto finish;
					}
//					goto finish;
					}
               		}
               	}
			wait_flag=True;
			alarm(timeout);
               }
	}
      	}
// We will be here on timeout ...
	alarm(0);
	msgbuf.ca_mbuf.op=MSG_TIMEOUT;
	msgbuf.mtype = MSG_TYPE;
	if (msgsnd(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
		perror("msgsnd TIMEOUT");
		fprintf(stderr, "Can't send TIMEOUT message. Abort.\n"); fflush(stderr);
		exit(1);
	}
finish:
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "eloUSBRead(): done ..\n", res);
	fflush(stderr);
}
#endif
	return 0;
}


/*
 ***************************************************************************
 *
 * xf86EloInputReadInput --
 *	Read all pending input events from the touchscreen and enqueue
 *	them.
 *
 ***************************************************************************
 */
#define EV_SYN 0x00

static void
xf86EloInputReadInput(unsigned char *buf, int *x, int *y, int *z)
{
  int   status = ELO_USB_STREAM;
  struct input_event            *ievent;
  
  ievent = (struct input_event  *)buf; 
  *x =-1; *y = -1;
/*  
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "event: type 0x%04x, code 0x%04x, value 0x%08x\n", ievent->type, ievent->code, ievent->value);
	fflush(stderr);
}
#endif
*/  
    switch(ievent->type) {
	case EV_ABS:
	  switch(ievent->code) {
	      case ABS_Y:
		*x=ievent->value;
		break;
		
	      case ABS_Z:
		*y=ievent->value;
		break;
		
	      case 11:
		*z=ievent->value;
		if((touched==0) && (*z >0)) {  /* Touch */
		  touched=1;
//		  fprintf(stderr, "TouchPress X: %d  Y: %d\n", 	*x, *y);
		  status = ELO_USB_PRESS;
		}
		else {
		  if((touched==1) && (*z ==0)) {  /* Release */
		    touched=0;
//		    fprintf(stderr, "TouchRelease X: %d  Y: %d\n", *x, *y);
		    status = ELO_USB_RELEASE;
		  }
		}
		break;
	  }
#if DEBUG_OUT == 1
if (debug_flag) {
	switch(ievent->code) {
	      case ABS_Y:
		if (*x < (-5120) || *x > 5120) 
			fprintf(stderr, "abs(x) too big: event: type 0x%04x, code 0x%04x, value 0x%08x\n", ievent->type, ievent->code, ievent->value);
		fprintf(stderr, "x = %d\n", *x);
		fflush(stderr);
		break;
		
	      case ABS_Z:
		if( *y < (-5120) || *y >5120)
			fprintf(stderr, "abs(y) too big: event: type 0x%04x, code 0x%04x, value 0x%08x\n", ievent->type, ievent->code, ievent->value);
		fprintf(stderr, "y = %d\n", *y);
		fflush(stderr);
		break;
		}
}
#endif
	  break;
	  
	case EV_SYN:
//	  fprintf(stderr, "Received SYN event type -  CODE: %d.\n", ievent->code);
	  break;
	  
	case EV_KEY:
//	  fprintf(stderr, "Received KEY event type -  CODE: %d.\n", ievent->code);
	  break;
	  
	default:
	  fprintf(stderr, "Unrecognized input event type %d.\n",ievent->type);
	break;
    }
   *z=status;
}

/*
 ***************************************************************************
 *
 * Serial Driver
 *	
 *
 ***************************************************************************
 */

static long get_BAUD(int Baud_Rate) {                      // derived baud rate from selected line
      long BAUD = (-1L);
      switch (Baud_Rate)
      {
         case 38400:
         default:
            BAUD = B38400;
            break;
         case 19200:
            BAUD  = B19200;
            break;
         case 9600:
            BAUD  = B9600;
            break;
         case 4800:
            BAUD  = B4800;
            break;
         case 2400:
            BAUD  = B2400;
            break;
         case 1800:
            BAUD  = B1800;
            break;
         case 1200:
            BAUD  = B1200;
            break;
         case 600:
            BAUD  = B600;
            break;
         case 300:
            BAUD  = B300;
            break;
         case 200:
            BAUD  = B200;
            break;
         case 150:
            BAUD  = B150;
            break;
         case 134:
            BAUD  = B134;
            break;
         case 110:
            BAUD  = B110;
            break;
         case 75:
            BAUD  = B75;
            break;
         case 50:
            BAUD  = B50;
            break;
      }  //end of switch baud_rate
      return BAUD;		  
}

static long get_DATABITS(int Data_Bits)
{
	long DATABITS = (-1L);
	
      switch (Data_Bits)
      {
         case 8:
         default:
            DATABITS = CS8;
            break;
         case 7:
            DATABITS = CS7;
            break;
         case 6:
            DATABITS = CS6;
            break;
         case 5:
            DATABITS = CS5;
            break;
      }  //end of switch data_bits
      return DATABITS;
}

static long get_STOPBITS(int Stop_Bits)
{
	long STOPBITS = (-1L);
      switch (Stop_Bits)
      {
         case 1:
         default:
            STOPBITS = 0;
            break;
         case 2:
            STOPBITS = CSTOPB;
            break;
      }  //end of switch stop bits
      return STOPBITS;
}

static long get_PARITY(char Parity, long *PARITYON)
{  
	long PARITY =(-1L);
      switch (Parity)
      {
         case 'N':
         default:                       //none
            *PARITYON = 0;
            PARITY = 0;
            break;
         case 'O':                        //odd
            *PARITYON = PARENB;
            PARITY = PARODD;
            break;
         case 'E':                        //even
            *PARITYON = PARENB;
            PARITY = 0;
            break;
      }  //end of switch parity
	return PARITY;
}

int eloSerialDriverOpen(char *devname, char *speed, char *parms) {
	int baud, data, stopb, rc; 
	long BAUD;                      // derived baud rate from command line
	long DATABITS;
	long STOPBITS;
	long PARITYON;
	long PARITY;
	char par;


#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "eloSerialDriverOpen() %s %s %s\n", devname, speed, parms);
	fflush(stderr);
}
#endif
	if (!isdigit(*speed)) speed++;
	sscanf(speed, "%d", &baud);

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "got baud %d\n", baud);
	fflush(stderr);
}
#endif
	BAUD = get_BAUD(baud);

	rc = sscanf(parms, "%d%c%d", &data, &par, &stopb);
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "rc=%d, data=%d, par=%c, stopb=%d\n", rc, data, par, stopb);
	fflush(stderr);
}
#endif
	DATABITS = get_DATABITS(data);
	STOPBITS = get_STOPBITS(stopb);
	PARITY     = get_PARITY(par, &PARITYON);

	if (DATABITS == (-1L) || 
	     STOPBITS == (-1L) ||
	     PARITY     == (-1L) ||
	     BAUD       == (-1L)) {
	  fprintf(stderr, "Uncorrect parameters for Serial driver. Abort.\n");
	  return 0;
	}
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "BAUD=0x%08x, DATABITS=0x%08x, STOPBITS=0x%08x, PARITY=0x%08x, PARITYON=0x%08x\n",
	BAUD, DATABITS, STOPBITS, PARITY, PARITYON);
	fflush(stderr);
}
#endif
      //open the device(com port) to be non-blocking (read will return immediately)
      fd = open(devname, O_RDWR | O_NOCTTY | O_NONBLOCK);
      if (fd < 0)
      {
         perror(devname);
	  fprintf(stderr, "Can't open `%s'. Abort.\n", devname);			 
         return 0;
      }

	wait_flag = True; 
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "OpenSerial: fd=%d/%d\n", fd, wait_flag);	 fflush(stderr);	
}
#endif

      //install the serial handler before making the device asynchronous
      saio.sa_handler = signal_handler_IO;
      sigemptyset(&saio.sa_mask);   //saio.sa_mask = 0;
      saio.sa_flags = 0;
      saio.sa_restorer = NULL;
      sigaction(SIGIO,&saio,NULL);
      sigaction(SIGALRM,&saio,NULL);

      // allow the process to receive SIGIO
      fcntl(fd, F_SETOWN, getpid());
      // Make the file descriptor asynchronous (the manual page says only
      // O_APPEND and O_NONBLOCK, will work with F_SETFL...)
      fcntl(fd, F_SETFL, FASYNC);

      tcgetattr(fd,&oldtio); // save current port settings 
      // set new port settings for canonical input processing 
      newtio.c_cflag = BAUD | CRTSCTS | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD;
      newtio.c_iflag = IGNPAR;
      newtio.c_oflag = 0;
      newtio.c_lflag = 0;       //ICANON;
      newtio.c_cc[VMIN]=1;
      newtio.c_cc[VTIME]=0;
      tcflush(fd, TCIFLUSH);
      tcsetattr(fd,TCSANOW,&newtio);

#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "OpenSerial: wait_flag=%d\n", wait_flag);	 fflush(stderr);	
}
#endif

      serial_res = 0;
      return 1;

}


void eloSerialDriverClose(void) {
      // restore old port settings
      tcsetattr(fd,TCSANOW,&oldtio);
      close(fd);        //close the com port
}


int eloSerialRead(void) {
	int idx_elo, rc;
	ca_msgbuf_t  msgbuf;
	char elobuf[ELO_PACKET_SIZE];
	 int	reply_p = 0;
	 int	sum = ELO_INIT_CHECKSUM;
	 int	i_state = 0;
	 int x; /* output */
	 int y; /* output */
	 unsigned short sx, sy;

	idx_elo = 0;      // elo_buffer is empty
	STOP=False;
	alarm(timeout);

	while(STOP==False) {
		if (idx_elo == ELO_PACKET_SIZE) {  // elo_buffer full, let see what we have ...
			 reply_p = 0;
 			 sum = ELO_INIT_CHECKSUM;
			 i_state = 0;
			 idx_elo = 0;
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "-- ELO Packet -- "); fflush(stderr);
	hexdump((unsigned long)elobuf, 10);
}
#endif
			 if ((rc = xf86EloGetPacket(elobuf, &reply_p, &sum)) == 1) {
			 	// ELO packet is OK
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "Packet OK.\n"); fflush(stderr);
}
#endif
					    /*     * Process only ELO_TOUCHs here.   */
				 if (elobuf[1] == ELO_TOUCH) {
  					  /*
     					    * First stick together the various pieces.
     				           */
//    					sx = (unsigned short)((elobuf[3]<<8)&0xff00) | (unsigned short)(elobuf[4]&0xff);
//    					sy = (unsigned short)((elobuf[5] <<8)&0xff00) | (unsigned short)(elobuf[6]&0xff);
    					sx = (unsigned short)((elobuf[4]<<8)&0xff00) | (unsigned short)(elobuf[3]&0xff);
    					sy = (unsigned short)((elobuf[6] <<8)&0xff00) | (unsigned short)(elobuf[5]&0xff);
					x = sx; y = sy;	
    					i_state = elobuf[2] & 0x07;
					 /*
					   * Don't drop button events.
     					   */    
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "-- x(%d)(0x%04x)--y(%d)(0x%04x)---state(0x%02x)\n", x,sx, y,sy, i_state);
}
#endif
    					if (i_state == ELO_PRESS || i_state == ELO_RELEASE) {
							x_min = (x < x_min)? x: x_min;
							x_max =(x > x_max)? x : x_max;
							y_min = (y < y_min)? y : y_min;
							y_max =(y > y_max)? y : y_max;
							if (i_state == ELO_PRESS)  {
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "eloSerialRead(): got ELO_USB_PRESS, send a message..\n");
	fflush(stderr);
}
#endif
							msgbuf.ca_mbuf.op=MSG_PRESS;
							msgbuf.mtype = MSG_TYPE;
							memset(msgbuf.ca_mbuf.body.data, 0x00, 64);
							sprintf(msgbuf.ca_mbuf.body.point.sx, "%d", x);
							sprintf(msgbuf.ca_mbuf.body.point.sy, "%d", y);
							if (msgsnd(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
								perror("msgsnd PRESS");
								fprintf(stderr, "Can't send PRESS message. Abort.\n");
								exit(1);
								}
							return 1;
							} // if (i_state == ELO_PRESS) 
							if (i_state == ELO_RELEASE) {
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "eloSerialRead(): got ELO_USB_RELEASE, turn on skip bytes flag ...\n");
	fflush(stderr);
}
#endif
							; // skip it ...	
							}
    					}
				 }else{ //if (elobuf[1] == ELO_ ...
				 	;  // skip it ...
#if DEBUG_OUT == 1
if (debug_flag) {
					fprintf(stderr, "eloSerialRead(): its not a ELO_TOUCH packet.\n");
}
#endif
				 }
			 }else{ // if ((rc = xf86EloGetPacket( ... 
			 	;  // ?? packet is not OK, just skip it  ....
			 }			 
		}else{  // if (idx_elo == ...
			if ( serial_res == 0) { //serial buffer is empty, we need read from the serial port
         			if (wait_flag==False) {  //if input is available
         				alarm(0);
         				serial_res = read(fd, serial_buf, 255);
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "serial_res=%d\n", serial_res);	 fflush(stderr);	
	hexdump((unsigned long)serial_buf, serial_res);
}
#endif
					serial_idx = 0;
         			}
			}else{ // if ( serial_res == 0)
				if (serial_idx < serial_res) {
/*
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "serial_buf[%d]=0x%02x --> elobuf[%d]\n", serial_idx, serial_buf[serial_idx], idx_elo);	 fflush(stderr);	
}
#endif
*/
					elobuf[ idx_elo] = serial_buf[ serial_idx];
					idx_elo++;
					serial_idx++;
				}else{ //if (serial_idx < serial_res)
					serial_res = 0;    // serial buffer emtpy, 
					alarm(timeout);
					wait_flag = True;
				}
			}
		}
	}
#if DEBUG_OUT == 1
if (debug_flag) {
	fprintf(stderr, "Exit from read cycle ...timeout probably ...\n");	 fflush(stderr);	
}
#endif
	alarm(0);
	msgbuf.ca_mbuf.op=MSG_TIMEOUT;
	msgbuf.mtype = MSG_TYPE;
	if (msgsnd(msg_upstream_id, (struct msgbuf *)&msgbuf, sizeof(ca_message_t), 0) == (-1)) {
		perror("msgsnd TIMEOUT");
		fprintf(stderr, "Can't send TIMEOUT message. Abort.\n"); fflush(stderr);
		exit(1);
	}
	return 0;  
}

void printMSGstreamError(void)
{
		fprintf(stderr, "Can't delete the MSG stream! You probably need to reboot Linux ...\n");
}
void printCalibrationError(void)
{
	fprintf(stderr, "An error was encountered during calibration.  Please calibrate again\n");
}

/***************************************************************************
   Elo Test Area ..
   Functions imported from the XFree86 driver (4.5.0)
***************************************************************************/

static int
xf86EloGetPacket(unsigned char	*buffer,
		 int		*buffer_p,
		 int		*checksum)
{
  int	num_bytes = 10;
  int ok;


#if DEBUG_OUT >1 
if (debug_flag) {
	fprintf(stderr, "xf86EloGetPacket(): checksum: 0x%X\n", *checksum);
}
#endif
  
  while (num_bytes) {
    /*
     * Sync with the start of a packet.
     */
    if ((*buffer_p == 0) && (buffer[0] != ELO_SYNC_BYTE)) {
      /*
       * No match, shift data one byte toward the start of the buffer.
       */
      fprintf(stderr, "%s: Dropping one byte in an attempt to synchronize: '%c' 0x%X\n", __FUNCTION__, buffer[0], buffer[0]);
      memcpy(&buffer[0], &buffer[1], num_bytes-1);
    }
    else {
      /*
       * Compute checksum in assembly buffer.
       */
      if (*buffer_p < ELO_PACKET_SIZE-1) {
	*checksum = *checksum + buffer[*buffer_p];
	*checksum = *checksum % 256;
#if DEBUG_OUT > 1
if (debug_flag) {
	fprintf(stderr, " [%d]: 0x%X-->0x%X ",*buffer_p, buffer[*buffer_p], *checksum);
}
#endif
      }
      (*buffer_p)++;
    }
    num_bytes--;
  }

  if (*buffer_p == ELO_PACKET_SIZE) {
    /*
     * Got a packet, validate checksum and reset state.
     */
    ok = (*checksum == buffer[ELO_PACKET_SIZE-1]);
#if DEBUG_OUT > 1
if (debug_flag) {
	fprintf(stderr, "Expecting checksum %d, got %d\n", *checksum, buffer[ELO_PACKET_SIZE-1]);
}
#endif
    *checksum = ELO_INIT_CHECKSUM;
    *buffer_p = 0;

    if (!ok) {
      fprintf(stderr, "Checksum error on Elographics touchscreen link\n");
      return 2;
    }
    
    /*
     * Valid packet received report it.
     */
    return 1;
  }
  else {
    fprintf(stderr, "Wrong packet length ...\n");	
    return 0;
  }
}


#if DEBUG_OUT == 1
/*
 * hexdump() for print a memory areas
 */

static char *hex2char(char *start, char *wb2)
{
    int index, i;
    for (index=0; index < 16; index++) {
		if ( *(start + index ) >= 0x20 && *(start + index ) <= 0x7e )
		    wb2[ index ] = *(start + index );
		else
		    wb2[ index ] = '.';
    }
    wb2[ 16] = 0x00;
    return wb2;
}

void hexdump(unsigned long start, int size)
{
    int count = start&0x0fff;
    int lines, index;
    int skip0 = 0;
    char wb[17];

    lines = (size >> 4) + 1;

    fprintf(stderr, "\n*********** Dump from 0x%08lx (%d bytes) ********\n", start, size);

    for( index =0, start&=0xfffffff0; index < lines; index++) {


	if ( *(unsigned long *)start == 0 &&
             *(unsigned long *)(start + 4) == 0 &&
                 *(unsigned long *)(start + 8) == 0 &&
                     *(unsigned long *)(start + 12) == 0
	)
	    skip0++;
	else
	    skip0 = 0;

	if ( skip0 == 0 ) {
/*
	sprintf(hwb,
	"%08x   %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x   [%s]\n",
*/
    fprintf(stderr, 
    "%08lx   %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x   [%s]\n",
     start,  *(unsigned char *)start,
                 *(unsigned char *)(start +1),
                     *(unsigned char *)(start +2),
                         *(unsigned char *)(start +3),
                              *(unsigned char *)(start + 4),
                                  *(unsigned char *)(start + 5),
                                      *(unsigned char *)(start + 6),
                                          *(unsigned char *)(start + 7),
                                               *(unsigned char *)(start + 8),
                                                   *(unsigned char *)(start + 9),
                                                       *(unsigned char *)(start + 10),
                                                           *(unsigned char *)(start + 11),
                                                                *(unsigned char *)(start + 12),
                                                                    *(unsigned char *)(start + 13),
                                                                        *(unsigned char *)(start + 14),
                                                                            *(unsigned char *)(start + 15),
                          hex2char((char *)start, wb)
	);
/*	outCons(hwb); */
/*    printf("%s", hwb);  */
	}else
	if ( skip0 == 1)
        fprintf(stderr, "       ******** null line(s) skipped *********\n");
	start += 16;
    }
}
#endif

