File: timing.h

package info (click to toggle)
lcdproc 0.5.9-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 5,064 kB
  • sloc: ansic: 59,645; sh: 1,740; perl: 681; makefile: 417
file content (194 lines) | stat: -rw-r--r-- 5,917 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/** \file server/drivers/timing.h
 * Utility header file for timing functions
 *
 * Made by Guillaume Filion, moved from the HD44780 driver.
 *
 * From hd44780.c:
 * Modified July 2000 by Charles Steinkuehler to use one of 3 methods for delay
 * timing.  I/O reads, gettimeofday, and nanosleep.  Of the three, nanosleep
 * seems to work best, so that's what is set by default.
 */

/*-
 * This file is released under the GNU General Public License. Refer to the
 * COPYING file distributed with this package.
 *
 * Copyright (c)  2001 Guillaume Filion <gfk@logidac.com>
 *                2001 Joris Robijn <joris@robijn.net>
 *                2000 Charles Steinkuehler <cstein@newtek.com>
 */

#ifndef _TIMING_H
#define _TIMING_H

/*
 * Uncomment one of the lines below this paragraph to select your desired
 * delay generation mechanism.
 * Mechanism DELAY_NANOSLEEP seems to provide the best performance.
 * Mechanism DELAY_IOCALLS can be quite inaccurate.
 *
 * This should be a configure option. However probably nobody wants to
 * change this nowadays anyway. Maybe we should just get rid of the
 * alternatives.
 */

//#define DELAY_GETTIMEOFDAY
#define DELAY_NANOSLEEP
//#define DELAY_IOCALLS


#include <string.h>
#include <errno.h>
#include <unistd.h>

#include "shared/report.h"

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

/* Include the correct time.h stuff (regardless of selected mechanism) */
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
#  include <sys/time.h>
# else
#  include <time.h>
# endif
#endif

#if defined HAVE_SCHED_H
# include <sched.h>
#endif

/* Only one alternate delay method at a time, please ;-) */
#if defined DELAY_GETTIMEOFDAY
# undef DELAY_NANOSLEEP
# undef DELAY_IOCALLS
#elif defined DELAY_IOCALLS && defined HAVE_PCSTYLE_LPT_CONTROL
# undef DELAY_GETTIMEOFDAY
# undef DELAY_NANOSLEEP
# include "port.h"
#else /* assume DELAY_NANOSLEEP */
# undef DELAY_GETTIMEOFDAY
# undef DELAY_IOCALLS
#endif

/*
 * Convenience macros for operations on timevals. These are usually defined
 * in sys/time.h. If your system does not have them, the defines from below
 * are used.
 *
 * NOTE: `timercmp' does not work for >= or <=.
 */
#ifndef timerisset
# define timerisset(tvp)        ((tvp)->tv_sec || (tvp)->tv_usec)
#endif
#ifndef timerclear
# define timerclear(tvp)        ((tvp)->tv_sec = (tvp)->tv_usec = 0)
#endif
#ifndef timercmp
# define timercmp(a, b, CMP)                                                  \
  (((a)->tv_sec == (b)->tv_sec) ?                                             \
   ((a)->tv_usec CMP (b)->tv_usec) :                                          \
   ((a)->tv_sec CMP (b)->tv_sec))
#endif
#ifndef timeradd
# define timeradd(a, b, result)                                               \
  do {                                                                        \
    (result)->tv_sec = (a)->tv_sec + (b)->tv_sec;                             \
    (result)->tv_usec = (a)->tv_usec + (b)->tv_usec;                          \
    if ((result)->tv_usec >= 1000000)                                         \
      {                                                                       \
        ++(result)->tv_sec;                                                   \
        (result)->tv_usec -= 1000000;                                         \
      }                                                                       \
  } while (0)
#endif
#ifndef timersub
# define timersub(a, b, result)                                               \
  do {                                                                        \
    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                             \
    (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;                          \
    if ((result)->tv_usec < 0) {                                              \
      --(result)->tv_sec;                                                     \
      (result)->tv_usec += 1000000;                                           \
    }                                                                         \
  } while (0)
#endif


/**
 * Do necessary initialization for the selected waiting method.
 * \return  0 if successful, -1 on error.
 */
static inline int
timing_init()
{
#if defined DELAY_NANOSLEEP
# if defined HAVE_SCHED_SETSCHEDULER
	/* Change to Round-Robin scheduling for nanosleep if possible */
	/* Set priority to 1 */
	struct sched_param param;
	param.sched_priority=1;
	if (( sched_setscheduler(0, SCHED_RR, &param)) == -1) {
		report(RPT_WARNING, "Can't obtain realtime priority: %s", strerror(errno));
# else
	{
		report(RPT_WARNING, "Not compiled for realtime priority");
# endif
		report(RPT_WARNING, "Device communication might be unreliable or slow");
	}
#elif defined DELAY_IOCALLS
	if (port_access(0x3BD) == -1) {
		return -1;
	}
#endif
	return 0;
}


/**
 * Delay operation for some time using either gettimeofday (more or less an
 * active waiting loop), nanosleep, or an I/O call.
 * \param usecs  Microsecond to pause
 */
static inline void
timing_uPause(int usecs)
{
#if defined DELAY_GETTIMEOFDAY
	struct timeval current_time,delay_time,wait_time;

	/* Get current time first thing */
	gettimeofday(&current_time,NULL);

	/* Calculate when delay is over */
	delay_time.tv_sec  = 0;
	delay_time.tv_usec = usecs;
	timeradd(&current_time,&delay_time,&wait_time);

	do {
		gettimeofday(&current_time,NULL);
	} while (timercmp(&current_time,&wait_time,<));

#elif defined DELAY_NANOSLEEP
	struct timespec delay_time,remaining;

	delay_time.tv_sec = 0;
	delay_time.tv_nsec = usecs * 1000;
	while ( nanosleep(&delay_time,&remaining) == -1 )
	{
		delay_time.tv_sec  = remaining.tv_sec;
		delay_time.tv_nsec = remaining.tv_nsec;
	}
#else	/* using I/O timing */
	int i;
	for (i = 0; i < usecs; ++i)
		port_in(0x3BD);	/* Assuming every port I/O takes 1us */
#endif
}


#endif /* _TIMING_H */