/*
 * Yoshifumi R. Shimizu
 *
 * ver.1.00, 1999.02.01-04
 *     Using only Xlib
 *
 * ver.1.01, 1999.02.06
 *     Using X Toolkit
 *
 * ver.1.02, 1999.02.09
 *     Using application resources and option tables
 *
 * ver.1.03, 1999.02.20-23
 *     Adding temp3, and increasing resouces / option tables
 *     -DNO_TEMP3 compiling option for not showing temp3
 *
 * ver.1.04, 1999.05.04
 *     Slight improvement for getting resources
 *
 * ver.1.05, 1999.11.13
 *     Support SMBus access method.  Debugging infomation.
 *
 * xmbmon  --- X mother board monitor for WinBond W83781D Chip
 *              (and for National Semiconductor LM78/LM79/LM75 Chips)
 *
 * compile:
 *   gcc -s -o xmbmon xmbmon.c -I/usr/X11R6/include \
 *             -L/usr/X11R6/lib -lXaw -lXmu -lXt -lXext -lX11
 *
 * Information related to WinBond W83781D LM78/LM79 Chips by Alex van Kaam
 *
 *  http://members.brabant.chello.nl/~a.vankaam/mbm/
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <signal.h>

/* debug flag used in InitMBInfo() */
int debug_flag = 0;

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>

#ifdef HAVE_SMBUS
#define DEFAULT_METHOD	'S'
#else
#define DEFAULT_METHOD	'I'
#endif

#define RES_NAME   "XMBmon"

#define DEFAULT_GEOMETRY  "100x140"
#define DEFAULT_FONT      "-adobe-helvetica-bold-r-*-*-10-*-*-*-*-*-*-*"

#define DEFAULT_COUNT        "4"
#define DEFAULT_SEC         "20"
#define DEFAULT_WSEC      "1800"
#define DEFAULT_TMIN      "10.0"
#define DEFAULT_TMAX      "50.0"
#define DEFAULT_VMIN      "1.80"
#define DEFAULT_VMAX      "2.20"
#define DEFAULT_TICK         "3"

#define DEFAULT_CLTMB     "blue"
#define DEFAULT_CLTCPU     "red"
# ifdef NO_TEMP3
#define DEFAULT_CLVC     "green"
# else
#define DEFAULT_CLTCS    "green"
#define DEFAULT_CLVC      "cyan"
# endif

#define DEFAULT_CMTMB   "\\ MB"
#define DEFAULT_CMTMB1    " MB"
#define DEFAULT_CMTCPU    "CPU"
#define DEFAULT_CMTCS    "chip"
#define DEFAULT_CMVC    "Vc\\ "
#define DEFAULT_CMVC1     "Vc "

/* temp1(MotherBoard), temp2(CPU) [,temp3(ChipSet)] and Vcore0 */
# ifdef NO_TEMP3
#define NUM_DATA 3
# else
#define NUM_DATA 4
# endif

/* global variables */

char *font;

int width, height;

float tmin, tmax, vmin, vmax;
int n_tick;
float tscl, vscl, sscl, htck; 
float scale[NUM_DATA];
float orign[NUM_DATA];
float cur_val[NUM_DATA];

int n_count, interval_sec, w_sec;
int counter = 0;
int w_counter = 0;
int w_range;

int t_sec, t_usec;
struct itimerval itv;

typedef struct ring_data {
	float val;
	struct ring_data *next;
} ring_d;

ring_d *rdp[NUM_DATA];
ring_d *rdpw[NUM_DATA];

float *fmean;

char *l_color[NUM_DATA];
unsigned long cpix[NUM_DATA], d_cpix[NUM_DATA];

