A simple RTOS for microcontrollers based upon concepts of FreeRTOS

This file is part of SimpleRTOS2

by Isaac Marino Bavaresco

This is file "Test\TestTasks-PIC24.c"

/*============================================================================*/
/*
SimpleRTOS - Very simple RTOS for Microcontrollers - PIC24 port
v2.00 (2014-01-21)
isaacbavaresco@yahoo.com.br
*/
/*============================================================================*/
/*
 Copyright (c) 2007-2014, Isaac Marino Bavaresco
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Neither the name of the author nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*============================================================================*/
#include <string.h>
#include "../SimpleRTOS/SimpleRTOS.h"
#include "../SimpleRTOS/Mutex.h"
#include "../SimpleRTOS/SerialPIC24.h"
/*============================================================================*/
#include "Test.h"
/*============================================================================*/
mutex_t Mutex = { NULL, NULL, 0, 0 };
/*============================================================================*/
void MutexTask1( void *param )
    {
    static const char   Message[] = "Hello world!\r\n";
    const char          *p;
    int                 i;

    while( 1 )
        {
        /* We will wait undefinitely until we get the mutex. */
        if( MutexTake( &Mutex, -1 ))
            {
            /* Transmit the whole string. */
            for( i = strlen( Message ), p = Message; i; i--, p++ )
                /* Transmit one char. While there is no room for new chars... */
                SerialTransmit( 1, *p, -1 );
#if 0
            /* Wait for the last byte to be transmitted. */
            while( TransmitInProgress() )
                vSleep( 1 );
#endif
            /* Let's punish the other task a little. */
            vSleep( 31 );

            /* Do not forget to give the mutex back. */
            MutexGive( &Mutex, 1 );
            }
        vSleep( 1 );
        }
    }
/*============================================================================*/
void MutexTask2( void *param )
    {
    static const char   Message[] = "I took over the world!\r\n";
    const char          *p;
    int                 i;

    while( 1 )
        {
        /* Try to take the mutex within a narrow time window */
        /* As the other task takes much more time, this one will get */
        /* the mutex less often. */
        if( MutexTake( &Mutex, -1 ))
            {
            /* Transmit the whole string. */
            for( i = strlen( Message ), p = Message; i; i--, p++ )
                /* While there is no room for new chars... */
                SerialTransmit( 1, *p, -1 );

            vSleep( 2 );

            /* Do not forget to give the mutex back. */
            MutexGive( &Mutex, 1 );
            }
        else
            vSleep( 2 );
        }
    }
/*============================================================================*/
/* Sort of a "poor man's" SIGNAL. */
int Die     = 0;

int Alive   = 0;
/*============================================================================*/
void SuicideTask( void *param )
    {

    /* Make sure the loop will repeat at least once. */
    Die = 0;

    while( 1 )
        {
        /* Somebody told us to die... */
        if( Die )
            {
            /* Clean-up before exitting. */
/*          LATAbits.LATA0  = 0; */
            Alive           = 0;
            /* Die pigy, die. */
            DeleteTask( NULL );
            }

        /* Just a silly thing to do. */
/*      LATAbits.LATA0 = ! LATAbits.LATA0; */

        vSleep( 2 );
        }
    }
/*============================================================================*/
void VictimTask( void *param )
    {
    while( 1 )
        {
        /* Another silly thing. */
/*      LATAbits.LATA1     = ! LATAbits.LATA1; */
        vSleep( 3 );
        }
    }
/*============================================================================*/
void TaskRX( void *param )
    {
    context_t   *Victim = NULL;
    int         i;

    while( 1 )
        {
        /* Wait for a character. */
        i = SerialReceive( 1, -1 );

        switch( i )
            {
            /* Start the suicide task. */
            case 0x73 /*'s'*/:
                /* We should not create an already created task. */
                if( ! Alive )
                    {
                    /* The task was created succesfully... */
                    if( CreateTask( Stacks[4], sizeof Stacks[4], NULL, GetAddress( SuicideTask ), 1 ) != NULL )
                        /* ... flag it. */
                        Alive   = 1;
                    }
                break;

            /* Tell the suicide task to die. */
            case 0x64 /*'d'*/:
                Die     = 1;
                break;

            /* Create the victim task. */
            case 0x76 /*'v'*/:
                /* If the task is not already created... */
                if( Victim == NULL )
                    {
                    /* ... create it. */
                    Victim = CreateTask( Stacks[5], sizeof Stacks[5], NULL, GetAddress( VictimTask ), 1 );
                    }
                break;

            /* Kill the victim task. */
            case 0x6b /*'k'*/:
                /* If the task is alive... */
                if( Victim != NULL )
                    {
                    /* ... kill it... */
                    DeleteTask( Victim );
                    /* ... and flag it. */
                    Victim  = NULL;
                    }
                break;
            }
        }
    }
/*============================================================================*/
/*

At least one tasks must never block (i.e. call Sleep, call MutexTake or
QueueWrite or QueueRead with a delay argument different than zero, try to
delete itself, etc.) or the system will hang.

If your application doesn't have a task that can never block, then an additional
task must be created to perform this role (it would be the equivalent to
FreeRTOS's Idle Task, but with SimpleRTOS we can save this additional task
whenever possible).

This task may call Yield though.

*/
/*============================================================================*/
void MainTask( void *param )
    {
    unsigned long i = 0;

    SerialPortInitMinimal( 1, 115200 );
    MutexInit( &Mutex, MUTEX_SWITCH_IMMEDIATE );

    /* Create the other tasks... */
    CreateTask( Stacks[1], sizeof Stacks[1], NULL, GetAddress( TaskRX ), 2 );
    CreateTask( Stacks[2], sizeof Stacks[2], NULL, GetAddress( MutexTask1 ), 2 );
    CreateTask( Stacks[3], sizeof Stacks[3], NULL, GetAddress( MutexTask2 ), 1 );

/*

When debugging we will simulate reception of serial characters using a timer
interrupt, see file SerialPIC24.c.

MPLAB SIM doesn't seem to support Timer2, so we use the core timer.
Under PICKit3 and ICD3 the core timer doesn't freeze so we use Timer2.

*/

#if         defined __DEBUG
    PR2             = 40000;
    TMR2            = 0;
    T2CON           = 0x8000;

    IFS0bits.T2IF   = 0;
    IEC0bits.T2IE   = 1;
#endif  /*  defined __DEBUG */

    while( 1 )
        {
        /* Some very computationally intensive calculations. */
        i++;

        /* Output the results. */
/*      PORTA   = (unsigned char)i; */

        /* Give a chance for the other tasks, but return ASAP. */
        Yield();
        }
    }
/*============================================================================*/
void TickHook( void )
    {
    }
/*============================================================================*/