drivers/ecos_lpc2138_sja1000/time_slicer.c
changeset 0 4472ee7c6c3e
equal deleted inserted replaced
-1:000000000000 0:4472ee7c6c3e
       
     1 /*
       
     2 This file is part of CanFestival, a library implementing CanOpen Stack.
       
     3 
       
     4  Author: Christian Fortin (canfestival@canopencanada.ca)
       
     5 
       
     6 See COPYING file for copyrights details.
       
     7 
       
     8 This library is free software; you can redistribute it and/or
       
     9 modify it under the terms of the GNU Lesser General Public
       
    10 License as published by the Free Software Foundation; either
       
    11 version 2.1 of the License, or (at your option) any later version.
       
    12 
       
    13 This library is distributed in the hope that it will be useful,
       
    14 but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    16 Lesser General Public License for more details.
       
    17 
       
    18 You should have received a copy of the GNU Lesser General Public
       
    19 License along with this library; if not, write to the Free Software
       
    20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    21 */
       
    22 
       
    23 #include <stdlib.h>
       
    24 
       
    25 #include <sys/time.h>
       
    26 #include <signal.h>
       
    27 
       
    28 #include <cyg/kernel/kapi.h>
       
    29 #include <cyg/hal/hal_arch.h>
       
    30 
       
    31 #include "applicfg.h"
       
    32 
       
    33 #include <timer.h>
       
    34 
       
    35 
       
    36 #define max(a,b) a>b?a:b
       
    37 #define min(a,b) a<b?a:b
       
    38 
       
    39 
       
    40 // ---------  The timer table ---------
       
    41 s_timer_entry timers[MAX_NB_TIMER] = {{TIMER_FREE, NULL, NULL, 0, 0, 0},};
       
    42 TIMEVAL total_sleep_time = TIMEVAL_MAX;
       
    43 TIMER_HANDLE last_timer_raw = -1;
       
    44 
       
    45 cyg_alarm_t chrono_timer;
       
    46 cyg_alarm alarm_timer;
       
    47 cyg_handle_t alarm_handle_timer;
       
    48 cyg_handle_t rtclock, rtcounter;
       
    49 
       
    50 void init_timer(void)
       
    51 {
       
    52 	rtclock = cyg_real_time_clock();
       
    53 	cyg_clock_to_counter(rtclock, &rtcounter);
       
    54 
       
    55 	cyg_alarm_create(rtcounter,
       
    56                          &chrono_timer,
       
    57                          0, 
       
    58                          &alarm_handle_timer,
       
    59                          &alarm_timer);
       
    60 }
       
    61 
       
    62 
       
    63 unsigned int getElapsedTime(void)
       
    64 {
       
    65 	// HCS12 main timer :  Increment every 4 us.
       
    66 	return 0; // IO_PORTS_16(TCNTH);
       
    67 }
       
    68 
       
    69 
       
    70 void setTimer(TIMEVAL tm /* in ms? s? us? */)
       
    71 {
       
    72 /*
       
    73 	this function is required by the library to make the scheduler work
       
    74 	properly
       
    75 	it is called by SetAlarm() (in src/timer.c)
       
    76 
       
    77 	the interrupt vector must call TimeDispatch() (in src/timer.c)
       
    78 */
       
    79 	/*
       
    80 		value of alarm time for eCos
       
    81 		  1 = 10 msec
       
    82 		100 = 1 sec
       
    83 
       
    84 #define MS_TO_TIMEVAL(ms) ms/10
       
    85 #define US_TO_TIMEVAL(us) us*4
       
    86 
       
    87 	*/
       
    88 
       
    89 	cyg_alarm_initialize(alarm_handle_timer, tm, 0);
       
    90 }
       
    91 
       
    92 
       
    93 void chrono_timer(cyg_handle_t alarm, cyg_addrword_t data)
       
    94 {
       
    95 	int i;
       
    96 	int next_wakeup = TIMEVAL_MAX; // used to compute when should normaly occur next wakeup
       
    97 	// First run : change timer state depending on time
       
    98 	// Get time since timer signal
       
    99 	int overrun = getElapsedTime();
       
   100 	
       
   101 	int real_total_sleep_time = total_sleep_time + overrun;
       
   102 	
       
   103 	for(i=0; i <= last_timer_raw; i++)
       
   104 	{
       
   105 		s_timer_entry *row = (timers+i);
       
   106 
       
   107 		if (row->state & TIMER_ARMED) // if row is active
       
   108 		{
       
   109 			if (row->val <= real_total_sleep_time) // to be trigged
       
   110 			{
       
   111 				if (!row->interval) // if simply outdated
       
   112 				{
       
   113 					row->state = TIMER_TRIG; // ask for trig
       
   114 				}
       
   115 				else // or period have expired
       
   116 				{
       
   117 					// set val as interval, with overrun correction
       
   118 					row->val = row->interval - (overrun % row->interval);
       
   119 					row->state = TIMER_TRIG_PERIOD; // ask for trig, periodic
       
   120 					// Check if this new timer value is the soonest
       
   121 					next_wakeup = min(row->val,next_wakeup);
       
   122 				}
       
   123 			}
       
   124 			else
       
   125 			{
       
   126 				// Each armed timer value in decremented.
       
   127 				row->val -= real_total_sleep_time;
       
   128 
       
   129 				// Check if this new timer value is the soonest
       
   130 				next_wakeup = min(row->val,next_wakeup);
       
   131 			}
       
   132 		}
       
   133 	}
       
   134 	
       
   135 	// Remember how much time we should sleep.
       
   136 	total_sleep_time = next_wakeup;
       
   137 
       
   138 	// Set timer to soonest occurence
       
   139 	setTimer(next_wakeup);
       
   140 
       
   141 	// Then trig them or not.
       
   142 	for(i=0; i<=last_timer_raw; i++)
       
   143 	{
       
   144 		s_timer_entry *row = (timers+i);
       
   145 
       
   146 		if (row->state & TIMER_TRIG)
       
   147 		{
       
   148 			row->state &= ~TIMER_TRIG; // reset trig state (will be free if not periodic)
       
   149 			(*row->callback)(row->d, row->id); // trig !
       
   150 		}
       
   151 	}
       
   152 }
       
   153 
       
   154 
       
   155 
       
   156 
       
   157 TIMER_HANDLE SetAlarm(CO_Data* d, UNS32 id, TimerCallback_t callback, TIMEVAL value, TIMEVAL period)
       
   158 {
       
   159 	int i;
       
   160 	TIMER_HANDLE row_number = TIMER_NONE;
       
   161 
       
   162 	if (callback == NULL) // nothing to store
       
   163 		return TIMER_NONE;
       
   164 
       
   165 	// in order to decide new timer setting we have to run over all timer rows
       
   166 	
       
   167 	for(i=0; i <= last_timer_raw + 1 && i < MAX_NB_TIMER; i++)
       
   168 	{
       
   169 		s_timer_entry *row = (timers+i);
       
   170 
       
   171 		if (row->state == TIMER_FREE) // an empty row
       
   172 		{	// just store
       
   173 			row->callback = callback;
       
   174 			row->d = d;
       
   175 			row->id = id;
       
   176 			row->val = value;
       
   177 			row->interval = period;
       
   178 			row->state = TIMER_ARMED;
       
   179 
       
   180 			row_number = i;
       
   181 			break;
       
   182 		}
       
   183 	}
       
   184 	
       
   185 	if (row_number != TIMER_NONE) // if successfull
       
   186 	{
       
   187 		if (row_number == last_timer_raw + 1) last_timer_raw++;
       
   188 		
       
   189 		// set next wakeup alarm if new entry is sooner than others, or if it is alone
       
   190 		unsigned int real_timer_value = min(value, TIMEVAL_MAX);
       
   191 		unsigned int elapsed_time = getElapsedTime();
       
   192 
       
   193 		if (total_sleep_time > elapsed_time && total_sleep_time - elapsed_time > real_timer_value)
       
   194 		{
       
   195 			total_sleep_time = elapsed_time + real_timer_value;
       
   196 			setTimer(real_timer_value);
       
   197 		}
       
   198 
       
   199 		return row_number;
       
   200 	}
       
   201 
       
   202 	return TIMER_NONE;
       
   203 }
       
   204 
       
   205 // ---------  Use this to remove an alarm ---------
       
   206 TIMER_HANDLE DelAlarm(TIMER_HANDLE handle)
       
   207 {
       
   208 	if (handle != TIMER_NONE)
       
   209 	{
       
   210 		if (handle == last_timer_raw) 
       
   211 			last_timer_raw--;
       
   212 		timers[handle].state = TIMER_FREE; 		
       
   213 	}
       
   214 	else 
       
   215 	{
       
   216 	}
       
   217 
       
   218 	return TIMER_NONE;
       
   219 }