#define C_LBL 10
char ctmin[C_LBL], ctmax[C_LBL];
char cvmin[C_LBL], cvmax[C_LBL];
char *c_rdv[NUM_DATA], *c_rdg[NUM_DATA];
# ifdef NO_TEMP3
char *c_rdp[NUM_DATA] = {"%.1f", "%.1f", "%.2f"};
# else
char *c_rdp[NUM_DATA] = {"%.1f", "%.1f", "%.1f", "%.2f"};
# endif
int x_rdg[NUM_DATA], x_rdv[NUM_DATA], y_rdg, y_rdv;
int cg_width[NUM_DATA], cv_width[NUM_DATA], cg_w, cv_w;
int c_height, cm_width, cm_height;
char access_method = DEFAULT_METHOD;

/* variables for X11 */

Widget wgt;
Display	*disp;
Window win;
GC gct, gcl[NUM_DATA];
XPoint *points;
XFontStruct *fontstr;

/* functions */

void get_args(int argc, char *argv[]);
void usage(void);
void get_res(void);
void init_dt(void);
void getWH(int *width, int *height);
void repaint_proc(void);
void quit_proc(void);
void draw_values(void);
#ifdef LINUX
typedef void sig_t ;
#endif
sig_t alarm_handler(int);
int ColorPix(Display *, char *, unsigned long *);

