|
0
|
1 //========================================================================== |
|
|
2 // |
|
2
|
3 // common/clock.cxx |
|
0
|
4 // |
|
2
|
5 // Clock class implementations |
|
0
|
6 // |
|
|
7 //========================================================================== |
|
|
8 //####COPYRIGHTBEGIN#### |
|
|
9 // |
|
|
10 // ------------------------------------------- |
|
|
11 // The contents of this file are subject to the Cygnus eCos Public License |
|
|
12 // Version 1.0 (the "License"); you may not use this file except in |
|
|
13 // compliance with the License. You may obtain a copy of the License at |
|
|
14 // http://sourceware.cygnus.com/ecos |
|
|
15 // |
|
|
16 // Software distributed under the License is distributed on an "AS IS" |
|
|
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the |
|
|
18 // License for the specific language governing rights and limitations under |
|
|
19 // the License. |
|
|
20 // |
|
|
21 // The Original Code is eCos - Embedded Cygnus Operating System, released |
|
|
22 // September 30, 1998. |
|
|
23 // |
|
|
24 // The Initial Developer of the Original Code is Cygnus. Portions created |
|
2
|
25 // by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions. All Rights Reserved. |
|
0
|
26 // ------------------------------------------- |
|
|
27 // |
|
|
28 //####COPYRIGHTEND#### |
|
|
29 //========================================================================== |
|
|
30 //#####DESCRIPTIONBEGIN#### |
|
|
31 // |
|
2
|
32 // Author(s): nickg |
|
|
33 // Contributors: nickg |
|
|
34 // Date: 1997-09-15 |
|
|
35 // Purpose: Clock class implementation |
|
0
|
36 // Description: This file contains the definitions of the counter, |
|
|
37 // clock and alarm class member functions that are common |
|
|
38 // to all clock implementations. |
|
|
39 // |
|
|
40 //####DESCRIPTIONEND#### |
|
|
41 // |
|
|
42 //========================================================================== |
|
|
43 |
|
|
44 #include <pkgconf/kernel.h> |
|
|
45 |
|
|
46 #include <cyg/kernel/ktypes.h> // base kernel types |
|
|
47 #include <cyg/infra/cyg_trac.h> // tracing macros |
|
|
48 #include <cyg/infra/cyg_ass.h> // assertion macros |
|
|
49 |
|
|
50 #include <cyg/kernel/clock.hxx> // our header |
|
|
51 |
|
|
52 #include <cyg/kernel/sched.hxx> // scheduler definitions |
|
|
53 #include <cyg/kernel/thread.hxx> // thread definitions |
|
|
54 #include <cyg/kernel/intr.hxx> // interrupt definitions |
|
|
55 |
|
|
56 #include <cyg/kernel/sched.inl> // scheduler inlines |
|
|
57 #include <cyg/kernel/clock.inl> // Clock inlines |
|
|
58 |
|
|
59 // ------------------------------------------------------------------------- |
|
|
60 // Static variables |
|
|
61 |
|
|
62 #ifdef CYGVAR_KERNEL_COUNTERS_CLOCK |
|
|
63 |
|
|
64 Cyg_Clock *Cyg_Clock::real_time_clock = NULL; // System real time clock |
|
|
65 |
|
|
66 #endif |
|
|
67 |
|
|
68 //========================================================================== |
|
|
69 // Constructor for counter object |
|
|
70 |
|
|
71 Cyg_Counter::Cyg_Counter( |
|
|
72 cyg_uint32 incr |
|
|
73 ) |
|
|
74 { |
|
|
75 CYG_REPORT_FUNCTION(); |
|
|
76 |
|
|
77 counter = 0; |
|
|
78 increment = incr; |
|
|
79 #if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST) |
|
|
80 |
|
|
81 alarm_list = NULL; // Linear list of Alarms |
|
|
82 |
|
|
83 #elif defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST) |
|
|
84 |
|
|
85 for(cyg_ucount32 i=0; i < CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE; i++) { |
|
|
86 alarm_list[i] = NULL; |
|
|
87 } |
|
|
88 |
|
|
89 #else |
|
|
90 #error "No CYGIMP_KERNEL_COUNTERS_x_LIST config" |
|
|
91 #endif |
|
|
92 |
|
|
93 } |
|
|
94 |
|
|
95 // ------------------------------------------------------------------------- |
|
|
96 // Destructor for Counter object |
|
|
97 |
|
|
98 Cyg_Counter::~Cyg_Counter() |
|
|
99 { |
|
|
100 CYG_REPORT_FUNCTION(); |
|
|
101 |
|
|
102 |
|
|
103 } |
|
|
104 |
|
|
105 // ------------------------------------------------------------------------- |
|
|
106 // |
|
|
107 |
|
|
108 #ifdef CYGDBG_USE_ASSERTS |
|
|
109 |
|
2
|
110 bool Cyg_Counter::check_this( cyg_assert_class_zeal zeal) const |
|
0
|
111 { |
|
|
112 // check that we have a non-NULL pointer first |
|
|
113 if( this == NULL ) return false; |
|
|
114 |
|
|
115 switch( zeal ) |
|
|
116 { |
|
|
117 case cyg_system_test: |
|
|
118 case cyg_extreme: |
|
|
119 case cyg_thorough: |
|
|
120 case cyg_quick: |
|
|
121 case cyg_trivial: |
|
|
122 case cyg_none: |
|
|
123 default: |
|
|
124 break; |
|
|
125 }; |
|
|
126 |
|
|
127 return true; |
|
|
128 } |
|
|
129 |
|
|
130 #endif |
|
|
131 |
|
|
132 // ------------------------------------------------------------------------- |
|
|
133 // Counter tick function |
|
|
134 |
|
|
135 void Cyg_Counter::tick( cyg_uint32 ticks ) |
|
|
136 { |
|
|
137 // CYG_REPORT_FUNCTION(); |
|
|
138 |
|
|
139 CYG_ASSERTCLASS( this, "Bad counter object" ); |
|
|
140 |
|
|
141 // Increment the counter in a loop so we process |
|
|
142 // each tick separately. This is easier than trying |
|
|
143 // to cope with a range of increments. |
|
|
144 |
|
|
145 while( ticks-- ) |
|
|
146 { |
|
|
147 Cyg_Scheduler::lock(); |
|
|
148 |
|
|
149 // increment the counter, note that it is |
|
|
150 // allowed to wrap. |
|
|
151 counter += increment; |
|
|
152 |
|
|
153 // now check for any expired alarms |
|
|
154 |
|
|
155 Cyg_Alarm **alarm_list_ptr; // pointer to list |
|
|
156 |
|
|
157 #if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST) |
|
|
158 |
|
|
159 alarm_list_ptr = &alarm_list; |
|
|
160 |
|
|
161 #elif defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST) |
|
|
162 |
|
|
163 // With multiple lists, each one contains only the alarms |
|
|
164 // that will expire at a given tick modulo the list number. |
|
|
165 // So we only have a fraction of the alarms to check here. |
|
|
166 |
|
|
167 alarm_list_ptr = &(alarm_list[ |
|
|
168 (counter/increment) % CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE ] ); |
|
|
169 |
|
|
170 #else |
|
|
171 #error "No CYGIMP_KERNEL_COUNTERS_x_LIST config" |
|
|
172 #endif |
|
|
173 |
|
|
174 // Now that we have the list pointer, we can use common code for |
|
|
175 // both list oragnizations. |
|
|
176 |
|
2
|
177 #ifdef CYGIMP_KERNEL_COUNTERS_SORT_LIST |
|
|
178 |
|
|
179 // With a sorted alarm list, we can simply pick alarms off the |
|
|
180 // front of the list until we find one that is in the future. |
|
|
181 |
|
0
|
182 while( *alarm_list_ptr != NULL ) |
|
|
183 { |
|
|
184 Cyg_Alarm *alarm = *alarm_list_ptr; |
|
|
185 |
|
|
186 CYG_ASSERTCLASS(alarm, "Bad alarm in counter list" ); |
|
|
187 |
|
|
188 if( alarm->trigger <= counter ) |
|
|
189 { |
|
|
190 // remove alarm from list |
|
|
191 *alarm_list_ptr = alarm->next; |
|
|
192 |
|
|
193 if( alarm->interval != 0 ) |
|
|
194 { |
|
|
195 // The alarm has a retrigger interval. |
|
|
196 // Reset the trigger time and requeue |
|
|
197 // the alarm. |
|
|
198 alarm->trigger += alarm->interval; |
|
|
199 add_alarm( alarm ); |
|
|
200 } |
|
|
201 else alarm->enabled = false; |
|
|
202 |
|
|
203 CYG_INSTRUMENT_ALARM( CALL, this, alarm ); |
|
|
204 |
|
|
205 // call alarm function |
|
|
206 alarm->alarm(alarm, alarm->data); |
|
|
207 |
|
|
208 // all done, loop |
|
|
209 } |
|
|
210 else break; |
|
|
211 } |
|
2
|
212 #else |
|
0
|
213 |
|
2
|
214 // With an unsorted list, we must scan the whole list for |
|
|
215 // candidates. We move the whole list to a temporary location |
|
|
216 // before doing this so that we are not disturbed by new |
|
|
217 // alarms being added to the list. As we consider and |
|
|
218 // eliminate alarms we put them onto the done_list and at the |
|
|
219 // end we then move it back to where it belongs. |
|
|
220 |
|
|
221 Cyg_Alarm *done_list = NULL; |
|
|
222 |
|
|
223 Cyg_Alarm *alarm_list = *alarm_list_ptr; |
|
|
224 *alarm_list_ptr = NULL; |
|
|
225 |
|
|
226 while( alarm_list != NULL ) |
|
|
227 { |
|
|
228 Cyg_Alarm *alarm = alarm_list; |
|
|
229 |
|
|
230 CYG_ASSERTCLASS(alarm, "Bad alarm in counter list" ); |
|
|
231 |
|
|
232 // remove alarm from list |
|
|
233 alarm_list = alarm->next; |
|
|
234 |
|
|
235 if( alarm->trigger <= counter ) |
|
|
236 { |
|
|
237 if( alarm->interval != 0 ) |
|
|
238 { |
|
|
239 // The alarm has a retrigger interval. |
|
|
240 // Reset the trigger time and requeue |
|
|
241 // the alarm. |
|
|
242 alarm->trigger += alarm->interval; |
|
|
243 add_alarm( alarm ); |
|
|
244 } |
|
|
245 else alarm->enabled = false; |
|
|
246 |
|
|
247 CYG_INSTRUMENT_ALARM( CALL, this, alarm ); |
|
|
248 |
|
|
249 // call alarm function |
|
|
250 alarm->alarm(alarm, alarm->data); |
|
|
251 |
|
|
252 // all done, loop |
|
|
253 } |
|
|
254 else |
|
|
255 { |
|
|
256 // add unused alarm to done list. |
|
|
257 alarm->next = done_list; |
|
|
258 done_list = alarm; |
|
|
259 } |
|
|
260 } |
|
|
261 |
|
|
262 // Transfer any alarms that might have been added to the |
|
|
263 // alarm list by alarm callbacks to the done list. This |
|
|
264 // happens very rarely. |
|
|
265 while( *alarm_list_ptr != NULL ) |
|
|
266 { |
|
|
267 Cyg_Alarm *alarm = *alarm_list_ptr; |
|
|
268 *alarm_list_ptr = alarm->next; |
|
|
269 alarm->next = done_list; |
|
|
270 done_list = alarm; |
|
|
271 } |
|
|
272 |
|
|
273 // return done list to real list |
|
|
274 *alarm_list_ptr = done_list; |
|
|
275 |
|
|
276 #endif |
|
0
|
277 Cyg_Scheduler::unlock(); |
|
|
278 |
|
|
279 } |
|
|
280 |
|
|
281 } |
|
|
282 |
|
|
283 // ------------------------------------------------------------------------- |
|
|
284 // Add an alarm to this counter |
|
|
285 |
|
|
286 void Cyg_Counter::add_alarm( Cyg_Alarm *alarm ) |
|
|
287 { |
|
|
288 CYG_REPORT_FUNCTION(); |
|
|
289 |
|
|
290 CYG_ASSERTCLASS( this, "Bad counter object" ); |
|
|
291 CYG_ASSERTCLASS( alarm, "Bad alarm passed" ); |
|
|
292 |
|
|
293 Cyg_Scheduler::lock(); |
|
|
294 |
|
|
295 // set this now to allow an immediate handler call to manipulate |
|
|
296 // this alarm sensibly. |
|
|
297 alarm->enabled = true; |
|
|
298 |
|
|
299 // Check here for an alarm that triggers now or in the past and |
|
|
300 // call its alarm function immediately. |
|
|
301 if( alarm->trigger <= counter ) |
|
|
302 { |
|
|
303 CYG_INSTRUMENT_ALARM( CALL, this, alarm ); |
|
|
304 |
|
|
305 // call alarm function. Note that this is being |
|
|
306 // called here before the add_alarm has returned. |
|
|
307 // Note that this function may disable the alarm. |
|
|
308 |
|
|
309 alarm->alarm(alarm, alarm->data); |
|
|
310 |
|
|
311 // Note that this extra check on alarm->enabled is in case the |
|
|
312 // handler function disables this alarm! |
|
|
313 if( alarm->interval != 0 && alarm->enabled ) |
|
|
314 { |
|
|
315 // The alarm has a retrigger interval. |
|
|
316 // Reset the trigger interval and drop |
|
|
317 // through to queue it. |
|
|
318 alarm->trigger += alarm->interval; |
|
|
319 // ensure the next alarm time is in our future, and in phase |
|
|
320 // with the original time requested. |
|
|
321 alarm->synchronize(); |
|
|
322 } |
|
|
323 else |
|
|
324 { |
|
|
325 // The alarm is all done with, disable it |
|
|
326 // unlock and return. |
|
|
327 alarm->enabled = false; |
|
|
328 Cyg_Scheduler::unlock(); |
|
|
329 return; |
|
|
330 } |
|
|
331 } |
|
|
332 |
|
|
333 CYG_INSTRUMENT_ALARM( ADD, this, alarm ); |
|
|
334 |
|
|
335 { |
|
|
336 // Find the pointer to the relevant list _after_ a retrigger |
|
|
337 // alarm has been given its new trigger time. |
|
|
338 |
|
|
339 Cyg_Alarm **alarm_list_ptr; // pointer to list |
|
|
340 |
|
|
341 #if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST) |
|
|
342 |
|
|
343 alarm_list_ptr = &alarm_list; |
|
|
344 |
|
|
345 #elif defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST) |
|
|
346 |
|
|
347 // Each alarm must go into the list that covers the tick that is |
|
|
348 // going to happen _after_ the trigger time (or at it if trigger |
|
|
349 // happens to fall on a tick. |
|
|
350 |
|
|
351 alarm_list_ptr = &(alarm_list[ |
|
|
352 ((alarm->trigger+increment-1)/increment) % |
|
|
353 CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE ] ); |
|
|
354 |
|
|
355 #else |
|
|
356 #error "No CYGIMP_KERNEL_COUNTERS_x_LIST config" |
|
|
357 #endif |
|
|
358 |
|
2
|
359 #ifdef CYGIMP_KERNEL_COUNTERS_SORT_LIST |
|
|
360 |
|
0
|
361 // Now that we have the list pointer, we can use common code for |
|
|
362 // both list oragnizations. |
|
|
363 |
|
|
364 while( *alarm_list_ptr != NULL ) |
|
|
365 { |
|
|
366 Cyg_Alarm *list_alarm = *alarm_list_ptr; |
|
|
367 |
|
|
368 CYG_ASSERTCLASS(list_alarm, "Bad alarm in counter list" ); |
|
|
369 |
|
|
370 // The alarms are in ascending trigger order. When we |
|
|
371 // find an alarm that is later than us, we go in front of |
|
|
372 // it. |
|
|
373 |
|
|
374 if( list_alarm->trigger > alarm->trigger ) break; |
|
|
375 else alarm_list_ptr = &list_alarm->next; |
|
|
376 } |
|
2
|
377 #endif |
|
0
|
378 // Insert the new alarm at *alarm_list_ptr |
|
|
379 |
|
|
380 alarm->next = *alarm_list_ptr; |
|
|
381 *alarm_list_ptr = alarm; |
|
|
382 |
|
|
383 Cyg_Scheduler::unlock(); |
|
|
384 } |
|
|
385 } |
|
|
386 |
|
|
387 // ------------------------------------------------------------------------- |
|
|
388 // Remove an alarm from this counter |
|
|
389 |
|
|
390 void Cyg_Counter::rem_alarm( Cyg_Alarm *alarm ) |
|
|
391 { |
|
|
392 CYG_REPORT_FUNCTION(); |
|
|
393 |
|
|
394 CYG_ASSERTCLASS( this, "Bad counter object" ); |
|
|
395 CYG_ASSERTCLASS( alarm, "Bad alarm passed" ); |
|
|
396 |
|
|
397 Cyg_Alarm **alarm_list_ptr; // pointer to list |
|
|
398 |
|
|
399 #if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST) |
|
|
400 |
|
|
401 alarm_list_ptr = &alarm_list; |
|
|
402 |
|
|
403 #elif defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST) |
|
|
404 |
|
|
405 alarm_list_ptr = &(alarm_list[ |
|
|
406 ((alarm->trigger+increment-1)/increment) % |
|
|
407 CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE ] ); |
|
|
408 |
|
|
409 #else |
|
|
410 #error "No CYGIMP_KERNEL_COUNTERS_x_LIST config" |
|
|
411 #endif |
|
|
412 |
|
|
413 // Now that we have the list pointer, we can use common code for |
|
|
414 // both list organizations. |
|
|
415 |
|
|
416 Cyg_Scheduler::lock(); |
|
|
417 |
|
|
418 CYG_INSTRUMENT_ALARM( REM, this, alarm ); |
|
|
419 |
|
|
420 while( *alarm_list_ptr != NULL ) |
|
|
421 { |
|
|
422 Cyg_Alarm *list_alarm = *alarm_list_ptr; |
|
|
423 |
|
|
424 CYG_ASSERTCLASS(list_alarm, "Bad alarm in counter list" ); |
|
|
425 |
|
|
426 if( list_alarm == alarm ) break; |
|
|
427 else alarm_list_ptr = &list_alarm->next; |
|
|
428 } |
|
|
429 |
|
|
430 // If the alarm was found, remove it from the list. |
|
|
431 if( *alarm_list_ptr != NULL ) |
|
|
432 { |
|
|
433 *alarm_list_ptr = alarm->next; |
|
|
434 alarm->enabled = false; |
|
|
435 } |
|
|
436 |
|
|
437 Cyg_Scheduler::unlock(); |
|
|
438 } |
|
|
439 |
|
|
440 //========================================================================== |
|
|
441 // Constructor for clock object |
|
|
442 |
|
|
443 Cyg_Clock::Cyg_Clock( |
|
|
444 cyg_resolution res |
|
|
445 ) |
|
|
446 { |
|
|
447 CYG_REPORT_FUNCTION(); |
|
|
448 |
|
|
449 resolution = res; |
|
|
450 } |
|
|
451 |
|
|
452 // ------------------------------------------------------------------------- |
|
|
453 // Destructor for Clock objects |
|
|
454 |
|
|
455 Cyg_Clock::~Cyg_Clock() |
|
|
456 { |
|
|
457 CYG_REPORT_FUNCTION(); |
|
|
458 |
|
|
459 } |
|
|
460 |
|
|
461 // ------------------------------------------------------------------------- |
|
|
462 // |
|
|
463 |
|
|
464 #ifdef CYGDBG_USE_ASSERTS |
|
|
465 |
|
2
|
466 bool Cyg_Clock::check_this( cyg_assert_class_zeal zeal) const |
|
0
|
467 { |
|
|
468 // check that we have a non-NULL pointer first |
|
|
469 if( this == NULL ) return false; |
|
|
470 |
|
|
471 switch( zeal ) |
|
|
472 { |
|
|
473 case cyg_system_test: |
|
|
474 case cyg_extreme: |
|
|
475 case cyg_thorough: |
|
|
476 case cyg_quick: |
|
|
477 case cyg_trivial: |
|
|
478 case cyg_none: |
|
|
479 default: |
|
|
480 break; |
|
|
481 }; |
|
|
482 |
|
|
483 return true; |
|
|
484 } |
|
|
485 |
|
|
486 #endif |
|
|
487 |
|
|
488 //========================================================================== |
|
|
489 // Constructor for alarm object |
|
|
490 |
|
|
491 Cyg_Alarm::Cyg_Alarm( |
|
|
492 Cyg_Counter *c, // Attached to this counter |
|
|
493 cyg_alarm_fn *a, // Call-back function |
|
|
494 CYG_ADDRWORD d // Call-back data |
|
|
495 ) |
|
|
496 { |
|
|
497 CYG_REPORT_FUNCTION(); |
|
|
498 |
|
|
499 counter = c; |
|
|
500 alarm = a; |
|
|
501 data = d; |
|
|
502 trigger = 0; |
|
|
503 interval = 0; |
|
|
504 enabled = false; |
|
|
505 |
|
|
506 #if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST) || defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST) |
|
|
507 next = NULL; |
|
|
508 #endif |
|
|
509 |
|
|
510 } |
|
|
511 |
|
|
512 Cyg_Alarm::Cyg_Alarm(){} |
|
|
513 |
|
|
514 // ------------------------------------------------------------------------- |
|
|
515 // Destructor |
|
|
516 |
|
|
517 Cyg_Alarm::~Cyg_Alarm() |
|
|
518 { |
|
|
519 CYG_REPORT_FUNCTION(); |
|
|
520 |
|
|
521 disable(); |
|
|
522 } |
|
|
523 |
|
|
524 // ------------------------------------------------------------------------- |
|
|
525 // |
|
|
526 |
|
|
527 #ifdef CYGDBG_USE_ASSERTS |
|
|
528 |
|
2
|
529 bool Cyg_Alarm::check_this( cyg_assert_class_zeal zeal) const |
|
0
|
530 { |
|
|
531 // check that we have a non-NULL pointer first |
|
|
532 if( this == NULL ) return false; |
|
|
533 |
|
|
534 switch( zeal ) |
|
|
535 { |
|
|
536 case cyg_system_test: |
|
|
537 case cyg_extreme: |
|
|
538 case cyg_thorough: |
|
|
539 if( trigger != 0 && !enabled ) return false; |
|
|
540 case cyg_quick: |
|
|
541 case cyg_trivial: |
|
|
542 case cyg_none: |
|
|
543 default: |
|
|
544 break; |
|
|
545 }; |
|
|
546 |
|
|
547 return true; |
|
|
548 } |
|
|
549 |
|
|
550 #endif |
|
|
551 |
|
|
552 // ------------------------------------------------------------------------- |
|
|
553 // Initialize Alarm and enable |
|
|
554 |
|
|
555 void Cyg_Alarm::initialize( |
|
|
556 cyg_tick_count t, // Absolute trigger time |
|
|
557 cyg_tick_count i // Relative retrigger interval |
|
|
558 ) |
|
|
559 { |
|
|
560 CYG_REPORT_FUNCTION(); |
|
|
561 |
|
|
562 // If already enabled, remove from counter |
|
|
563 |
|
|
564 if( enabled ) counter->rem_alarm(this); |
|
|
565 |
|
|
566 CYG_INSTRUMENT_ALARM( INIT, this, 0 ); |
|
|
567 CYG_INSTRUMENT_ALARM( TRIGGER, |
|
|
568 ((cyg_uint32 *)&t)[0], |
|
|
569 ((cyg_uint32 *)&t)[1] ); |
|
|
570 CYG_INSTRUMENT_ALARM( INTERVAL, |
|
|
571 ((cyg_uint32 *)&i)[0], |
|
|
572 ((cyg_uint32 *)&i)[1] ); |
|
|
573 |
|
|
574 trigger = t; |
|
|
575 interval = i; |
|
|
576 |
|
|
577 counter->add_alarm(this); |
|
|
578 } |
|
|
579 |
|
|
580 // ------------------------------------------------------------------------- |
|
|
581 // Synchronize with a past alarm stream that had been disabled, |
|
|
582 // bring past times into synch, and the like. |
|
|
583 |
|
|
584 void |
|
|
585 Cyg_Alarm::synchronize( void ) |
|
|
586 { |
|
|
587 if( interval != 0 ) { |
|
|
588 // This expression sets the trigger to the next whole interval |
|
|
589 // at or after the current time. This means that alarms will |
|
|
590 // continue at the same intervals as if they had never been |
|
|
591 // disabled. The alternative would be to just set trigger to |
|
|
592 // (counter->counter + interval), but this is less satisfying |
|
|
593 // than preserving the original intervals. That behaviour can |
|
|
594 // always be obtained by using initialize() rather than |
|
|
595 // enable(), while the current behaviour would be more |
|
|
596 // difficult to achieve that way. |
|
|
597 cyg_tick_count d; |
|
|
598 d = counter->current_value() + interval - trigger; |
|
|
599 if ( d > interval ) { |
|
|
600 // then trigger was in the past, so resynchronize |
|
|
601 trigger += interval * ((d - 1) / interval ); |
|
|
602 } |
|
|
603 // otherwise, we were just set up, so no worries. |
|
|
604 } |
|
|
605 } |
|
|
606 |
|
|
607 // ------------------------------------------------------------------------- |
|
|
608 // Ensure alarm enabled |
|
|
609 |
|
|
610 void Cyg_Alarm::enable() |
|
|
611 { |
|
|
612 if( !enabled ) |
|
|
613 { |
|
|
614 // ensure the alarm time is in our future: |
|
|
615 synchronize(); |
|
|
616 enabled = true; |
|
|
617 counter->add_alarm(this); |
|
|
618 } |
|
|
619 } |
|
|
620 |
|
|
621 //========================================================================== |
|
|
622 // System clock object |
|
|
623 |
|
|
624 #ifdef CYGVAR_KERNEL_COUNTERS_CLOCK |
|
|
625 |
|
|
626 class Cyg_RealTimeClock |
|
|
627 : public Cyg_Clock |
|
|
628 { |
|
|
629 Cyg_Interrupt interrupt; |
|
|
630 |
|
|
631 static cyg_uint32 isr(cyg_vector vector, CYG_ADDRWORD data); |
|
|
632 |
|
|
633 static void dsr(cyg_vector vector, cyg_ucount32 count, CYG_ADDRWORD data); |
|
|
634 |
|
|
635 Cyg_RealTimeClock(); |
|
|
636 |
|
|
637 static Cyg_RealTimeClock rtc; |
|
|
638 }; |
|
|
639 |
|
|
640 Cyg_Clock::cyg_resolution rtc_resolution = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION; |
|
|
641 |
|
|
642 //Cyg_RealTimeClock Cyg_RealTimeClock::rtc __attribute__((init_priority (1))); |
|
|
643 |
|
|
644 Cyg_RealTimeClock Cyg_RealTimeClock::rtc CYG_INIT_PRIORITY( CLOCK ); |
|
|
645 |
|
|
646 // ------------------------------------------------------------------------- |
|
|
647 |
|
|
648 Cyg_RealTimeClock::Cyg_RealTimeClock() |
|
|
649 : Cyg_Clock(rtc_resolution), |
|
2
|
650 interrupt(CYGNUM_HAL_INTERRUPT_RTC, 1, (CYG_ADDRWORD)this, isr, dsr) |
|
0
|
651 { |
|
|
652 CYG_REPORT_FUNCTION(); |
|
|
653 |
|
|
654 HAL_CLOCK_INITIALIZE( CYGNUM_KERNEL_COUNTERS_RTC_PERIOD ); |
|
|
655 |
|
|
656 interrupt.attach(); |
|
|
657 |
|
2
|
658 interrupt.unmask_interrupt(CYGNUM_HAL_INTERRUPT_RTC); |
|
0
|
659 |
|
|
660 Cyg_Clock::real_time_clock = this; |
|
|
661 } |
|
|
662 |
|
2
|
663 #ifdef HAL_CLOCK_LATENCY |
|
|
664 cyg_tick_count total_clock_latency, total_clock_interrupts; |
|
|
665 cyg_int32 min_clock_latency = 0x7FFFFFFF; |
|
|
666 cyg_int32 max_clock_latency = 0; |
|
|
667 bool measure_clock_latency = false; |
|
|
668 #endif |
|
|
669 |
|
0
|
670 // ------------------------------------------------------------------------- |
|
|
671 |
|
|
672 cyg_uint32 Cyg_RealTimeClock::isr(cyg_vector vector, CYG_ADDRWORD data) |
|
|
673 { |
|
|
674 // CYG_REPORT_FUNCTION(); |
|
|
675 |
|
2
|
676 #ifdef HAL_CLOCK_LATENCY |
|
|
677 if (measure_clock_latency) { |
|
|
678 cyg_int32 delta; |
|
|
679 HAL_CLOCK_LATENCY(&delta); |
|
|
680 // Note: Ignore a latency of 0 when finding min_clock_latency. |
|
|
681 if (delta > 0) { |
|
|
682 // Valid delta measured |
|
|
683 total_clock_latency += delta; |
|
|
684 total_clock_interrupts++; |
|
|
685 if (min_clock_latency > delta) min_clock_latency = delta; |
|
|
686 if (max_clock_latency < delta) max_clock_latency = delta; |
|
|
687 } |
|
|
688 } |
|
|
689 #endif |
|
|
690 |
|
0
|
691 CYG_INSTRUMENT_CLOCK( ISR, 0, 0); |
|
|
692 |
|
2
|
693 HAL_CLOCK_RESET( CYGNUM_HAL_INTERRUPT_RTC, CYGNUM_KERNEL_COUNTERS_RTC_PERIOD ); |
|
0
|
694 |
|
2
|
695 Cyg_Interrupt::acknowledge_interrupt(CYGNUM_HAL_INTERRUPT_RTC); |
|
0
|
696 |
|
|
697 return Cyg_Interrupt::CALL_DSR; |
|
|
698 } |
|
|
699 |
|
|
700 // ------------------------------------------------------------------------- |
|
|
701 |
|
|
702 void Cyg_RealTimeClock::dsr(cyg_vector vector, cyg_ucount32 count, CYG_ADDRWORD data) |
|
|
703 { |
|
|
704 // CYG_REPORT_FUNCTION(); |
|
|
705 |
|
|
706 Cyg_RealTimeClock *rtc = (Cyg_RealTimeClock *)data; |
|
|
707 |
|
|
708 CYG_INSTRUMENT_CLOCK( TICK_START, |
|
|
709 rtc->current_value_lo(), |
|
|
710 rtc->current_value_hi()); |
|
|
711 |
|
|
712 rtc->tick( count ); |
|
|
713 |
|
|
714 #ifdef CYGSEM_KERNEL_SCHED_TIMESLICE |
|
|
715 #if 0 == CYG_SCHED_UNIQUE_PRIORITIES |
|
|
716 |
|
|
717 // If timeslicing is enabled, call the scheduler to |
|
|
718 // handle it. But not if we have unique priorities. |
|
|
719 |
|
|
720 Cyg_Scheduler::scheduler.timeslice(); |
|
|
721 |
|
|
722 #endif |
|
|
723 #endif |
|
|
724 |
|
|
725 CYG_INSTRUMENT_CLOCK( TICK_END, |
|
|
726 rtc->current_value_lo(), |
|
|
727 rtc->current_value_hi()); |
|
|
728 |
|
|
729 } |
|
|
730 |
|
|
731 #endif |
|
|
732 |
|
|
733 // ------------------------------------------------------------------------- |
|
|
734 // EOF common/clock.cxx |