PIC24 Support Libraries
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
app_example.c
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 #define ESOS_USE_IRQS
31 
32 // INCLUDEs go here (First include the main esos.h file)
33 // After that, the user can include what they need
34 #include "esos.h"
35 #ifdef __linux
36 #include "esos_pc.h"
37 #include "esos_pc_stdio.h"
38 #else
39 #include "esos_pic24.h"
40 #include "esos_pic24_rs232.h"
41 #endif
42 
43 // INCLUDE these so our printf and other PC hacks work
44 #include <stdio.h>
45 #include <sys/select.h>
46 #include <termios.h>
47 #include <unistd.h>
48 
49 // DEFINEs go here
50 
51 /*
52  * PROTOTYPEs go here
53  *
54  */
55 void reverseString(char *psz_s1, char *psz_s2);
56 uint32 randomNumInRange(uint32 u32_lo, uint32 u32_hi);
57 
58 // GLOBALs go here
59 // Generally, the user-created semaphores will be defined/allocated here
60 static uint8 psz_CRNL[3]= {0x0D, 0x0A, 0};
61 
62 
63 // timer globals
64 uint32 u32_myT1Count = 0;
65 uint8 LED1 = TRUE;
66 uint8 LED2 = TRUE;
67 
68 ESOS_SEMAPHORE(sem_BCanRun);
69 ESOS_SEMAPHORE(sem_CCanRun);
70 ESOS_SEMAPHORE(sem_mutex);
71 
72 struct stTask* pst_MyTasks[3];
73 
74 /*
75  * Simulate the timer ISR found on a MCU
76  * The PC doesn't have a timer ISR, so this task will periodically
77  * call the timer services callback instead.
78  * USED ONLY FOR DEVELOPMENT AND TESTING ON PC.
79  * Real MCU hardware doesn't need this task
80  */
81 ESOS_USER_TASK( __simulated_isr ) {
83  while (TRUE) {
84  // call the ESOS timer services callback just like a real H/W ISR would
85  __esos_tmrSvcsExecute();
87 
88  } // endof while(TRUE)
89  ESOS_TASK_END();
90 } // end child_task
91 
92 
93 /************************************************************************
94  * User supplied functions
95  ************************************************************************
96  */
97 
98 /*
99  * Returns a random number with a value between the two arguments.
100  *
101  * /todo Yes, I know this routine is cheesy. But, it works and
102  * I am in a really big hurry right now.
103  */
104 
105 uint32 randomNumInRange(uint32 u32_lo, uint32 u32_hi) {
106  uint32 u32_d1, u32_d2, u32_d4, u32_ret;
107  UINT32 U32_temp;
108 
109  while (TRUE) {
110  u32_d4 = esos_GetRandomUint32();
111  u32_ret = u32_lo + u32_d4;
112  if (u32_ret <= u32_hi) return u32_ret;
113 
114  U32_temp._uint32 = u32_d4;
115  u32_d2 = U32_temp.u16LoWord ^ U32_temp.u16HiWord;
116  u32_ret = u32_lo + u32_d2;
117  if (u32_ret <= u32_hi) return u32_ret;
118 
119  u32_d1 = U32_temp.u8LoLsb ^ U32_temp.u8LoMsb ^ U32_temp.u8HiLsb ^ U32_temp.u8HiMsb;
120  u32_ret = u32_lo + u32_d1;
121  if (u32_ret <= u32_hi) return u32_ret;
122  } //endwhile
123 } //end randomNumInRange
124 
125 
126 // user-created timer callback
127 ESOS_USER_TIMER( swTimerCounter ) {
128  u32_myT1Count++;
129 } //endof swTimerCounter
130 
131 // user-created timer callback
132 ESOS_USER_TIMER( swTimerLED ) {
133  LED2 = !LED2;
134  printf("\a");
135  fflush(stdout);
136 } //endof swTimerLED
137 
138 // user-created timer callback
139 ESOS_USER_TIMER( swTimerPrintA ) {
140  static uint32 u32_cnt;
141 
142  printf("A:%d\n", u32_cnt++);
143  fflush(stdout);
144 } //endof swTimerPrintA
145 
146 ESOS_USER_TIMER( swTimerPrintB ) {
147  static uint32 u32_cnt;
148 
149  printf("B:%d\n", u32_cnt++);
150  fflush(stdout);
151 } //endof swTimerPrintB
152 
153 ESOS_USER_TIMER( swTimerPrintC ) {
154  static uint32 u32_cnt;
155 
156  printf("C:%d\n", u32_cnt++);
157  fflush(stdout);
158 } //endof swTimerPrintC
159 
160 /* ======================================
161  * Three tasks to run cooperatively.
162  * They used printf() since I want the routines
163  * to fit a screen. Plus, this is for the PC
164  * so we can tolerate printf()'s hugeness.
165  * ======================================
166  */
167 ESOS_USER_TASK( task1 ) {
168  uint32 u32_rnd;
169 
170  ESOS_TASK_BEGIN();
171  while (TRUE) {
172  u32_rnd = 1+(0x0F & esos_GetRandomUint32());
173  u32_rnd <<= 8;
174  printf("T1 (%d)\n", u32_rnd);
175  ESOS_TASK_WAIT_TICKS( u32_rnd);
176  } // endof while(TRUE)
177  ESOS_TASK_END();
178 } // end task1()
179 
180 ESOS_USER_TASK( task2 ) {
181  uint32 u32_rnd;
182 
183  ESOS_TASK_BEGIN();
184  while (TRUE) {
185  u32_rnd = 1+(0x0F & esos_GetRandomUint32());
186  u32_rnd <<= 9;
187  printf("T2 (%d)\n", u32_rnd);
188  ESOS_TASK_WAIT_TICKS( u32_rnd);
189  } // endof while(TRUE)
190  ESOS_TASK_END();
191 } // end task2()
192 
193 ESOS_USER_TASK( task3 ) {
194  uint32 u32_rnd;
195 
196  ESOS_TASK_BEGIN();
197  while (TRUE) {
198  u32_rnd = 1+(0x0F & esos_GetRandomUint32());
199  u32_rnd <<= 10;
200  printf("T3 (%d)\n", u32_rnd);
201  ESOS_TASK_WAIT_TICKS( u32_rnd);
202  } // endof while(TRUE)
203  ESOS_TASK_END();
204 } // end task3()
205 
206 /* ======================================
207  * Three tasks to run cooperatively.
208  * They used printf() since I want the routines
209  * to fit a screen. Plus, this is for the PC
210  * so we can tolerate printf()'s hugeness.
211  * ======================================
212  */
213 ESOS_USER_TASK( taskSemA ) {
214  uint32 u32_rnd;
215  static u8_cnt;
216 
217  ESOS_TASK_BEGIN();
218  u8_cnt = 0;
219  while (TRUE) {
220  u8_cnt++;
221  if (u8_cnt == 10) {
222  ESOS_SIGNAL_SEMAPHORE( sem_BCanRun, 1 );
223  }
224  if (u8_cnt == 20) {
225  ESOS_SIGNAL_SEMAPHORE( sem_CCanRun, 1 );
226  }
227  u32_rnd = 1+(0x0F & esos_GetRandomUint32());
228  u32_rnd <<= 7;
229  printf("taskSemA %d (%d)\n", u8_cnt, u32_rnd);
230  ESOS_TASK_WAIT_TICKS( u32_rnd);
231  } // endof while(TRUE)
232  ESOS_TASK_END();
233 } // end taskSemA()
234 
235 ESOS_USER_TASK( taskSemB ) {
236  uint32 u32_rnd;
237  static u8_cnt;
238 
239  ESOS_TASK_BEGIN();
240  u8_cnt = 0;
241  ESOS_TASK_WAIT_SEMAPHORE( sem_BCanRun, 1 );
242  while (TRUE) {
243  u8_cnt++;
244  u32_rnd = 1+(0x0F & esos_GetRandomUint32());
245  u32_rnd <<= 8;
246  printf("taskSemB %d (%d)\n", u8_cnt, u32_rnd);
247  ESOS_TASK_WAIT_TICKS( u32_rnd);
248  } // endof while(TRUE)
249  ESOS_TASK_END();
250 } // end taskSemB()
251 
252 ESOS_USER_TASK( taskSemC ) {
253  uint32 u32_rnd;
254  static u8_cnt;
255 
256  ESOS_TASK_BEGIN();
257  u8_cnt = 0;
258  ESOS_TASK_WAIT_SEMAPHORE( sem_CCanRun, 1 );
259  while (TRUE) {
260  u8_cnt++;
261  u32_rnd = 1+(0x0F & esos_GetRandomUint32());
262  u32_rnd <<= 8;
263  printf("taskSemC %d (%d)\n", u8_cnt, u32_rnd);
264  ESOS_TASK_WAIT_TICKS( u32_rnd);
265  } // endof while(TRUE)
266  ESOS_TASK_END();
267 } // end taskSemC()
268 
269 
270 ESOS_USER_TASK( taskMutexA ) {
271  uint32 u32_rnd;
272  static u8_cnt;
273 
274  ESOS_TASK_BEGIN();
275  u8_cnt = 0;
276  while (TRUE) {
277  ESOS_TASK_WAIT_SEMAPHORE( sem_mutex, 1);
278  u8_cnt++;
279  u32_rnd = 1+(0x0F & esos_GetRandomUint32());
280  u32_rnd <<= 8;
281  printf("taskMutexA %d (%d)\n", u8_cnt, u32_rnd);
282  ESOS_SIGNAL_SEMAPHORE( sem_mutex, 1);
283  ESOS_TASK_WAIT_TICKS( u32_rnd);
284  } // endof while(TRUE)
285  ESOS_TASK_END();
286 } // end taskMutexA()
287 
288 
289 ESOS_USER_TASK( taskMutexB ) {
290  uint32 u32_rnd;
291  static u8_cnt;
292 
293  ESOS_TASK_BEGIN();
294  u8_cnt = 0;
295  while (TRUE) {
296  ESOS_TASK_WAIT_SEMAPHORE( sem_mutex, 1);
297  u8_cnt++;
298  u32_rnd = 1+(0x0F & esos_GetRandomUint32());
299  u32_rnd <<= 8;
300  printf("taskMutexB %d (%d)\n", u8_cnt, u32_rnd);
301  ESOS_SIGNAL_SEMAPHORE( sem_mutex, 1);
302  ESOS_TASK_WAIT_TICKS( u32_rnd );
303  } // endof while(TRUE)
304  ESOS_TASK_END();
305 } // end taskMutexB()
306 
307 
308 /*
309  * A beeping/blinking ESOS task
310  *
311  * Downers to using a task..... Can't easily
312  * change the timer period. A S/W timer is
313  * a bit more flexible and more responsive.
314  * But, a S/W timer can wreak much more havoc
315  * than its task counterpart.
316  */
317 ESOS_USER_TASK( task_LED ) {
318  ESOS_TASK_BEGIN();
319  while (TRUE) {
320  LED2 = !LED2;
321  ESOS_TASK_WAIT_TICKS( 1000);
322  printf("\a");
323  fflush(stdout);
324  } // endof while(TRUE)
325  ESOS_TASK_END();
326 } // end upper_case()
327 
328 /*
329  * task to access and print the global variable
330  * incremented by SW/ timer. If the task were
331  * modify this variable, we'd need a semaphore.
332  * As it stands, this task only reads it, so we're
333  * safe.
334  */
335 ESOS_USER_TASK( query_swTmrCnt ) {
336  static uint8 u8_char;
337 
338  ESOS_TASK_BEGIN();
339  while (TRUE) {
342  ESOS_TASK_WAIT_ON_GET_UINT8( u8_char );
344  if (u8_char == ' ') {
350  } //endif()
351  } // endof while(TRUE)
352  ESOS_TASK_END();
353 } // end upper_case()
354 
355 /*
356  * Read "in" stream and make it upper-case one
357  * character at a time.
358  */
359 ESOS_USER_TASK( upper_case ) {
360  static uint8 u8_char;
361 
362  ESOS_TASK_BEGIN();
363  while (TRUE) {
366  ESOS_TASK_WAIT_ON_GET_UINT8( u8_char );
368  if ((u8_char >= 'a') && (u8_char <= 'z') )
369  u8_char = u8_char - 'a' + 'A';
374  } // endof while(TRUE)
375  ESOS_TASK_END();
376 } // end upper_case()
377 
378 /*
379  * Read "in" stream and make it upper-case the whole
380  * string at a time. The ESOS comm system will return
381  * an in-string to us when it hits a zero-terminator or
382  * a suitable return/linefeed character.
383  */
384 ESOS_USER_TASK( upper_case2 ) {
385  static uint8 u8_i;
386  static uint8 au8_x[257];
387  static uint8 au8_y[257];
388 
389  ESOS_TASK_BEGIN();
390  while (TRUE) {
395  u8_i = 0;
396  while (TRUE) {
397  if ((au8_x[u8_i] >= 'a') && (au8_x[u8_i] <= 'z') )
398  au8_y[u8_i] = au8_x[u8_i] - 'a' + 'A';
399  else
400  au8_y[u8_i] = au8_x[u8_i];
401  if (au8_x[u8_i] == 0) break;
402  u8_i++;
403  }
408  } // endof while(TRUE)
409  ESOS_TASK_END();
410 } // end upper_case()
411 
412 /*
413  * Read "in" stream and reverses it
414  */
415 ESOS_USER_TASK( reverse_string ) {
416  static uint8 u8_char;
417  static char sz_in[257];
418  static char sz_out[257];
419 
420  ESOS_TASK_BEGIN();
421  while (TRUE) {
426  reverseString( sz_in, sz_out );
432  } // endof while(TRUE)
433  ESOS_TASK_END();
434 } // end upper_case()
435 
436 /*
437  * Inputs a string, outputs the reverse. This file is used
438  * in three MPLAB projects:
439  * reverse_string.mcp - polled RX, TX I/O
440  * uartrx_fifo.mcp - interrupt RX, polled TX I/O
441  * uartrxtx_fifo.mcp - interrupt RX, interrupt TX I/O
442  * Interrupt RX inChar1() is selected by defining UART1_RX_INTERRUPT macro
443  * Interrupt TX outChar1() is selected by defining UART1_TX_INTERRUPT macro
444  * These macros are defined in their respective MPLAB projects.
445 */
446 void reverseString(char *psz_s1, char *psz_s2) {
447  char *psz_s1end;
448  if (!(*psz_s1)) {
449  *psz_s2 = 0; //psz_s1 is empty, return.
450  return;
451  }
452  psz_s1end = psz_s1;
453  //find end of first string
454  while (*psz_s1end) psz_s1end++;
455  psz_s1end--; //backup one to first non-zero byte
456  //now copy to S2 in reverse order
457  while (psz_s1end != psz_s1) {
458  *psz_s2 = *psz_s1end;
459  psz_s1end--;
460  psz_s2++;
461  }
462  //copy last byte
463  *psz_s2 = *psz_s1end;
464  psz_s2++;
465  //mark end of string
466  *psz_s2 = 0;
467 }
468 
469 /******************************************************************************
470  * Function: void user_init(void)
471  *
472  * PreCondition: None
473  *
474  * Input: None
475  *
476  * Output: None
477  *
478  * Side Effects: None
479  *
480  * Overview: user_init is a centralized initialization routine where
481  * the user can setup their application. It is called
482  * automagically by ES_OS during the operating system
483  * initialization.
484  *
485  * Note: The user should set up any state machines and init
486  * all application variables. They can also turn on
487  * any needed peripherals here.
488  *
489  * The user SHALL NOT mess with the interrupt hardware
490  * directly!!! The ES_OS must be aware of the interrupts
491  * and provides osXXXXXXX functions for the user to use.
492  * Using these ES_OS-provided functions, the user may
493  * (and probably should) initialize, register, and enable
494  * interrupts in this routine.
495  *
496  * Furthermore, the user should register AT LEAST one
497  * user application task here (via esos_RegisterTask) or
498  * the ES_OS scheduler will have nothing to schedule
499  * to run when this function returns.
500  *
501  *****************************************************************************/
502 void user_init(void) {
503  uint16* pu16_ptr;
504  uint16 u16_junk;
505  ESOS_TMR_HANDLE tmrhnd_t1,tmrhnd_t2,tmrhnd_t3;
506 
507  __esos_unsafe_PutString( HELLO_MSG );
508 
509  /*
510  * Now, let's get down and dirty with ESOS and our user tasks
511  *
512  * Once tasks are registered, they will start executing in
513  * the ESOS scheduler.
514  */
515 
516  // register our little ESOS task to mimic MCU's TIMER T1 IRQ which kicks off
517  // the ESOS S/W timers when they expire
518  esos_RegisterTask( __simulated_isr );
519 
520  /* ====================================================================
521  * REGISTER SOME USER TASKS
522  * ====================================================================
523  */
524 
525 
526 // here are several combinations of tasks that should work together
527 #if 0
528  esos_RegisterTask( upper_case );
529 #endif
530 #if 0
531  tmrhnd_t1 = esos_RegisterTimer( swTimerLED, 500 );
532 #endif
533 #if 0
534  esos_RegisterTask( upper_case );
535  tmrhnd_t1 = esos_RegisterTimer( swTimerLED, 500 );
536 #endif
537 #if 0
538  esos_RegisterTask( query_swTmrCnt );
539  tmrhnd_t1 = esos_RegisterTimer( swTimerLED, 500 );
540  tmrhnd_t2 = esos_RegisterTimer( swTimerCounter, 10 );
541 #endif
542 #if 0
543  esos_RegisterTask( upper_case2 );
544  tmrhnd_t1 = esos_RegisterTimer( swTimerLED, 1000 );
545 #endif
546 #if 0
547  esos_RegisterTask( reverse_string );
548  tmrhnd_t1 = esos_RegisterTimer( swTimerLED, 1000 );
549 #endif
550 #if 0
551  esos_RegisterTimer( swTimerLED, 1000 );
552  esos_RegisterTask( task1 );
553  esos_RegisterTask( task2 );
554  esos_RegisterTask( task3 );
555 #endif
556 #if 0
557  esos_RegisterTask( reverse_string );
558  esos_RegisterTask( task_LED );
559 #endif
560 #if 0
561  esos_RegisterTask( upper_case2 );
562  esos_RegisterTask( task_LED );
563  tmrhnd_t1 = esos_RegisterTimer( swTimerPrintA, 400 );
564  tmrhnd_t2 = esos_RegisterTimer( swTimerPrintB, 500 );
565  tmrhnd_t3 = esos_RegisterTimer( swTimerPrintC, 750 );
566 #endif
567 
568 // The whole enchilada! Well, maybe not a whole one, but a big one!
569 #if 0
570  esos_RegisterTask( query_swTmrCnt );
571  esos_RegisterTimer( swTimerCounter, 10 );
572  esos_RegisterTimer( swTimerLED, 1000 );
573  tmrhnd_t1 = esos_RegisterTimer( swTimerPrintA, 400 );
574  tmrhnd_t2 = esos_RegisterTimer( swTimerPrintB, 500 );
575  tmrhnd_t3 = esos_RegisterTimer( swTimerPrintC, 750 );
576  esos_RegisterTask( task1 );
577  esos_RegisterTask( task2 );
578  esos_RegisterTask( task3 );
579 #endif
580 
581 // Another big enchilada
582 #if 0
583  esos_RegisterTask( reverse_string );
584  esos_RegisterTimer( swTimerLED, 1000 );
585  tmrhnd_t1 = esos_RegisterTimer( swTimerPrintA, 400 );
586  tmrhnd_t2 = esos_RegisterTimer( swTimerPrintB, 500 );
587  tmrhnd_t3 = esos_RegisterTimer( swTimerPrintC, 750 );
588  esos_RegisterTask( task1 );
589  esos_RegisterTask( task2 );
590  esos_RegisterTask( task3 );
591 #endif
592 
593 #if 0
594  ESOS_INIT_SEMAPHORE(sem_BCanRun, 0);
595  ESOS_INIT_SEMAPHORE(sem_CCanRun, 0);
596  esos_RegisterTask( taskSemA );
597  esos_RegisterTask( taskSemB );
598  esos_RegisterTask( taskSemC );
599 #endif
600 
601 #if 1
602  // test code based on mutex semaphore problem
603  // descried by Jeff Brantley
604  ESOS_INIT_SEMAPHORE(sem_mutex, 1);
605  esos_RegisterTask( taskMutexA );
606  esos_RegisterTask( taskMutexB );
607 #endif
608 
609 } // end user_init()