/*---------- definitions of static data for X Toolkits ----------*/

	static String fallback_resources[] = {
		"*translations: #override \
			<Configure>: repaint_proc()\\n\
			<Expose>: repaint_proc()\\n\
			<BtnUp>: repaint_proc()\\n\
			<Key>Q: quit_proc()",
		"*geometry: " DEFAULT_GEOMETRY,
		"*font: "     DEFAULT_FONT,
		"*count: "    DEFAULT_COUNT,
		"*sec: "      DEFAULT_SEC,
		"*wsec: "     DEFAULT_WSEC,
		"*tmin: "     DEFAULT_TMIN,
		"*tmax: "     DEFAULT_TMAX,
		"*vmin: "     DEFAULT_VMIN,
		"*vmax: "     DEFAULT_VMAX,
		"*tick: "     DEFAULT_TICK,
		"*cltmb: "    DEFAULT_CLTMB,
		"*cltcpu: "   DEFAULT_CLTCPU,
# ifdef NO_TEMP3
# else
		"*cltcs: "    DEFAULT_CLTCS,
# endif
		"*clvc: "     DEFAULT_CLVC,
		"*cmtmb: "    DEFAULT_CMTMB,
		"*cmtcpu: "   DEFAULT_CMTCPU,
# ifdef NO_TEMP3
# else
		"*cmtcs: "    DEFAULT_CMTCS,
# endif
		"*cmvc: "     DEFAULT_CMVC,
		NULL,
	};
	static XtActionsRec actions[] = {
		{"repaint_proc", (XtActionProc) repaint_proc},
		{"quit_proc", (XtActionProc) quit_proc},
	};
	static struct _app_res {
		char *font;
		int count;
		int sec;
		int wsec;
		float tmin;
		float tmax;
		float vmin;
		float vmax;
		int tick;
		char *cltmb;
		char *cltcpu;
# ifdef NO_TEMP3
# else
		char *cltcs;
# endif
		char *clvc;
		char *cmtmb;
		char *cmtcpu;
# ifdef NO_TEMP3
# else
		char *cmtcs;
# endif
		char *cmvc;
		char *method;
	} app_resources;
	static XtResource resources[] = {
		{"font", "Font", XtRString, sizeof(String),
			XtOffset(struct _app_res*, font),
			XtRString, (XtPointer) NULL},
		{"count", "Count", XtRInt, sizeof(int),
			XtOffset(struct _app_res*, count),
			XtRImmediate, (XtPointer) NULL},
		{"sec", "Sec", XtRInt, sizeof(int),
			XtOffset(struct _app_res*, sec),
			XtRImmediate, (XtPointer) NULL},
		{"wsec", "wSec", XtRInt, sizeof(int),
			XtOffset(struct _app_res*, wsec),
			XtRImmediate, (XtPointer) NULL},
		{"tmin", "Tmin", XtRFloat, sizeof(float),
			XtOffset(struct _app_res*, tmin),
			XtRImmediate, (XtPointer) NULL},
		{"tmax", "Tmax", XtRFloat, sizeof(float),
			XtOffset(struct _app_res*, tmax),
			XtRImmediate, (XtPointer) NULL},
		{"vmin", "Vmin", XtRFloat, sizeof(float),
			XtOffset(struct _app_res*, vmin),
			XtRImmediate, (XtPointer) NULL},
		{"vmax", "Vmax", XtRFloat, sizeof(float),
			XtOffset(struct _app_res*, vmax),
			XtRImmediate, (XtPointer) NULL},
		{"tick", "Tick", XtRInt, sizeof(int),
			XtOffset(struct _app_res*, tick),
			XtRImmediate, (XtPointer) NULL},
		{"cltmb", "ClTmb", XtRString, sizeof(String),
			XtOffset(struct _app_res*, cltmb),
			XtRString, (XtPointer) NULL},
		{"cltcpu", "ClTcpu", XtRString, sizeof(String),
			XtOffset(struct _app_res*, cltcpu),
			XtRString, (XtPointer) NULL},
# ifdef NO_TEMP3
# else
		{"cltcs", "ClTcs", XtRString, sizeof(String),
			XtOffset(struct _app_res*, cltcs),
			XtRString, (XtPointer) NULL},
# endif
		{"clvc", "ClVc", XtRString, sizeof(String),
			XtOffset(struct _app_res*, clvc),
			XtRString, (XtPointer) NULL},
		{"cmtmb", "CMTmb", XtRString, sizeof(String),
			XtOffset(struct _app_res*, cmtmb),
			XtRString, (XtPointer) NULL},
		{"cmtcpu", "CMTcpu", XtRString, sizeof(String),
			XtOffset(struct _app_res*, cmtcpu),
			XtRString, (XtPointer) NULL},
# ifdef NO_TEMP3
# else
		{"cmtcs", "CMTcs", XtRString, sizeof(String),
			XtOffset(struct _app_res*, cmtcs),
			XtRString, (XtPointer) NULL},
# endif
		{"cmvc", "CMVc", XtRString, sizeof(String),
			XtOffset(struct _app_res*, cmvc),
			XtRString, (XtPointer) NULL},
		{"method","Method",XtRString,sizeof(String),
		        XtOffset(struct _app_res*,method),
		         XtRString,(XtPointer) NULL},
	};
	static XrmOptionDescRec options[] = {
		{"-font", ".font", XrmoptionSepArg, NULL},
		{"-count", ".count", XrmoptionSepArg, NULL},
		{"-sec", ".sec", XrmoptionSepArg, NULL},
		{"-wsec", ".wsec", XrmoptionSepArg, NULL},
		{"-tmin", ".tmin", XrmoptionSepArg, NULL},
		{"-tmax", ".tmax", XrmoptionSepArg, NULL},
		{"-vmin", ".vmin", XrmoptionSepArg, NULL},
		{"-vmax", ".vmax", XrmoptionSepArg, NULL},
		{"-tick", ".tick", XrmoptionSepArg, NULL},
		{"-cltmb", ".cltmb", XrmoptionSepArg, NULL},
		{"-cltcpu", ".cltcpu", XrmoptionSepArg, NULL},
# ifdef NO_TEMP3
# else
		{"-cltcs", ".cltcs", XrmoptionSepArg, NULL},
# endif
		{"-clvc", ".clvc", XrmoptionSepArg, NULL},
		{"-cmtmb", ".cmtmb", XrmoptionSepArg, NULL},
		{"-cmtcpu", ".cmtcpu", XrmoptionSepArg, NULL},
# ifdef NO_TEMP3
# else
		{"-cmtcs", ".cmtcs", XrmoptionSepArg, NULL},
# endif
		{"-cmvc", ".cmvc", XrmoptionSepArg, NULL},
		{"-method",".method",XrmoptionSepArg,NULL},
	};

