This file is part of SimpleRTOS2
/*============================================================================*/ /* 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 ) { } /*============================================================================*/