app_reverse.c - demonstrates a user task that reverses a string

ESOS application program to recreate the “reverse” program reverse_string.c in Chapter 10. (See Figure 10.16 in the text.) “Reverse” program waits for a string from the UART, reverses the string using the reverseString() function, and then sends the reversed string out to the UART.

Use this program to test your UART connection under ESOS

Application also has a flashing LED on RB15. Flashing LED is generated by a >user task that runs simultaneously with the echo task above.

Note

Demonstrates multitasking and communications services under ESOS

 
INCLUDEs go here (First include the main esos.h file)
After that, the user can include what they need
#include    "esos.h"
#ifdef __linux
#include    "esos_pc.h"
#include    "esos_pc_stdio.h"
 

INCLUDE these so that printf() and our PC hacks work

#include <stdio.h>
#include <sys/select.h>
#include <termios.h>
#include <unistd.h>
#else
#include    "esos_pic24.h"
#include    "esos_pic24_rs232.h"
#endif
 

DEFINEs go here

#ifndef __linux
#define   CONFIG_LED1()   CONFIG_RB15_AS_DIG_OUTPUT()
#define   LED1            _LATB15
#else
#define   CONFIG_LED1()   printf("called CONFIG_LED1()\n");
uint8_t     LED1 = TRUE;      // LED1 is initially "on"
#endif
 

PROTOTYPEs go here

void reverseString(char *psz_s1, char *psz_s2);
 
GLOBALs go here
Generally, the user-created semaphores will be defined/allocated here
 
#ifdef __linux
Simulate the timer ISR found on a MCU
The PC doesn’t have a timer ISR, so this task will periodically call the timer services callback instead. USED ONLY FOR DEVELOPMENT AND TESTING ON PC. Real MCU hardware doesn’t need this task
ESOS_USER_TASK( __simulated_isr ) {
  ESOS_TASK_BEGIN();
  while (TRUE) {

call the ESOS timer services callback just like a real H/W ISR would

    __esos_tmrSvcsExecute();
    ESOS_TASK_WAIT_TICKS( 1 );

  } // endof while(TRUE)
  ESOS_TASK_END();
} // end child_task
#endif

/************************************************************************
 * User supplied functions
 ************************************************************************
 */

/**
 * An ESOS task to mimic the heartbeat LED found
 * in the PIC24 support library code used in Chapters 8-13.
 *
 * Toggle LED1, wait 250ms, repeat forever.
 *
 * \note Since this heartbeat is performed in an ESOS task,
 * a flashing LED indicates that the ESOS scheduler is still
 * running properly.  If the LED quits flashing, the ESOS
 * scheduler is no longer rotating through the runnable task
 * list.  The most likely reason is that some task has ceased
 * "yielding" the processor, and is caught in some deadlock
 * or otherwise infinite loop.
 * \hideinitializer
 */
ESOS_USER_TASK(heartbeat_LED) {
  ESOS_TASK_BEGIN();
  while (TRUE) {
    LED1 = !LED1;
#ifdef __linux
    if (LED1) {
      printf("\a");
      fflush(stdout);
    }
#endif
    ESOS_TASK_WAIT_TICKS( 500 );
  } // endof while(TRUE)
  ESOS_TASK_END();
} // end upper_case()

/**
 * Read an entire string from the "in" stream, reverse the string
 * and send new string out the "out" stream
 */
ESOS_USER_TASK( reverse_string ) {
  static char            sz_in[257];
  static char            sz_out[257];

  ESOS_TASK_BEGIN();
  while (TRUE) {
    ESOS_TASK_WAIT_ON_AVAILABLE_IN_COMM();
    ESOS_TASK_WAIT_ON_GET_STRING( sz_in );
    ESOS_TASK_SIGNAL_AVAILABLE_IN_COMM();
    reverseString( sz_in, sz_out );
    ESOS_TASK_WAIT_ON_AVAILABLE_OUT_COMM();
    ESOS_TASK_WAIT_ON_SEND_STRING( sz_out );
    ESOS_TASK_WAIT_ON_SEND_UINT8('\n');
    ESOS_TASK_SIGNAL_AVAILABLE_OUT_COMM();
  } // endof while(TRUE)
  ESOS_TASK_END();
} // end reverse_string()
 
 

Inputs a string, outputs the reverse. This file is used in three MPLAB projects:

  • reverse_string.mcp - polled RX, TX I/O
  • uartrx_fifo.mcp - interrupt RX, polled TX I/O
  • uartrxtx_fifo.mcp - interrupt RX, interrupt TX I/O

Interrupt RX inChar1() is selected by defining UART1_RX_INTERRUPT macro Interrupt TX outChar1() is selected by defining UART1_TX_INTERRUPT macro These macros are defined in their respective MPLAB projects.

EXACTLY THE SAME ROUTINE AS USED IN CHAPTER 10. PLACED IN THIS SOURCE FILE FOR CONVENIENCE ONLY!!!

void reverseString(char *psz_s1, char *psz_s2) {
  char *psz_s1end;
  if (!(*psz_s1)) {
    *psz_s2 = 0;  //psz_s1 is empty, return.
    return;
  }
  psz_s1end = psz_s1;
  //find end of first string
  while (*psz_s1end) psz_s1end++;
  psz_s1end--;      //backup one to first non-zero byte
  //now copy to S2 in reverse order
  while (psz_s1end != psz_s1) {
    *psz_s2 = *psz_s1end;
    psz_s1end--;
    psz_s2++;
  }
  //copy last byte
  *psz_s2 = *psz_s1end;
  psz_s2++;
  //mark end of string
  *psz_s2 = 0;
}


/****************************************************
 *  user_init()
 ****************************************************
 */
void user_init(void) {
 

Call the hardware-provided routines to print the HELLO_MSG to the screen. Must use this call because the ESOS communications subsystems is not yet fully initialized, since this call is in user_init()

In general, users should call hardware-specific function like this.

  __esos_unsafe_PutString( HELLO_MSG );

#ifdef __linux

register our little ESOS task to mimic MCU’s TIMER T1 IRQ which kicks off the ESOS S/W timers when they expire

  esos_RegisterTask( __simulated_isr );
#endif
 

configure our hardware to support to support our application

  CONFIG_LED1();
 

user_init() should register at least one user task

  esos_RegisterTask(heartbeat_LED);
  esos_RegisterTask(reverse_string);

} // end user_init()