/*---------- end of static data for X Toolkits ----------*/

void get_args(int argc, char *argv[])
{
	int	i, j;
	double d;

	for (i = 1; i < argc; i++){
		if (0 == strcmp("-d", argv[i]) || 0 == strcmp("-debug", argv[i])){
			debug_flag = 1;
		}
		if (0 == strcmp("-h", argv[i]) || 0 == strcmp("-help", argv[i])){
			usage();
		}
	}
}

void usage(void)
{
	fprintf(stderr, \
"X MotherBoard Monitor, ver.1.03 by YRS\n"
"  options: -g   (" DEFAULT_GEOMETRY ")  <geometry(Toolkit option)>\n"
"         : -count     (" DEFAULT_COUNT ")  <counts in an interval>\n"
"         : -sec      (" DEFAULT_SEC ")  <seconds of an interval>\n"
"         : -wsec   (" DEFAULT_WSEC ")  <total seconds shown>\n"
"         : -tmin   (" DEFAULT_TMIN ")  <min. temperature>\n"
"         : -tmax   (" DEFAULT_TMAX ")  <max. temperature>\n"
"         : -vmin   (" DEFAULT_VMIN ")  <min. voltage>\n"
"         : -vmax   (" DEFAULT_VMAX ")  <max. voltage>\n"
"         : -tick      (" DEFAULT_TICK ")  <ticks in ordinate>\n"
"         : -cltmb  (" DEFAULT_CLTMB ")  <Temp1 color>\n"
"         : -cltcpu  (" DEFAULT_CLTCPU ")  <Temp2 color>\n"
# ifdef NO_TEMP3
"         : -clvc  (" DEFAULT_CLVC ")  <Vcore color>\n"
# else
"         : -cltcs (" DEFAULT_CLTCS ")  <Temp3 color>\n"
"         : -clvc   (" DEFAULT_CLVC ")  <Vcore color>\n"
# endif
"         : -cmtmb   (" DEFAULT_CMTMB1 ")  <comment of Temp1>\n"
"         : -cmtcpu  (" DEFAULT_CMTCPU ")  <comment of Temp2>\n"
# ifdef NO_TEMP3
# else
"         : -cmtcs  (" DEFAULT_CMTCS ")  <comment of Temp3>\n"
# endif
"         : -cmvc    (" DEFAULT_CMVC1 ")  <comment of Vcore>\n"
"         : -debug           for debug information\n"
"         : -method  ( %c )  <access method (S or I)>\n", DEFAULT_METHOD
);
	exit(1);
}
	
int main(int argc, char *argv[])
{

	XtAppContext app_con;

	get_args(argc, argv);

	wgt = XtVaAppInitialize(&app_con, RES_NAME,
			options, XtNumber(options),
			&argc, argv, fallback_resources, NULL);
	XtVaGetApplicationResources(wgt, (caddr_t) &app_resources,
			resources, XtNumber(resources), NULL);
	XtAppAddActions(app_con, actions, XtNumber(actions));
	XtRealizeWidget(wgt);

	get_res();
	init_dt();

	XtAppMainLoop(app_con);
}

