PIC24 Support Libraries
esos.c
Go to the documentation of this file.
1 /*
2  * "Copyright (c) 2008 Robert B. Reese, Bryan A. Jones, J. W. Bruce ("AUTHORS")"
3  * All rights reserved.
4  * (R. Reese, reese_AT_ece.msstate.edu, Mississippi State University)
5  * (B. A. Jones, bjones_AT_ece.msstate.edu, Mississippi State University)
6  * (J. W. Bruce, jwbruce_AT_ece.msstate.edu, Mississippi State University)
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation for any purpose, without fee, and without written agreement is
10  * hereby granted, provided that the above copyright notice, the following
11  * two paragraphs and the authors appear in all copies of this software.
12  *
13  * IN NO EVENT SHALL THE "AUTHORS" BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
15  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE "AUTHORS"
16  * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17  *
18  * THE "AUTHORS" SPECIFICALLY DISCLAIMS ANY WARRANTIES,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE "AUTHORS" HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
23  *
24  * Please maintain this header in its entirety when copying/modifying
25  * these files.
26  *
27  *
28  */
29 
30 
31 
32 // Documentation for this file. If the \file tag isn't present,
33 // this file won't be documented.
34 /** \file
35  * \brief Central code for Embedded Systems Operating System (ESOS)
36  *
37  */
38 
39 #include "esos.h"
40 
41 
42 //**********************************************************
43 // GLOBAL variables for ESOS to use/maintain
44 //**********************************************************
45 
46 // Tasks management variables
47 struct stTask __astUserTaskPool[MAX_NUM_USER_TASKS];
48 uint8_t __au8UserTaskStructIndex[MAX_NUM_USER_TASKS];
49 struct stTask __astChildTaskPool[MAX_NUM_CHILD_TASKS];
50 uint8_t __u8UserTasksRegistered;
51 uint8_t __u8ChildTasksRegistered;
52 uint16_t __u16NumTasksEverCreated;
53 
54 // ESOS timer managmentment variables
55 struct stTimer __astTmrSvcs[MAX_NUM_TMRS];
56 uint8_t __esos_u8TmrSvcsRegistered;
57 uint16_t __esos_u16TmrActiveFlags;
58 
59 #ifdef ESOS_USE_BULK_CDC_USB
60 static struct stTask __stUsbCommSystem;
61 #endif
62 
63 // ESOS task mail services
64 MAILBOX __astMailbox[MAX_NUM_USER_TASKS];
65 uint8_t __au8_MBData[MAX_NUM_USER_TASKS][MAX_SIZE_TASK_MAILBOX];
66 CBUFFER __astCircularBuffers[MAX_NUM_USER_TASKS];
67 
68 
69 // misc ESOS variables
70 uint16_t __esos_u16UserFlags, __esos_u16SystemFlags;
71 uint32_t __u32_esos_PRNG_Seed;
72 uint32_t __esos_u32FNVHash = 2166136261uL;
73 
74 /****************************************************************
75 ** Embedded Systems Operating System (ESOS) code
76 ****************************************************************/
77 /**
78  * Adds a task to the scheduler. Task will start executing at the
79  * next opportunity. (almost immediately)
80  * \param taskname name of task (argument to \ref ESOS_USER_TASK declaration
81  * \retval NULLPTR if no more tasks can execute at this time (scheduler is full)
82  * \retval TaskHandle the handle of the just registered and scheduled task
83  * \sa ESOS_USER_TASK
84  * \sa esos_UnregisterTask
85 */
87  uint8_t u8_i;
88  uint8_t u8_FoundFcn = FALSE;
89  uint8_t u8_IndexFcn;
90  uint8_t u8_IndexFree=0;
91  uint8_t u8_FoundFree = FALSE;
92 
93  if (__u8UserTasksRegistered < MAX_NUM_USER_TASKS) {
94  /* First, we will look to see if the request task
95  has already been allocated to a task from the pool.
96  If so, then let's just reactivate/reset/etc the task.
97  */
98  for (u8_i=0; u8_i<MAX_NUM_USER_TASKS; u8_i++) {
99  if (__astUserTaskPool[u8_i].pfn == taskname) {
100  u8_FoundFcn = TRUE;
101  u8_IndexFcn = u8_i;
102  break;
103  } // endof if()
104  /* While we are looping through, take note of the first unused task
105  we find in the pool. We will assign this slot to the new task if
106  we can't find it already allocated a (dead) slot
107  */
108  if ((!u8_FoundFree) && (__astUserTaskPool[u8_i].pfn == NULLPTR)) {
109  u8_FoundFree = TRUE;
110  u8_IndexFree = u8_i;
111  } // endof if()
112  } // endof for()
113 
114  /* OK. We looked at all the tasks in the pool. We either
115  * found the new task already allocated (u8_FoundFcn),
116  OR
117  * we did not. In this case, there are two cases:
118  # We found a dead/free task slot in our search (u8_FoundFree),
119  OR
120  # we did not. (All slots are already being used. WE ARE IN TROUBLE!)
121 
122  If we found the new task already (dead but allocated) in the pool, then we need to
123  1) initialize the task, its flags, and its mailbox, and
124  2) add the task to the task rotation
125  */
126  if (u8_FoundFcn) {
127  __ESOS_INIT_TASK( &__astUserTaskPool[u8_IndexFcn]); // reset the task state
128  __astUserTaskPool[u8_IndexFcn].flags = 0; // reset the task flags
129  ESOS_TASK_FLUSH_TASK_MAILBOX(&__astUserTaskPool[u8_IndexFcn]); // reset the task mailbox
130  __au8UserTaskStructIndex[__u8UserTasksRegistered] = u8_IndexFcn;
131  __u8UserTasksRegistered++;
132  // make sure this task has a non-zero task identifier
133  if ( __astUserTaskPool[u8_IndexFree].u16_taskID == 0 ) {
134  // we will simply assign a sequential task ID number (sorta like unix does for PIDs)
135  __u16NumTasksEverCreated++;
136  __astUserTaskPool[u8_IndexFree].u16_taskID = __u16NumTasksEverCreated;
137  } // endif
138  return &__astUserTaskPool[u8_IndexFcn];
139  } // endof if
140  /* We did NOT find our task already in the pool, so allocate a new struct
141  It has never been registered before, or it's location was garbage collected at some
142  point.
143 
144  If we found a free task slot in the pool, then give this free slot to the new task.
145  */
146  if (u8_FoundFree) {
147  __astUserTaskPool[u8_IndexFree].pfn = taskname; // attach task to the free slot
148  __ESOS_INIT_TASK(&__astUserTaskPool[u8_IndexFree]); // reset the task state
149  __astUserTaskPool[u8_IndexFree].flags = 0; // reset the task flags
150  ESOS_TASK_FLUSH_TASK_MAILBOX(&__astUserTaskPool[u8_IndexFree]); // reset the task mailbox
151  __au8UserTaskStructIndex[__u8UserTasksRegistered] = u8_IndexFree;
152  __u8UserTasksRegistered++;
153  // Since this is a "new" task, give it a new task ID number
154  __u16NumTasksEverCreated++;
155  __astUserTaskPool[u8_IndexFree].u16_taskID = __u16NumTasksEverCreated;
156  return &__astUserTaskPool[u8_IndexFree];
157  } // endof if
158  /* we did NOT find our function in the pool OR a free struct to use, so
159  we will return a NULLPTR for now. In the future, maybe the garbage can be called here
160  to find some space by looking for killed/dead tasks. (Current dead tasks are garbaged
161  at the end of a complete pool rotation. Possibly we can do an early garbage collection
162  here, but it will only help in very rare circumstances.)
163  */
164  return NULLPTR;
165  } else {
166  return NULLPTR;
167  } //end of if-else
168 }// end esos_RegisterTask()
169 
170 /**
171  * Removes the task from the scheduler
172  * \param taskname name of task (argument to \ref ESOS_USER_TASK declaration
173  * \retval TRUE if task was found in scheduler and removed
174  * \retval FALSE otherwise
175  * \sa ESOS_USER_TASK
176  * \sa esos_RegisterTask
177 */
179  uint8_t u8Status=FALSE;
180  uint8_t u8_i, u8_z;
181  ESOS_TASK_HANDLE pstNowTask;
182 
183  /* Search through the pool and find out where the task needing unregistering
184  is residing in the pool. Then, we will mark this slot as needing removal
185  and setting a flag for task pool repacking at the end of the current
186  rotation through the pool.
187  */
188  for (u8_i=0; u8_i<__u8UserTasksRegistered; u8_i++) {
189  // get next index from array so we can get the task handle
190  u8_z = __au8UserTaskStructIndex[u8_i];
191  /* check tasks that have been allocated (not a NULLIDX) and
192  not been garbage collected (not REMOVE_IDX) yet. If our
193  task is among them, the mark it to be garbaged collected
194  (REMOVE_IDX) at the next opportunity
195  */
196  if ((u8_z != NULLIDX) & (u8_z != REMOVE_IDX)) {
197  pstNowTask = &__astUserTaskPool[u8_z];
198  // If we find our task, mark it and signal ESOS to repack task pool
199  if (pstNowTask->pfn == taskname) {
200  __au8UserTaskStructIndex[u8_i] = REMOVE_IDX;
201  __esos_SetSystemFlag( __ESOS_SYS_FLAG_PACK_TASKS );
202  u8Status=TRUE;
203  break;
204  } // end if (pfn == taskname)
205  } // end if (!NULLIDX)
206  } // end for
207  return u8Status;
208 }// end esos_UnregisterTask()
209 
210 /**
211  * Find the (active) task handle for a given task function
212  * \param taskname name of task (argument to \ref ESOS_USER_TASK declaration
213  * \retval NULLPTR if task is not found among the active tasks
214  * \retval TaskHandle the handle to the task function requested
215  * \sa ESOS_USER_TASK
216  * \sa esos_RegisterTask
217  * \sa esos_UnregisterTask
218 */
220  uint8_t u8_i, u8_z;
221  ESOS_TASK_HANDLE pst_NowTask;
222  ESOS_TASK_HANDLE pst_ReturnTask = (ESOS_TASK_HANDLE) NULLPTR;
223 
224  /* Scan through the pool of "registered" tasks and see
225  if we can find the task function name requested
226  */
227  for (u8_i=0; u8_i<__u8UserTasksRegistered; u8_i++) {
228  // get next index from array so we can get the task handle
229  u8_z = __au8UserTaskStructIndex[u8_i];
230  /* check tasks that have been allocated (not a NULLIDX) and
231  not been garbage collected (not REMOVE_IDX) yet. If our
232  task is among them, then return the handle to the caller
233  */
234  if ((u8_z != NULLIDX) & (u8_z != REMOVE_IDX)) {
235  pst_NowTask = &__astUserTaskPool[u8_z];
236  // If we find our task, save the pstXXX so we can return it
237  if (pst_NowTask->pfn == taskname) {
238  pst_ReturnTask = pst_NowTask;
239  break;
240  } // end if (pfn == taskname)
241  } // end if (!NULLIDX)
242  } //end for
243  return pst_ReturnTask;
244 } //end esos_GetTaskHandle()
245 
246 /**
247  * Find the (active) task handle for a given task function
248  * \param u16_TaskID name of task (argument to \ref ESOS_USER_TASK declaration)
249  * \retval NULLPTR if task is not found among the active tasks
250  * \retval TaskHandle the handle to the task function requested
251  * \sa ESOS_USER_TASK
252  * \sa esos_RegisterTask
253  * \sa esos_UnregisterTask
254 */
256  uint8_t u8_i, u8_z;
257  ESOS_TASK_HANDLE pst_NowTask;
258  ESOS_TASK_HANDLE pst_ReturnTask = (ESOS_TASK_HANDLE) NULLPTR;
259 
260  /* Scan through the pool of "registered" tasks and see
261  if we can find the task function name requested
262  */
263  for (u8_i=0; u8_i<__u8UserTasksRegistered; u8_i++) {
264  // get next index from array so we can get the task handle
265  u8_z = __au8UserTaskStructIndex[u8_i];
266  /* check tasks that have been allocated (not a NULLIDX) and
267  not been garbage collected (not REMOVE_IDX) yet. If our
268  task is among them, then return the handle to the caller
269  */
270  if ((u8_z != NULLIDX) & (u8_z != REMOVE_IDX)) {
271  pst_NowTask = &__astUserTaskPool[u8_z];
272  // If we find our task, save the pstXXX so we can return it
273  if (pst_NowTask->u16_taskID == u16_TaskID) {
274  pst_ReturnTask = pst_NowTask;
275  break;
276  } // end if (pfn == taskname)
277  } // end if (!NULLIDX)
278  } //end for
279  return pst_ReturnTask;
280 } //end esos_GetTaskHandleFromID()
281 
282 
283 
284 // TODO: I DONT THINK I NEED TO STORE THE ACTUAL PFNs SINCE THE PARENT'S
285 // WAIT FUNCTION WILL DECOMPOSE INTO A CALL TO THE CHILD TASK AUTOMATICALLY.
286 //
287 // INVESTIGATE MORE!
288 //
289 // TODO: make sure childs get restarted if they yield and some other task
290 // executes in the meantime!
291 
292 /**
293 * Searches child task pool to find a free child task structure and returns
294 * a handle (pst) back to the caller
295 * \retval TaskHandle if a child task structure is available
296 * \retval ESOS_BAD_CHILD_TASK_HANDLE if no structures are available at this time
297 */
299  uint16_t u16_i = 0;
300 
301  while (u16_i < MAX_NUM_CHILD_TASKS) {
302  if (ESOS_IS_TASK_INITED( &__astChildTaskPool[u16_i]) )
303  return &__astChildTaskPool[u16_i];
304  u16_i++;
305  }
306  return NULLPTR;
307 }// end esos_u16GetFreeChildTaskStruct()
308 
309 
310 /**
311  * Sets the seed value in the ESOS pseudo-random number generator (PRNG).
312  * \note ESOS init code sets a seed value for the PRNG. If the application
313  * desires a sequence that is not predictable at each execution run,
314  * then the seed should be set <em>ONCE</em> with some value that is
315  * different with each execution. An idea is to have the user press
316  * a key during startup. The value of the ESOS tick when the user presses
317  * the key will be different each time. This number would make an
318  * ideal PRNG seed.
319  * \sa esos_GetRandomUint32
320  * See http://www.firstpr.com.au/dsp/rand31/ for more information
321  */
322 void esos_SetRandomUint32Seed(uint32_t u32_in) {
323  __u32_esos_PRNG_Seed = u32_in;
324 } // end esos_SetRandomUint32Seed()
325 
326 /**
327 * Returns a 31-bit pseudo-random number generated by the Park-Miller
328 * algorithm.
329  * \sa esos_SetRandomUint32Seed
330 * \note Visit http://www.firstpr.com.au/dsp/rand31/ for more information
331 */
332 uint32_t esos_GetRandomUint32(void) {
333  uint32_t hi, lo;
334 
335  lo = 16807 * ( __u32_esos_PRNG_Seed * 0xFFFF );
336  hi = 16807 * ( __u32_esos_PRNG_Seed >> 16 );
337  lo += (hi & 0x7FFF) << 16;
338  lo += (hi >> 15);
339  if (lo > 0x7FFFFFFF) lo -= 0x7FFFFFFF;
340  return (__u32_esos_PRNG_Seed = (uint32_t) lo );
341 } // end esos_getRandomUint32()
342 
343 
344 /*******************************************************************************
345 *
346 *
347 */
348 uint16_t esos_taskname_hash_u16( void* buf, uint16_t len ) {
349  unsigned char *bp = (unsigned char *)buf; /* start of buffer */
350  unsigned char *be = bp + len; /* beyond end of buffer */
351  uint32_t u32_temp = 2166136261uL;
352 
353  /*
354  * FNV-1 hash each octet in the buffer
355  */
356  while (bp < be) {
357  /* multiply by the 32 bit FNV magic prime mod 2^32 */
358  u32_temp += (u32_temp<<1) + (u32_temp<<4) + (u32_temp<<7) + (u32_temp<<8) + (u32_temp<<24);
359 
360  /* xor the bottom with the current octet */
361  u32_temp ^= (uint32_t)*bp++;
362  } // end while
363  return (uint16_t) ((u32_temp >> 16) ^ (u32_temp & 0xFFFF));
364 } // end esos_taskname_hash_u16
365 
366 
367 /**
368  * Create a 32-bit (uint32_t) hash value for a buffer of voids
369  * Routine maintains "state" in the form of variable __esos_u32FNVHash
370  * This "state" is used in all of the ESOS FNV hash functions.
371  * Based on the Fowler/Noll/Vo (FNV1a) hash algorithm and code provided
372  * at http://www.isthe.com/chongo/tech/comp/fnv/
373  * \param buf pointer to a buffer of voids
374  * \param len length of the buffer of voids
375  * \retval uint32_t value of the resulting hash
376  * \sa esos_string_hash_u32
377  * \sa esos_hash_u32_to_u16
378 */
379 uint32_t esos_buffer_hash_u32(void *buf, uint16_t len) {
380  unsigned char *bp = (unsigned char *)buf; /* start of buffer */
381  unsigned char *be = bp + len; /* beyond end of buffer */
382 
383  /*
384  * FNV-1 hash each octet in the buffer
385  */
386  while (bp < be) {
387 
388  /* multiply by the 32 bit FNV magic prime mod 2^32 */
389 #if defined(NO_FNV_GCC_OPTIMIZATION)
390  __esos_u32FNVHash *= FNV_32_PRIME;
391 #else
392  __esos_u32FNVHash += (__esos_u32FNVHash<<1) + (__esos_u32FNVHash<<4) + (__esos_u32FNVHash<<7) + (__esos_u32FNVHash<<8) + (__esos_u32FNVHash<<24);
393 #endif
394 
395  /* xor the bottom with the current octet */
396  __esos_u32FNVHash ^= (uint32_t)*bp++;
397  }
398 
399  /* return our new hash value */
400  return __esos_u32FNVHash;
401 }
402 
403 
404 /**
405  * Create a 32-bit (uint32_t) hash value for a provided string
406  * Routine maintains "state" in the form of variable __esos_u32FNVHash
407  * This "state" is used in all of the ESOS FNV hash functions.
408  * Based on the Fowler/Noll/Vo (FNV1a) hash algorithm and code provided
409  * at http://www.isthe.com/chongo/tech/comp/fnv/
410  * \param psz_str pointer to zero-terminated string
411  * \retval uint32_t value of the resulting hash
412  * \sa esos_string_hash_u32
413  * \sa esos_hash_u32_to_u16
414 */
415 uint32_t esos_string_hash_u32(char *psz_str) {
416  unsigned char *ch_s = (unsigned char *)psz_str; /* unsigned string */
417 
418  /*
419  * FNV-1 hash each octet in the buffer
420  */
421  while (*ch_s) {
422 
423  /* multiply by the 32 bit FNV magic prime mod 2^32 */
424 #if defined(NO_FNV_GCC_OPTIMIZATION)
425  __esos_u32FNVHash *= FNV_32_PRIME;
426 #else
427  __esos_u32FNVHash += (__esos_u32FNVHash<<1) + (__esos_u32FNVHash<<4) + (__esos_u32FNVHash<<7) + (__esos_u32FNVHash<<8) + (__esos_u32FNVHash<<24);
428 #endif
429 
430  /* xor the bottom with the current octet */
431  __esos_u32FNVHash ^= (uint32_t)*ch_s++;
432  }
433 
434  /* return our new hash value */
435  return __esos_u32FNVHash;
436 }
437 
438 inline uint16_t esos_hash_u32_to_u16(uint32_t u32_hash) {
439  return (uint16_t) ((u32_hash>>16) ^ (u32_hash&0xFFFF));
440 }
441 /********************************************************************************/
442 
443 /**
444 * Returns the number of tasks we can execute
445 * \retval N the number of tasks this version of ESOS can execute
446 */
448  return MAX_NUM_USER_TASKS;
449 } // end osGetMaxNumberTasks()
450 
451 /*
452 * Determine whether a period of time has elapsed. Users
453 * have no need to call this function. It is used by ESOS
454 * internally.
455 * \param u32_startTick system tick count when timer was created
456 * \param u32_period duration of period in system ticks
457 * \retval TRUE if the period of time has elapsed
458 * \retval FALSE if the period of time has not yet elapsed
459 */
460 uint16_t __esos_hasTickDurationPassed(uint32_t u32_startTick, uint32_t u32_period) {
461  uint32_t u32_delta, u32_current;
462 
463  u32_current = esos_GetSystemTick();
464  u32_delta = u32_current - u32_startTick;
465  if (u32_current < u32_startTick)
466  u32_delta += 0xFFFFFFFF; // account for rollover (DELTA=0xFFFFFFF-start+current)
467  if (u32_delta > u32_period)
468  return TRUE;
469  else
470  return FALSE;
471 } // end __esos_hasSystemTickDurationPassed()
472 
473 /*
474 * ESOS timer services callback function. HW-specific code
475 * that creates the system tick must call this function at
476 * every ESOS system tick.
477 */
478 void __esos_tmrSvcsExecute(void) {
479  uint8_t u8_cnt, u8_index;
480 
481  u8_cnt = __esos_u8TmrSvcsRegistered;
482  u8_index = 0;
483  while (u8_cnt) {
484  // if timer is running, update its structure and call it if necessary
485  if (esos_IsTimerRunning(u8_index)) {
486  __astTmrSvcs[u8_index].u32_cntDown--;
487  if (__astTmrSvcs[u8_index].u32_cntDown == 0 ) {
488  __astTmrSvcs[u8_index].u32_cntDown = __astTmrSvcs[u8_index].u32_period;
489  __astTmrSvcs[u8_index].pfn();
490  } //endif timer has expired
491  u8_cnt--; // denote we've serviced one of the active timers
492  } // endif IsTimerRunning
493  u8_index++; // move index to next timer in array
494  } // end while(u8_cnt)
495 } //end __esos_tmrSvcsExecute()
496 
497 /**
498  * Adds a timer to the ESOS timer service. Timer function will execute at its
499  * next opportunity. Timer functions must have \em void arguments and \em void
500  * returns.
501  * \param timername name under which timer was declared in \ref ESOS_USER_TIMER.
502  * and contains the code to run when software timer expires
503  * \param u32_period period of timer in system ticks (currently, milliseconds)
504  * \retval ESOS_TMR_FAILURE if no more timers can added at this time
505  * \retval timerhandle if timer service was registered
506  * \sa ESOS_USER_TIMER
507  * \sa esos_UnregisterTimer
508  * \sa esos_GetTimerHandle
509  * \sa esos_ChangeTimerPeriod
510  * \sa esos_IsTimerRunning
511  * \sa
512  *
513  */
514 ESOS_TMR_HANDLE esos_RegisterTimer( void (*timername)(void), uint32_t u32_period ) {
515  uint8_t u8_i;
516 
517  if ( esos_GetNumberRunningTimers() < MAX_NUM_TMRS) {
518  for (u8_i=0; u8_i<MAX_NUM_TMRS; u8_i++ ) {
519  if (!esos_IsTimerRunning(u8_i)) {
520  __astTmrSvcs[u8_i].pfn = timername;
521  __astTmrSvcs[u8_i].u32_period = u32_period;
522  __astTmrSvcs[u8_i].u32_cntDown = u32_period;
523  __esos_u8TmrSvcsRegistered++;
524  __esos_MarkTimerRunning( u8_i );
525  return u8_i;
526  } // endif IsTimerRunning
527  } // endfor
528  return ESOS_TMR_FAILURE;
529  } // endif
530  else
531  return ESOS_TMR_FAILURE;
532 } // end esos_RegisterTimer
533 
534 /**
535  * Removes a timer from the ESOS timer service.
536  * \param hnd_timer handle to timer to remove
537  * \retval FALSE if timer wasn't active in the first place
538  * \retval TRUE if timer was stopped and removed
539  * \sa esos_RegisterTimer
540  * \sa esos_GetTimerHandle
541  * \sa esos_ChangeTimerPeriod
542  */
544 
545  if ( esos_IsTimerRunning(hnd_timer) ) {
546  __astTmrSvcs[hnd_timer].pfn = NULLPTR;
547  __esos_u8TmrSvcsRegistered--;
548  __esos_MarkTimerStopped(hnd_timer);
549  return TRUE;
550  } else
551  return FALSE;
552 } //end esos_UnregisterTimer()
553 
554 /**
555  * Finds the timer handle to the provided and ACTIVE timer function
556  * \param pfnTmrFcn pointer to timer function (will execute each time timer expires)
557  * \retval ESOS_TMR_FAILURE could not find the function in the active timer list
558  * \retval timerHandle handle to timer
559  * \sa esos_RegisterTimer
560  * \sa esos_UnregisterTimer
561  * \sa esos_ChangeTimerPeriod
562  * \sa esos_IsTimerRunning
563  */
564 ESOS_TMR_HANDLE esos_GetTimerHandle( void (*pfnTmrFcn)(void) ) {
565  uint8_t u8_i=0;
566  uint8_t u8_cnt;
567 
568  u8_cnt = esos_GetNumberRunningTimers();
569  while (u8_cnt) {
570  if (esos_IsTimerRunning(u8_i) ) {
571  if ( __astTmrSvcs[u8_i].pfn == pfnTmrFcn ) return u8_i;
572  u8_cnt--;
573  } //endif
574  u8_i++;
575  } // endwhile
576  return ESOS_TMR_FAILURE;
577 } //end esos_GetTimerHandle()
578 
579 
580 /**
581  * Change a timer period.
582  * \param hnd_timer handle to timer whose period is to be changed
583  * \param u32_period new period for timer selected by mask
584  * \retval FALSE if timer is not currently running
585  * \retval TRUE if timer period was changed
586  * \sa esos_RegisterTimer
587  * \sa esos_UnregisterTimer
588  * \sa esos_GetTimerHandle
589  * \sa esos_IsTimerRunning
590  */
591 uint8_t esos_ChangeTimerPeriod( ESOS_TMR_HANDLE hnd_timer, uint32_t u32_period ) {
592 
593  if (esos_IsTimerRunning(hnd_timer) ) {
594  __astTmrSvcs[hnd_timer].u32_period = u32_period;
595  return TRUE;
596  } else return FALSE;
597 } //end esos_geTimerHandle()
598 
599 void __esosInit(void) {
600  uint8_t u8_i;
601 
602  // initialize the pool of available user tasks
603  for (u8_i=0; u8_i<MAX_NUM_USER_TASKS; u8_i++) {
604  __astUserTaskPool[u8_i].pfn = NULLPTR;
605  __au8UserTaskStructIndex[u8_i] = NULLIDX;
606  __astChildTaskPool[u8_i].pfn = NULLPTR;
607  // assign each possible user task a mailbox and initialize it
608  __astUserTaskPool[u8_i].pst_Mailbox = &__astMailbox[u8_i];
609  (__astUserTaskPool[u8_i].pst_Mailbox)->pst_CBuffer = &__astCircularBuffers[u8_i];
610  __esos_InitMailbox(__astUserTaskPool[u8_i].pst_Mailbox, &__au8_MBData[u8_i][0]);
611  }
612  __esos_u16TmrActiveFlags = 0;
613  for (u8_i=0; u8_i<MAX_NUM_TMRS; u8_i++) {
614  __astTmrSvcs[u8_i].pfn = NULLPTR;
615  }
616 
617  // no user tasks are currently registered
618  __u8UserTasksRegistered = 0;
619  // no child tasks are active
620  __u8ChildTasksRegistered = 0;
621  // no timer services are active
622  __esos_u8TmrSvcsRegistered = 0;
623  // initialize the ESOS pseudo-random number generator
624  // see value. Use MAX_NUM_USER_TASKS for now.
625  __u32_esos_PRNG_Seed = MAX_NUM_USER_TASKS;
626 
627  /* Call the user provided function to initialize the
628  * and start the ESOS system tick..
629  */
630  __esos_hw_InitSystemTick();
631 
632  // initialize the HW interrupts
633  // (This routine is considered HW specific, because
634  // we don't know the number of HW interrupts on the
635  // CPU at this point....)
636 #ifdef ESOS_USE_IRQS
637  _esos_hw_InitUserInterrupts();
638 #endif
639  /*
640  * Now, initialize one of the communication systems if
641  * the user has requested it in user_config.h
642  *
643  * TODO: At some point, I want to be able to run both comm
644  * systems independently so we can use USB and debug via
645  * RS232 or vice-versa. I'll worry about that later.
646  */
647 #ifdef ESOS_USE_BULK_CDC_USB
648  __esos_InitCommSystem();
649 #endif
650 #ifdef ESOS_USE_SERIAL_PORT
651  __esos_InitCommSystem();
652 #endif
653 
654  user_init();
655 
656 } // end osInit()
657 
658 main_t main(void) {
659  uint8_t u8TaskReturnedVal=0;
660  uint8_t u8i ,u8j, u8NumRegdTasksTemp;
661  ESOS_TASK_HANDLE pstNowTask;
662 
663  __esosInit();
664  /* Keep a running counter of number of tasks we've created
665  ** to serve as stupid/simple task identifier
666  */
667  __u16NumTasksEverCreated = 0;
668  while (TRUE) {
669  /* First, let ESOS get something done.....
670  * service communications, garbage collection, etc.
671  * Whatever a nice little OS needs to do.
672  */
673 
674  u8i = 0;
675  /* get the number of currently registered tasks.... we must make
676  * a local copy, because the tasks themselves may unregister and
677  * change the variable __u8UserTasksRegistered as they go!
678  */
679  u8NumRegdTasksTemp = __u8UserTasksRegistered;
680 
681  // if there are registered tasks, let them run (call them)
682  while ( u8i < u8NumRegdTasksTemp ) {
683  /* Get the next task up for execution. Call it and catch
684  its state (returned value) when it gives focus back.
685  We may need to do something depending on its new state,
686  e.g. if it has ended, we need to remove it from the rotation
687  */
688  pstNowTask = &__astUserTaskPool[__au8UserTaskStructIndex[u8i]];
689  u8TaskReturnedVal = pstNowTask->pfn( pstNowTask );
690  if (u8TaskReturnedVal == ESOS_TASK_ENDED) {
691  //printf ("Unregistering an ENDED protothread\n");
692  esos_UnregisterTask( pstNowTask->pfn );
693  } // endif
694  u8i++;
695  OS_ITERATE;
696  } //end while()
697 
698  /* we have completed a rotation through the set of active tasks
699  Now repack the pool (if necessary) to keep everything nice and
700  tight.
701  */
702  if (__esos_IsSystemFlagSet( __ESOS_SYS_FLAG_PACK_TASKS) ) {
703  /* Now, loop over the UserTasks and pack them into
704  the beginning of our arrays. We loop through the list
705  backwards.....
706 
707  Loop over the original number of registered tasks and
708  look for NULLPTRs. If you find one, scoot all the following
709  tasks down by one and make the last one a NULLPTR. Reduce
710  our count of tasks by one to make the next search shorter.
711 
712  NOTE: we can't "break" the for-loop search because there
713  may be more than one unregistered tasks in the pool
714  */
715  u8i = __u8UserTasksRegistered;
716  // TODO: CHANGE THIS TO A do{}while(u8i)
717  while(TRUE) {
718  pstNowTask = &__astUserTaskPool[u8i];
719  if (__au8UserTaskStructIndex[u8i] == REMOVE_IDX) {
720  for ( u8j=u8i+1; u8j<u8NumRegdTasksTemp; u8j++) {
721  __au8UserTaskStructIndex[u8j-1] = __au8UserTaskStructIndex[u8j];
722  } // end for
723  __au8UserTaskStructIndex[u8NumRegdTasksTemp-1] = NULLIDX;
724  u8NumRegdTasksTemp--;
725  } // end if
726  /* Have we hit the beginning of the task pool yet?
727  If not, decrement (do another).
728  If so, we are done (break)
729  */
730  if (u8i)
731  u8i--;
732  else
733  break;
734  } // end while
735  /* We have repacked the task pool (possibly multiple times), so update
736  the new number of registered tasks and clear the task PACK flag
737  */
738  __u8UserTasksRegistered=u8NumRegdTasksTemp; // set record the new number of registered tasks
739  __esos_ClearSystemFlag( __ESOS_SYS_FLAG_PACK_TASKS );
740  } // end if
741  } //end while
742 
743  OS_END;
744 
745 } //end main()
ESOS_TMR_HANDLE esos_GetTimerHandle(void(*pfnTmrFcn)(void))
Definition: esos.c:564
#define esos_GetSystemTick()
Definition: esos.h:307
uint32_t esos_buffer_hash_u32(void *buf, uint16_t len)
Definition: esos.c:379
ESOS_TASK_HANDLE esos_RegisterTask(uint8_t(*taskname)(ESOS_TASK_HANDLE pstTask))
Definition: esos.c:86
#define NULLIDX
Definition: all_generic.h:426
uint32_t esos_GetRandomUint32(void)
Definition: esos.c:332
ESOS_TMR_HANDLE esos_RegisterTimer(void(*timername)(void), uint32_t u32_period)
Definition: esos.c:514
#define ESOS_IS_TASK_INITED(TaskHandle)
Definition: esos_task.h:167
uint32_t esos_string_hash_u32(char *psz_str)
Definition: esos.c:415
uint8_t ESOS_TMR_HANDLE
Definition: esos.h:236
void user_init(void)
ESOS_TASK_HANDLE esos_GetTaskHandleFromID(uint16_t u16_TaskID)
Definition: esos.c:255
#define esos_IsTimerRunning(hndl)
Definition: esos.h:458
int main_t
Definition: esos.h:91
uint8_t esos_UnregisterTimer(ESOS_TMR_HANDLE hnd_timer)
Definition: esos.c:543
#define ESOS_TASK_FLUSH_TASK_MAILBOX(pstTask)
Definition: esos_mail.h:230
#define esos_GetNumberRunningTimers()
Definition: esos.h:445
uint8_t esos_GetMaxNumberTasks(void)
Definition: esos.c:447
ESOS_TASK_HANDLE esos_GetTaskHandle(uint8_t(*taskname)(ESOS_TASK_HANDLE pstTask))
Definition: esos.c:219
void esos_SetRandomUint32Seed(uint32_t u32_in)
Definition: esos.c:322
uint8_t esos_ChangeTimerPeriod(ESOS_TMR_HANDLE hnd_timer, uint32_t u32_period)
Definition: esos.c:591
uint8_t esos_UnregisterTask(uint8_t(*taskname)(ESOS_TASK_HANDLE pstTask))
Definition: esos.c:178
#define NULLPTR
Definition: all_generic.h:424
#define __ESOS_INIT_TASK(TaskHandle)
Definition: esos_task.h:143
unsigned char uint8_t
An abbreviation for an 8-bit unsigned integer.
Definition: dataXferImpl.h:194
#define MAX_NUM_CHILD_TASKS
Definition: esos.h:112
ESOS_TASK_HANDLE esos_GetFreeChildTaskStruct()
Definition: esos.c:298