1 | #include <time.h> |
---|
2 | #include "timing.hpp" |
---|
3 | #include <dos.h> |
---|
4 | #include <stdlib.h> |
---|
5 | #include <i86.h> |
---|
6 | #include <stdio.h> |
---|
7 | #include <conio.h> |
---|
8 | #include "dprint.hpp" |
---|
9 | #include <string.h> |
---|
10 | |
---|
11 | |
---|
12 | static void (__interrupt __far *prev_int8)()=NULL; |
---|
13 | volatile unsigned long tick_counter,start_tick_counter; // note : if timer handler is installed for more than 497 days then |
---|
14 | // tick_counter will overflow. ** don't use this in OS code ** |
---|
15 | |
---|
16 | void (*install_timer_handler)(void (*fun)())=NULL; // function to install timer |
---|
17 | void (*uninstall_timer_handler)()=NULL; |
---|
18 | unsigned char timer_installed=0; |
---|
19 | |
---|
20 | |
---|
21 | static dostime_t dos_start_time; |
---|
22 | static dosdate_t dos_start_date; |
---|
23 | static chain_on=0,chain_counter=0; |
---|
24 | int total_timer_calls=0; |
---|
25 | |
---|
26 | #define MAX_TIMER_CALLS 10 |
---|
27 | |
---|
28 | #define TICKS_PER_SEC 100 |
---|
29 | |
---|
30 | struct |
---|
31 | { |
---|
32 | int and_call_mask; |
---|
33 | void ( *fun)(); |
---|
34 | } timer_calls[MAX_TIMER_CALLS]; |
---|
35 | |
---|
36 | void add_timer_call(void ( *fun)(), int and_call_mask) |
---|
37 | { |
---|
38 | if (total_timer_calls>=MAX_TIMER_CALLS) |
---|
39 | { |
---|
40 | dprintf("Too many timer calls installed\n"); |
---|
41 | exit(0); |
---|
42 | } |
---|
43 | timer_calls[total_timer_calls].fun=fun; |
---|
44 | timer_calls[total_timer_calls].and_call_mask=and_call_mask; |
---|
45 | total_timer_calls++; |
---|
46 | } |
---|
47 | |
---|
48 | void remove_timer_call(void ( *fun)()) |
---|
49 | { |
---|
50 | for (int i=0;i<total_timer_calls;i++) |
---|
51 | { |
---|
52 | if (timer_calls[i].fun==fun) |
---|
53 | { |
---|
54 | for (int j=i;j<total_timer_calls-1;j++) |
---|
55 | timer_calls[j]=timer_calls[j+1]; |
---|
56 | total_timer_calls--; |
---|
57 | return ; |
---|
58 | } |
---|
59 | } |
---|
60 | dprintf("remove_timer_call : call not installed\n"); |
---|
61 | exit(0); |
---|
62 | } |
---|
63 | |
---|
64 | void cli(); |
---|
65 | #pragma aux cli = "cli"; |
---|
66 | |
---|
67 | void sti(); |
---|
68 | #pragma aux sti = "sti"; |
---|
69 | |
---|
70 | |
---|
71 | |
---|
72 | static int inside=0; // check for re-entry |
---|
73 | void __interrupt __far new_timer_int () |
---|
74 | { |
---|
75 | outp(0x20,0x20); // signal int chip that ints can continue |
---|
76 | tick_counter++; |
---|
77 | |
---|
78 | if (!inside) |
---|
79 | { |
---|
80 | inside=1; |
---|
81 | sti(); // turn interrupts back on |
---|
82 | |
---|
83 | |
---|
84 | for (int i=0;i<total_timer_calls;i++) |
---|
85 | if ((tick_counter&timer_calls[i].and_call_mask)==0) |
---|
86 | timer_calls[i].fun(); |
---|
87 | inside=0; |
---|
88 | } else sti(); // turn interrupts back on |
---|
89 | |
---|
90 | chain_counter++; // see if we need to call the normal DOS intr yet |
---|
91 | if (chain_counter==chain_on) |
---|
92 | { |
---|
93 | chain_counter=0; |
---|
94 | _chain_intr(prev_int8); |
---|
95 | } |
---|
96 | |
---|
97 | } |
---|
98 | |
---|
99 | void timer_stub() // this should be called int timer_init has been called and install_timer_handler!=NULL |
---|
100 | { |
---|
101 | tick_counter++; |
---|
102 | |
---|
103 | if (!inside) |
---|
104 | { |
---|
105 | inside=1; |
---|
106 | for (int i=0;i<total_timer_calls;i++) |
---|
107 | if ((tick_counter&timer_calls[i].and_call_mask)==0) |
---|
108 | timer_calls[i].fun(); |
---|
109 | inside=0; |
---|
110 | } |
---|
111 | } |
---|
112 | |
---|
113 | void timer_init() |
---|
114 | { |
---|
115 | if (install_timer_handler) |
---|
116 | { |
---|
117 | install_timer_handler(timer_stub); |
---|
118 | timer_installed=1; |
---|
119 | } else |
---|
120 | { |
---|
121 | if (prev_int8) |
---|
122 | fprintf(stderr,"timer_init called twice (not good)\n"); |
---|
123 | else |
---|
124 | { |
---|
125 | _dos_gettime(&dos_start_time); // get initail time |
---|
126 | _dos_getdate(&dos_start_date); // get initail date |
---|
127 | |
---|
128 | prev_int8=_dos_getvect(8); |
---|
129 | _dos_setvect(0x8008,new_timer_int); // set protected mode int 8 |
---|
130 | |
---|
131 | int new_divsor; |
---|
132 | if (TICKS_PER_SEC<18.2) |
---|
133 | { |
---|
134 | new_divsor=0xffff; |
---|
135 | chain_on=1; |
---|
136 | } |
---|
137 | else |
---|
138 | { |
---|
139 | chain_on=TICKS_PER_SEC/18.2; |
---|
140 | new_divsor=0xffff/chain_on; |
---|
141 | } |
---|
142 | |
---|
143 | chain_counter=0; |
---|
144 | cli(); |
---|
145 | outp(0x43,0x36); // set timer speed |
---|
146 | outp(0x40,(new_divsor&0xff)); |
---|
147 | outp(0x40,((new_divsor&0xff00)>>8)); |
---|
148 | sti(); |
---|
149 | |
---|
150 | timer_installed=1; |
---|
151 | } |
---|
152 | atexit(timer_uninit); |
---|
153 | start_tick_counter=tick_counter=clock(); |
---|
154 | } |
---|
155 | } |
---|
156 | |
---|
157 | static char dim[12]={31, // Jan |
---|
158 | 29, // Feb |
---|
159 | 31, // March |
---|
160 | 30, // Apr |
---|
161 | 31, // May |
---|
162 | 30, // June |
---|
163 | 31, // July |
---|
164 | 30, // Aug |
---|
165 | 31, // Sept |
---|
166 | 31, // October |
---|
167 | 30, // Nov |
---|
168 | 31}; // Dec |
---|
169 | |
---|
170 | static int days_in_month(long month, long year) |
---|
171 | { |
---|
172 | if (month==1 && (((year-1)%4)==0)) // check for leap-year |
---|
173 | return 28; |
---|
174 | else return dim[month]; |
---|
175 | } |
---|
176 | |
---|
177 | void timer_uninit() |
---|
178 | { |
---|
179 | chain_on=0; |
---|
180 | if (timer_installed) |
---|
181 | { |
---|
182 | if (uninstall_timer_handler) |
---|
183 | uninstall_timer_handler(); |
---|
184 | else |
---|
185 | { |
---|
186 | if (prev_int8) |
---|
187 | { |
---|
188 | outp(0x43,0x36); // set timer speed back to 18.2 |
---|
189 | outp(0x40,0); |
---|
190 | outp(0x40,0); |
---|
191 | _dos_setvect(8,prev_int8); |
---|
192 | |
---|
193 | |
---|
194 | // don't try to restore the clock, we used chain_intr |
---|
195 | /* unsigned long ticks_passed=tick_counter-start_tick_counter; |
---|
196 | unsigned long hsec=ticks_passed*100/TICKS_PER_SEC; |
---|
197 | |
---|
198 | // now calculate how much time we stole from DOS and adjust the clock |
---|
199 | dos_start_time.hsecond=((long)dos_start_time.hsecond+hsec)%100; |
---|
200 | dos_start_time.second=((long)dos_start_time.second+hsec/100)%60; |
---|
201 | dos_start_time.minute=((long)dos_start_time.minute+hsec/(100*60))%60; |
---|
202 | dos_start_time.hour=((long)dos_start_time.hour+hsec/(100*60*60))%24; |
---|
203 | |
---|
204 | long days=hsec/(100*60*60*24); |
---|
205 | while (days) |
---|
206 | { |
---|
207 | dos_start_date.dayofweek=(dos_start_date.dayofweek+2)%7-1; |
---|
208 | dos_start_date.day=dos_start_date.day+1; |
---|
209 | if (days_in_month(dos_start_date.month,dos_start_date.year)>dos_start_date.day) |
---|
210 | { |
---|
211 | dos_start_date.day=1; |
---|
212 | dos_start_date.month++; |
---|
213 | if (dos_start_date.month>12) |
---|
214 | { |
---|
215 | dos_start_date.month=1; |
---|
216 | dos_start_date.year++; |
---|
217 | } |
---|
218 | } |
---|
219 | days--; |
---|
220 | } */ |
---|
221 | |
---|
222 | _dos_settime(&dos_start_time); |
---|
223 | _dos_setdate(&dos_start_date); |
---|
224 | |
---|
225 | prev_int8=NULL; |
---|
226 | } |
---|
227 | } |
---|
228 | timer_installed=0; |
---|
229 | } |
---|
230 | } |
---|
231 | |
---|
232 | void time_marker::get_time() |
---|
233 | { |
---|
234 | seconds=0; |
---|
235 | if (timer_installed) |
---|
236 | micro_seconds=tick_counter*1000/TICKS_PER_SEC; |
---|
237 | else |
---|
238 | micro_seconds=clock()*10; |
---|
239 | } |
---|
240 | |
---|
241 | time_marker::time_marker() |
---|
242 | { |
---|
243 | seconds=0; |
---|
244 | if (timer_installed) |
---|
245 | micro_seconds=tick_counter*1000/TICKS_PER_SEC; |
---|
246 | else |
---|
247 | micro_seconds=clock()*10; |
---|
248 | } |
---|
249 | |
---|
250 | double time_marker::diff_time(time_marker *other) |
---|
251 | { |
---|
252 | return (double)(micro_seconds-other->micro_seconds)/1000.0; |
---|
253 | } |
---|
254 | |
---|
255 | void milli_wait(unsigned wait_time) |
---|
256 | { |
---|
257 | if (timer_installed) |
---|
258 | { |
---|
259 | unsigned long wait_tick=wait_time*10/TICKS_PER_SEC+tick_counter; |
---|
260 | while (tick_counter<wait_tick) ; |
---|
261 | } else delay(wait_time); // timer not installed |
---|
262 | } |
---|
263 | |
---|