void get_res()
{
	font = app_resources.font;
	if(font == NULL)
		font = DEFAULT_FONT;
	n_count = app_resources.count;
	if(n_count <= 0)
		n_count = atoi(DEFAULT_COUNT);
	interval_sec = app_resources.sec;
	if(interval_sec <= 0)
		interval_sec = atoi(DEFAULT_SEC);
	w_sec = app_resources.wsec;
	if(w_sec <= 0)
		w_sec = atoi(DEFAULT_WSEC);
	tmin = app_resources.tmin;
	if(tmin <= 0.0)
		tmin = (float) atof(DEFAULT_TMIN);
	tmax = app_resources.tmax;
	if(tmax <= 0.0)
		tmax = (float) atof(DEFAULT_TMAX);
	vmin = app_resources.vmin;
	if(vmin <= 0.0)
		vmin = (float) atof(DEFAULT_VMIN);
	vmax = app_resources.vmax;
	if(vmax <= 0.0)
		vmax = (float) atof(DEFAULT_VMAX);
	n_tick = app_resources.tick;
	if(n_tick <= 0)
		n_tick = atoi(DEFAULT_TICK);
	l_color[0] = app_resources.cltmb;
	if(l_color[0] == NULL)
		l_color[0] = DEFAULT_CLTMB;
	l_color[1] = app_resources.cltcpu;
	if(l_color[1] == NULL)
		l_color[1] = DEFAULT_CLTCPU;
# ifdef NO_TEMP3
	l_color[2] = app_resources.clvc;
	if(l_color[2] == NULL)
		l_color[2] = DEFAULT_CLVC;
# else
	l_color[2] = app_resources.cltcs;
	if(l_color[2] == NULL)
		l_color[2] = DEFAULT_CLTCS;
	l_color[3] = app_resources.clvc;
	if(l_color[3] == NULL)
		l_color[3] = DEFAULT_CLVC;
# endif
	c_rdg[0] = app_resources.cmtmb;
	if(c_rdg[0] == NULL)
		c_rdg[0] = DEFAULT_CMTMB1;
	c_rdg[1] = app_resources.cmtcpu;
	if(c_rdg[1] == NULL)
		c_rdg[1] = DEFAULT_CMTCPU;
# ifdef NO_TEMP3
	c_rdg[2] = app_resources.cmvc;
	if(c_rdg[2] == NULL)
		c_rdg[2] = DEFAULT_CMVC1;
# else
	c_rdg[2] = app_resources.cmtcs;
	if(c_rdg[2] == NULL)
		c_rdg[2] = DEFAULT_CMTCS;
	c_rdg[3] = app_resources.cmvc;
	if(c_rdg[3] == NULL)
		c_rdg[3] = DEFAULT_CMVC1;
# endif
	if(app_resources.method!=NULL){
	  access_method=app_resources.method[0];
	}
}

void quit_proc(void)
{
	exit(1);
}

void repaint_proc(void)
{
	int wwd, hht;
	int i, n, ww = width -1, hh = height - 1;
	ring_d *p;
	static memo = 0;

	for (i = 0; i < NUM_DATA; i++) {
		sprintf(c_rdv[i], c_rdp[i], cur_val[i]);
		cv_width[i] = XTextWidth(fontstr, c_rdv[i], strlen(c_rdv[i]));
	}

	getWH(&wwd, &hht);
	if (wwd != width) {
		width = wwd;
		ww = width - 1;
		sscl = (float) width / (float) w_range;
# ifdef NO_TEMP3
		x_rdg[1] = (width - cg_width[1]) / 2;
		x_rdg[2] = width - cg_width[2] - 1;
# else
		x_rdg[1] = cg_width[0] / 2 + (width - cg_w) / 3 - cg_width[1] / 2;
		x_rdg[2] = cg_width[0] / 2 + (width - cg_w) * 2 / 3 - cg_width[2] / 2;
		x_rdg[3] = width - cg_width[3] - 1;
# endif
	}
# ifdef NO_TEMP3
	x_rdv[1] = (width - cv_width[1]) / 2;
	x_rdv[2] = width - cv_width[2] - 1;
# else
	x_rdv[1] = cv_width[0] / 2 + (width - cv_w) / 3 - cv_width[1] / 2;
	x_rdv[2] = cv_width[0] / 2 + (width - cv_w) * 2 / 3 - cv_width[2] / 2;
	x_rdv[3] = width - cv_width[3] - 1;
# endif
	if (hht != height) {
		height = hht;
		hh = height -1;
		tscl = (float) (height - c_height)/ (tmax - tmin);
		vscl = (float) (height - c_height)/ (vmax - vmin);
		htck = (float) (height - c_height)/ (float) (n_tick + 1);
		scale[0] = tscl;
		scale[1] = tscl;
# ifdef NO_TEMP3
		scale[2] = vscl;
# else
		scale[2] = tscl;
		scale[3] = vscl;
# endif
	}

	XClearWindow(disp, win);

	for (i = 0; i < NUM_DATA; i++) {
		XDrawString(disp, win, gcl[i], x_rdg[i], y_rdg, \
					c_rdg[i], strlen(c_rdg[i]));
		XDrawString(disp, win, gcl[i], x_rdv[i], y_rdv, \
					c_rdv[i], strlen(c_rdv[i]));
	}

	XDrawString(disp, win, gct, 0, hh+1, ctmin, strlen(ctmin));
	XDrawString(disp, win, gct, 0, cm_height, ctmax, strlen(ctmax));
	XDrawString(disp, win, gct, ww-cm_width, hh+1, cvmin, strlen(cvmin));
	XDrawString(disp, win, gct, ww-cm_width, cm_height, cvmax, strlen(cvmax));

	for (i = 0; i < n_tick + 1; i++) {
		n = hh - (int) ((float) (i + 1) * htck + 0.5);
		XDrawLine(disp, win, gct, 0, n, ww, n);
	}

	for (i = NUM_DATA - 1; i >= 0; i--) {
		for (n = 0, p = rdp[i]; n < w_counter; n++) {
			(points + n)->x = (short) ((float) n * sscl + 0.5);
			(points + n)->y = hh \
				- (short) ((p->val - orign[i]) * scale[i] + 0.5);
			p = p->next;
		}
		XDrawLines(disp, win, gcl[i], points, w_counter, CoordModeOrigin);
	}

	XFlush(disp);
}

void getWH(int *width, int *height)
{
	Dimension wd, ht;

	XtVaGetValues(wgt, XtNwidth, &wd, XtNheight, &ht, NULL);
	*width = (int) wd;
	*height = (int) ht;
}

int ColorPix(Display *display, char *color, unsigned long *cpix)
{
	Colormap cmap;
	XColor c0, c1;

	if (color == NULL)
		return (1);
	cmap = DefaultColormap(display, 0);
	if (XAllocNamedColor(disp, cmap, color, &c1, &c0)) {
		*cpix = c1.pixel;
		return (0);
	} else {
		return (1);
	}
}

void init_dt(void)
{
	extern sig_t alarm_handler();
	struct itimerval *itp = &itv;
	ring_d *p;
	int n, i;
	float d;
	
	if (w_sec < 10 * interval_sec) {
		fprintf(stderr,"wsec(%d) is too small w.r.t sec(%d) --- exit.\n",\
			w_sec, interval_sec);
		exit (1);
	}
	if (tmax < tmin) {
		fprintf(stderr,"tmin(%f) > tmax(%f), not allowed! --- exit.\n",\
			tmin, tmax);
		exit (1);
	}
	if (vmax < vmin) {
		fprintf(stderr,"vmin(%f) > vmax(%f), not allowed! --- exit.\n",\
			vmin, vmax);
		exit (1);
	}
	if (InitMBInfo(access_method)!=0){
		perror("InitMBInfo");
		fprintf(stderr," this program needs \"setuid root\" !!\n");
		exit (1);
	}
	if (debug_flag)
		exit (0);

# ifdef NO_TEMP3
	getTemp(&cur_val[0], &cur_val[1], &d) ;
	getVolt(&cur_val[2], &d, &d, &d, &d, &d, &d) ;
# else
	getTemp(&cur_val[0], &cur_val[1], &cur_val[2]);
	getVolt(&cur_val[3], &d, &d, &d, &d, &d, &d);
# endif

	
	disp = XtDisplay(wgt);
	win = XtWindow(wgt);
	getWH(&width, &height);

	if ((fontstr = XLoadQueryFont(disp, font)) == NULL) {
		fprintf(stderr,"Can't find font: %s\n", font);
		exit (1);
	}

	ColorPix(disp, DEFAULT_CLTMB, &(d_cpix[0]));
	ColorPix(disp, DEFAULT_CLTCPU, &(d_cpix[1]));
# ifdef NO_TEMP3
	ColorPix(disp, DEFAULT_CLVC, &(d_cpix[2]));
# else
	ColorPix(disp, DEFAULT_CLTCS, &(d_cpix[2]));
	ColorPix(disp, DEFAULT_CLVC, &(d_cpix[3]));
# endif
	gct = XCreateGC(disp, win, 0, 0);
	XSetFont(disp, gct, fontstr->fid);
	for (i = 0; i < NUM_DATA; i++) {
		if (ColorPix(disp, l_color[i], &(cpix[i])))
			cpix[i] = d_cpix[i];
		gcl[i] = XCreateGC(disp, win, 0, 0);
		XSetLineAttributes(disp, gcl[i], 2, LineSolid, CapRound, JoinRound);
		XSetForeground(disp, gcl[i], cpix[i]);
		XSetFont(disp, gcl[i], fontstr->fid);
		c_rdv[i] = (char *) malloc(C_LBL);
		sprintf(c_rdv[i], c_rdp[i], cur_val[i]);
		cg_width[i] = XTextWidth(fontstr, c_rdg[i], strlen(c_rdg[i]));
		cv_width[i] = XTextWidth(fontstr, c_rdv[i], strlen(c_rdv[i]));
	}

	sprintf(ctmin, "%2.f", tmin);
	sprintf(ctmax, "%2.f", tmax);
	sprintf(cvmin, "%1.1f", vmin);
	sprintf(cvmax, "%1.1f", vmax);

	w_range = w_sec / interval_sec;
	points = (XPoint *) malloc(sizeof(short) * 2 * w_range);

	for (i = 0; i < NUM_DATA; i++) {
		rdp[i] = p = (ring_d *) malloc(sizeof(ring_d));	
		rdpw[i] = p;
		for (n = 1; n < width; n++) {
			p->next = (ring_d *) malloc(sizeof(ring_d));	
			p = p->next;
		}
		p->next = rdp[i];
	}
	fmean = (float *) malloc(sizeof(float) * NUM_DATA * n_count);

	orign[0] = tmin;
	orign[1] = tmin;
# ifdef NO_TEMP3
	orign[2] = vmin;
# else
	orign[2] = tmin;
	orign[3] = vmin;
	cg_w = (cg_width[0] + cg_width[3]) / 2;
	cv_w = (cv_width[0] + cv_width[3]) / 2;
# endif
	x_rdg[0] = 0;
# ifdef NO_TEMP3
	x_rdg[1] = (width - cg_width[1]) / 2;
	x_rdg[2] = width - cg_width[2] - 1;
# else
	x_rdg[1] = cg_width[0] / 2 + (width - cg_w) / 3 - cg_width[1] / 2;
	x_rdg[2] = cg_width[0] / 2 + (width - cg_w) * 2 / 3 - cg_width[2] / 2;
	x_rdg[3] = width - cg_width[3] - 1;
# endif
	x_rdv[0] = 0;
# ifdef NO_TEMP3
	x_rdv[1] = (width - cv_width[1]) / 2;
	x_rdv[2] = width - cv_width[2] - 1;
# else
	x_rdv[1] = cv_width[0] / 2 + (width - cv_w) / 3 - cv_width[1] / 2;
	x_rdv[2] = cv_width[0] / 2 + (width - cv_w) * 2 / 3 - cv_width[2] / 2;
	x_rdv[3] = width - cv_width[3] - 1;
# endif
    y_rdg = fontstr->max_bounds.ascent - 1;
/*
	y_rdv = 2 * fontstr->max_bounds.ascent + fontstr->max_bounds.descent;
	y_rdv = 2 * fontstr->max_bounds.ascent;
*/
	y_rdv = 2 * y_rdg;
/*
	c_height = 2 * (fontstr->max_bounds.ascent + fontstr->max_bounds.descent);
*/
	c_height = 2 * fontstr->max_bounds.ascent;
	cm_height = c_height + y_rdg - 1;
	cm_width = XTextWidth(fontstr, cvmin, strlen(cvmin)) - 1;
	sscl = (float) width / (float) w_range;
	tscl = (float) (height - c_height)/ (tmax - tmin);
	vscl = (float) (height - c_height)/ (vmax - vmin);
	htck = (float) (height - c_height)/ (float) (n_tick + 1);
	scale[0] = tscl;
	scale[1] = tscl;
# ifdef NO_TEMP3
	scale[2] = vscl;
# else
	scale[2] = tscl;
	scale[3] = vscl;
# endif

	if (signal(SIGALRM, SIG_IGN) != SIG_IGN)
#ifndef LINUX
		signal(SIGALRM, (sig_t) alarm_handler);
#else
		signal(SIGALRM, alarm_handler);
#endif

	t_sec = interval_sec / n_count;
	t_usec = (interval_sec % n_count) * 1000000 / n_count;

	itp->it_interval.tv_sec = t_sec;
	itp->it_interval.tv_usec = t_usec;
	itp->it_value.tv_sec = t_sec;
	itp->it_value.tv_usec = t_usec;

	setitimer(ITIMER_REAL, itp, (struct itimerval *) 0);
}

sig_t alarm_handler(int sig)
{
	struct itimerval *itp = &itv;
	float d, *p;
	int i, n;

	signal(sig, SIG_IGN);

# ifdef NO_TEMP3
	getTemp(&cur_val[0], &cur_val[1], &d);
	getVolt(&cur_val[2], &d, &d, &d, &d, &d, &d);
# else
	getTemp(&cur_val[0], &cur_val[1], &cur_val[2]);
	getVolt(&cur_val[3], &d, &d, &d, &d, &d, &d);
# endif

	draw_values();

	p = fmean + counter;
	for (i = 0; i < NUM_DATA; i++)
		*(p + i * n_count) = cur_val[i];

	counter++;
	if (counter == n_count) {
		if (w_counter <= w_range)
			w_counter++;
		else {
			for (i = 0; i < NUM_DATA; i++)
				rdp[i] = rdp[i]->next;
		}
		counter = 0;
		p = fmean;
		for (i = 0; i < NUM_DATA; i++) {
			for (n = 0, d = 0.0; n < n_count; n++, p++)
				d += *p;
			rdpw[i]->val = d / (float) n_count;
			rdpw[i] = rdpw[i]->next;
		}
		repaint_proc();
	}

	itp->it_interval.tv_sec = t_sec;
	itp->it_interval.tv_usec = t_usec;
	itp->it_value.tv_sec = t_sec;
	itp->it_value.tv_usec = t_usec;

	setitimer(ITIMER_REAL, itp, (struct itimerval *) 0);

#ifndef LINUX
	signal(SIGALRM, (sig_t) alarm_handler);
#else
	signal(SIGALRM, alarm_handler);
#endif

}

void draw_values(void)
{
	int i;

	XClearArea(disp, win, 0, y_rdg , 0, y_rdg, False);
	for (i = 0; i < NUM_DATA; i++) {
		sprintf(c_rdv[i], c_rdp[i], cur_val[i]);
		XDrawString(disp, win, gcl[i], x_rdv[i], y_rdv, \
					c_rdv[i], strlen(c_rdv[i]));
	}
	XFlush(disp);
}

