|
|||||||||||
|
|||||||||||
Tics Realtime Sample Code
Tics Realtime Simple Tasks
/*******************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* taskA continuously prints string to screen,
* and yields to other tasks. (Note that since
* no other tasks are running there are no other
* tasks to yield to, so taskA runs continuously).
*
********************************************************/
void taskA(void)
{
while (TRUE) {
printf("Hello from taskA... ");
yield();
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
startTask(makeTask(taskA, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* taskA prints string to screen every 200 ms.
*
********************************************************/
void taskA(void)
{
while (TRUE) {
printf("Hello from taskA... ");
pause(200L);
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
startTask(makeTask(taskA, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* taskA and taskB continuously print to the
* screen and yield to each other.
*
********************************************************/
void taskA(void)
{
while (TRUE) {
printf("Hello from taskA... ");
yield();
}
}
void taskB(void)
{
while (TRUE) {
printf("Hello from taskB... ");
yield();
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
startTask(makeTask(taskA, 0));
startTask(makeTask(taskB, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* taskA prints string to screen every 200 ms,
* while taskB continuously prints and yields.
*
********************************************************/
void taskA(void)
{
while (TRUE) {
printf("Hello from taskA... ");
pause(100L);
}
}
void taskB(void)
{
while (TRUE) {
printf("Hello from taskB... ");
yield();
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
startTask(makeTask(taskA, 0));
startTask(makeTask(taskB, 0));
suspend();
}
Tics Realtime Task Instance Examples
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* Illustrates how multiple instances of the same
* task can be used to manage multiple
* analog channels using the task number method.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
typeFreeMsg MsgSpace[NUM_MSGS];
typedef struct structAnalog {
int channelNum, gain;
long sampleInterval;
} typeAnalog;
typeAnalog Analog[] = {
0, 50, 100L, /* Channel 0 */
1, 60, 400L, /* Channel 1 */
2, 70, 1000L /* Channel 2 */
};
/********************************************************
*
* The task below is a single generic task that
* accesses its data based on its task number,
* which is the second argument to makeTask (see
* makeTask in main below). The task number for
* the active task is contained in the global
* ActiveTcb->taskNum. Thus, a task determines
* which instance (in this example 0, 1, or 2) by
* its task number. Note that although the code
* below is the same for each task instance,
* the data is different, and so the gain,
* channel, and sample interval are different for
* each task instance.
*
* The 3 instances of this task are started in
* main below.
*
********************************************************/
void readAnalogChannel(void)
{
int reading;
typeAnalog * a;
a = &Analog[ActiveTcb->taskNum];
setGain(a->gain);
while (TRUE) {
reading = getAnalogReading(a->channelNum);
processAnalogReading(reading);
pause(a->sampleInterval);
}
}
void main()
{
int i;
startTics(makeTics(MsgSpace, NUM_MSGS));
for (i = 0; i < 3; i++) {
startTask(makeTask(readAnalogChannel, i));
}
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* Illustrates how multiple instances of the same
* task can be used to manage multiple
* analog channels using the tcb->ptr method.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
typeFreeMsg MsgSpace[NUM_MSGS];
typedef struct structAnalog {
int channelNum, gain;
long sampleInterval;
} typeAnalog;
typeAnalog Analog[] = {
0, 50, 100L, /* Channel 0 */
1, 60, 400L, /* Channel 1 */
2, 70, 1000L /* Channel 2 */
};
/********************************************************
*
* The task below is a single generic task that
* accesses its data based on its the generic
* pointer ActiveTcb->ptr, which is assigned
* to each individual task instance in main.
*
* Note that although the code
* below is the same for each task instance,
* the data is different, and so the gain,
* channel, and sample interval are different for
* each task instance.
*
* The 3 instances of this task are started in
* main below.
*
********************************************************/
void readAnalogChannel(void)
{
int reading;
typeAnalog * a;
a = (typeAnalog *) ActiveTcb->ptr;
setGain(a->gain);
while (TRUE) {
reading = getAnalogReading(a->channelNum);
processAnalogReading(reading);
pause(a->sampleInterval);
}
}
void main()
{
int i;
typeTcb * tcb;
typeAnalog * a;
static int gain[] = {50, 60, 90};
static long sampleInterval[] = {100L, 200L, 3000L};
startTics(makeTics(MsgSpace, NUM_MSGS));
for (i = 0; i <3; i++) { tcb="startTask(makeTask(readAnalogChannel," i)); tcb->ptr = malloc(sizeof(typeAnalog));
a = (typeAnalog *) tcb->ptr;
a->channelNum = i;
a->gain = gain[i];
a->sampleInterval = sampleInterval[i];
}
suspend();
}
Tics Realtime Sample Isr Code
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* The code below illustrates how a transmit and
* receive isr for a network might be coded.
*
* The hardware generates an interrupt to the
* receive isr whenever data can be sent out, at
* which time the receive isr checks the transmit
* queue for requests and processes the request
* at the front of the queue.
*
* A receive interrupt is generated when a
* complete packet of data has been received.
* The receive isr allocates a data packet, puts
* the received data into the packet, points a msg
* to the packet, and sends the msg to a packet
* processing task.
*
* Note that Tics has no requirements involving
* the installation of a driver or isr. You simply
* write the isr code using the "interrupt"
* keyword, and set up the isr vector.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define DATA_OUT 1005
#define DATA_IN 1006
#define RCV_INTR_NUM (0x3e0 / 4)
#define XMIT_INTR_NUM (0x3f0 / 4)
#define NET_POOL_BLKSIZE 64
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbNetQ, * TcbE;
typeMem * NetPool;
unsigned char NetPoolData[NET_POOL_BLKSIZE * 10];
/********************************************************
*
* T r a n s m i t I s r
*
* The isr below gets an interrupt whenever it
* is ok to transmit more data out over a high
* speed communications channel. The isr checks
* a request queue that tasks (see taskD below)
* send msgs to when data is to be sent out.
* The isr illustrates how a null tcb queue is
* used inside an isr. The null tcb queue is
* created in main below. taskD below sends a
* request to the queue.
*
********************************************************/
void interrupt far netXmitIsr(void)
{
int msgList[] = {DATA_OUT, NULL_MSG};
typeMsg * msg;
/* Check the request queue to see if there is any data to
* send out and if so, get the data packet from the msg and
* send it out onto the network.
*/
msg = _rcvMsg(TcbNetQ, 0, msgList, FALSE, TRUE);
if (msg != NULL) {
/* Put code here to send msg out onto network. */
/* Free the data pointed to by the msg. */
_putMem(&NetPool, msg->pData, FALSE);
/* Free the msg itself. */
_freeMsg(msg, FALSE);
}
/* Note that _isrRet() is not necessary here because no
* other tasks were scheduled from within this isr. Contrast
* this with netIsrRcv below.
*/
}
/********************************************************
*
* R e c e i v e I s r
*
* A receive interrupt is generated when a
* complete packet of data has been received.
* The receive isr allocates a data packet, puts
* the received data into the packet, points a msg
* to the packet, and sends the msg to a packet
* processing task.
*
********************************************************/
void interrupt far netRcvIsr(void)
{
typeMsg * msg;
unsigned char * packet;
packet = _getMem(&NetPool, FALSE);
msg = _makeMsg(TcbE, DATA_IN, FALSE);
msg->pData = packet;
_sendMsg(msg, FALSE, FALSE);
/* Return to the interrupted task, or preempt it if TcbE is
* of a higher priority. The invocation of _isrRet() below
* is necessary because taskE was implicitly scheduled
* by sendMsg and may be of a higher priority than
* the task that was preempted to enter this isr. If _isrRet()
* is not invoked, then this isr will return to the preempted
* task.
*/
_isrRet();
}
/********************************************************
*
* T r a n s m i t R e q u e s t T a s k
*
* This task generates transmit requests by
* sending msgs to the transmit request queue.
*
********************************************************/
void taskD(void)
{
typeMsg * msg;
while (TRUE) {
pause(1000L);
msg = makeMsg(TcbNetQ, DATA_OUT);
msg->pData = getMem(&NetPool);
/* Fill packet pointed to by msg->pData here... */
sendMsg(msg);
}
}
/********************************************************
*
* P a c k e t P r o c e s s i n g T a s k
*
* This task receives packet msgs from the
* receive isr and processes them.
*
********************************************************/
void taskE(void)
{
typeMsg * msg;
while (TRUE) {
msg = waitMsg(DATA_IN);
/* Process msg here... */
/* Free the data packet. */
putMem(&NetPool, msg->pData);
/* Free the msg itself. */
freeMsg(msg);
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
startTask(makeTask(taskD, 0));
startTask(makeTask(taskE, 0));
/* Create a queue (a NULL task). */
TcbNetQ = startTask(makeTask(NULL, 0));
/* Set interrupt vectors for transmit and receive. */
setvect(RCV_INTR_NUM, netRcvIsr);
setvect(XMIT_INTR_NUM, netXmitIsr);
/* Create a memory pool for network packets. When taskD
* sends a msg to the TcbNetQ, it points the msg to a
* packet that will be sent out on the network. */
NetPool = makeMem(NetPoolData, sizeof(NetPoolData), NET_POOL_BLKSIZE);
suspend();
}
Tics Realtime Sample Mail Passing
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* Shows simple mail passing between two tasks.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define HELLO 0
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbA;
void taskA(void)
{
while (TRUE) {
freeMail(waitMail(HELLO));
printf("Received Mail. ");
}
}
void taskB(void)
{
while (TRUE) {
sendMail(makeMail(TcbA, HELLO));
pause(200L);
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbA = startTask(makeTask(taskA, 0));
startTask(makeTask(taskB, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* Shows simple mail passing between 3 tasks.
* taskB sends mail with data to taskA with mail
* over-write allowed (default). taskC also sends
* mail to taskA, with over-writes disallowed.
*
* Note that it is sometimes desirable to
* over-write data. Consider a task that updates
* the screen with the latest data value,
* which is received from another task via mail.
* If a newer value arrives before the previous
* value is written to the screen, then it is
* desirable to over-write the old in the
* mailbox with the new value before it is
* displayed. If msgs were used instead of mail,
* both the old and the new value would be queued
* resulting in the undesirable situation of
* the old value being displayed even though
* the newer value is available.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define HELLO 0
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbA;
void taskA(void)
{
int data;
typeMail * mail;
while (TRUE) {
mail = waitMail(HELLO);
printf("Received mail with data = %d ", mail->iData);
freeMail(mail);
}
}
void taskB(void)
{
typeMail * mail;
while (TRUE) {
mail = makeMail(TcbA, HELLO);
mail->iData = 5;
sendMail(mail);
pause(200L);
}
}
void taskC(void)
{
typeMail * mail;
while (TRUE) {
mail = makeMail(TcbA, HELLO);
mail->iData = 5;
/* Disallow over-writing of mail that has not yet been
* read.
*/
mail->flags |= OVER_WRITE_DISABLE;
sendMail(mail);
pause(300L);
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbA = startTask(makeTask(taskA, 0));
startTask(makeTask(taskB, 0));
startTask(makeTask(taskC, 0));
suspend();
}
Miscellaneous Tics Settings
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbA;
void taskA(void)
{
int pri = DEF_PRI;
while (TRUE) {
/* Dynamically change the priority of this task. */
ActiveTcb->pri = pri++;
if (pri > 50) pri = DEF_PRI;
}
}
void main()
{
typeTics * tics;
/* Make the Tics data structure. */
tics = makeTics(MsgSpace, NUM_MSGS);
/* Tics defaults timer chip interrupt rate to 5 ms. The code
* below resets it to 10 ms. For details on computing "timerChipCount"
* for see the "Tics Realtime Kernel Programmer's Guide".
*/
tics->timerChipCount = 11932; /* Raw count to be loaded into timer register. */
tics->uSPerTimerChipCount = 10000; /* Number of uS per interrupt. */
startTics(tics);
/* Make task control block for taskA. */
TcbA = makeTask(taskA, 0);
/* Raise taskA's priority. (Lower numbers are higher priority). */
TcbA->pri--;
/* Enable time-slicing. Note that time-slicing is undesirable.
* See the chapter on time-slicing in "The Art of Real-time
* Programming" for further details.
*/
TcbA->flags |= TIMESLICE;
/* Set the time-slice interval to 100 ms. (Default is 50 ms). */
TcbA->timeSlice = 100;
/* Disable stack checking between context switches. */
TcbA->flags |= NO_STACK_CHECK;
/* Now start taskA with the attributes assigned above. Note that
* any of the above defined attributes can be changed
* dynamically during program execution.
*/
startTask(TcbA);
suspend();
}
Tics Realtime Sample Message Passing
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* Shows simple message passing between two tasks.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define HELLO 1000
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbA;
void taskA(void)
{
while (TRUE) {
freeMsg(waitMsg(HELLO));
printf("Received msg. ");
}
}
void taskB(void)
{
while (TRUE) {
sendMsg(makeMsg(TcbA, HELLO));
pause(200L);
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbA = startTask(makeTask(taskA, 0));
startTask(makeTask(taskB, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
*
* P u r p o s e
*
* Show simple message passing bewtween tasks.
* Keyboard monitoring task has been adding so
* that pressing any key forces a clean exit.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define HELLO 1000
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbA;
void taskC(void)
{
while (TRUE) {
if (kbhit()) {
exitTics();
exit(0);
}
pause(200L);
}
}
void taskA(void)
{
while (TRUE) {
freeMsg(waitMsg(HELLO));
printf("Received msg. ");
}
}
void taskB(void)
{
while (TRUE) {
sendMsg(makeMsg(TcbA, HELLO));
pause(200L);
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbA = startTask(makeTask(taskA, 0));
startTask(makeTask(taskB, 0));
startTask(makeTask(taskC, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
*
* P u r p o s e
*
* Shows simple message passing with integer data
* bewtween tasks.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define HELLO 1000
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbA;
void taskA(void)
{
typeMsg * msg;
while (TRUE) {
msg = waitMsg(HELLO);
printf("Received msg with data = %d ", msg->iData);
freeMsg(msg);
}
}
void taskB(void)
{
int i;
typeMsg * msg;
i = 0;
while (TRUE) {
msg = makeMsg(TcbA, HELLO);
msg->iData = i++;
sendMsg(msg);
pause(200L);
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbA = startTask(makeTask(taskA, 0));
startTask(makeTask(taskB, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
*
* P u r p o s e
*
* Shows simple message passing with pointer data
* bewtween tasks.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define HELLO 1000
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbA;
typedef struct structData {
int item00, item01, item02;
} typeData;
void taskA(void)
{
typeMsg * msg;
typeData * d;
while (TRUE) {
msg = waitMsg(HELLO);
d = (typeData *) msg->pData;
printf("Received msg with data = %d,%d,%d ",
d->item00, d->item01, d->item02);
freeMsg(msg);
}
}
void taskB(void)
{
int i;
typeMsg * msg;
typeData data;
data.item00 = 5;
data.item01 = 6;
data.item02 = 7;
while (TRUE) {
msg = makeMsg(TcbA, HELLO);
msg->pData = &data;
sendMsg(msg);
pause(200L);
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbA = startTask(makeTask(taskA, 0));
startTask(makeTask(taskB, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
*
* P u r p o s e
*
* Shows simple message passing bewtween tasks
* where the destination task can receive more
* than one message number.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define START 1000
#define STOP 1001
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbA;
void startMotor(int motorNum)
{
/* Start motor according to its motor number. */
printf("Motor number %d started. ", motorNum);
}
void stopMotor(void)
{
/* Motor number not require to stop motor. */
printf("Motor stopped. ");
}
void taskA(void)
{
typeMsg * msg;
while (TRUE) {
msg = waitMsg(ANY_MSG);
switch (msg->msgNum) {
case START:
startMotor(msg->iData); /* Pass motor number. */
break;
case STOP:
stopMotor();
break;
}
freeMsg(msg);
}
}
void taskB(void)
{
typeMsg * msg;
while (TRUE) {
msg = makeMsg(TcbA, START);
msg->iData = 5;
sendMsg(msg);
pause(10000L); /* Wait 10 seconds before stopping. */
sendMsg(makeMsg(TcbA, STOP));
pause(5000L); /* Wait 5 seconds before starting. */
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbA = startTask(makeTask(taskA, 0));
startTask(makeTask(taskB, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
*
* P u r p o s e
*
* Shows simple message passing bewtween tasks
* where the destination task must reply to
* the sender task.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define HELLO 1000
#define HELLO_BACK 1001
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbA;
void taskA(void)
{
typeMsg * msg;
while (TRUE) {
msg = waitMsg(HELLO);
sendMsg(makeMsg(msg->senderTcb, HELLO_BACK));
freeMsg(msg);
}
}
void taskB(void)
{
while (TRUE) {
sendMsg(makeMsg(TcbA, HELLO));
freeMsg(waitMsg(HELLO_BACK));
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbA = startTask(makeTask(taskA, 0));
startTask(makeTask(taskB, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
*
* P u r p o s e
*
* Shows simple message passing bewtween tasks
* where the sender task fakes out the
* receiving task who responds to taskC
* instead of taskB. See code below for details.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define HELLO 1000
#define HELLO_BACK 1001
#define CONTINUE 1002
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbA, * TcbC;
void taskA(void)
{
typeMsg * msg;
while (TRUE) {
msg = waitMsg(HELLO);
sendMsg(makeMsg(msg->senderTcb, HELLO_BACK));
freeMsg(msg);
}
}
void taskB(void)
{
typeMsg * msg;
while (TRUE) {
msg = makeMsg(TcbA, HELLO);
msg->senderTcb = TcbC;
sendMsg(msg);
freeMsg(waitMsg(CONTINUE));
}
}
void taskC(void)
{
while (TRUE) {
freeMsg(waitMsg(HELLO_BACK));
sendMsg(makeMsg(TcbA, CONTINUE));
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbA = startTask(makeTask(taskA, 0));
startTask(makeTask(taskB, 0));
TcbC = startTask(makeTask(taskC, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
*
* P u r p o s e
*
* Shows simple message passing bewtween tasks
* where the destination task (taskA) will only
* wait 1 second for a message, after which it
* prints a timeout error string to the screen.
*
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define HELLO 1000
#define HELLO_BACK 1001
#define CONTINUE 1002
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbA;
void taskA(void)
{
typeMsg * msg;
while (TRUE) {
msg = waitTimedMsg(HELLO, 1000L);
if (msg->msgNum == TIMEOUT) {
freeMsg(msg);
printf("TIMEOUT error. Exiting.\n");
exitTics();
exit(0);
}
freeMsg(msg);
}
}
void taskB(void)
{
long pauseValue = 1000L;
while (TRUE) {
sendMsg(makeMsg(TcbA, HELLO));
pause(pauseValue);
pauseValue += 100L;
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbA = startTask(makeTask(taskA, 0));
startTask(makeTask(taskB, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
*
* P u r p o s e
*
* Shows simple message passing bewtween tasks
* where the destination task will only wait
* 1 second for a message, after which it prints
* a timeout error string to the screen. The
* distinction between this example and the
* one above is that here taskA will accept
* any of 3 messages before it times out, and
* therefore, uses _waitTimedMsg which accepts
* a list of messages.
*
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define START 1000
#define STOP 1001
#define CONTINUE 1002
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbA;
void taskA(void)
{
typeMsg * msg;
int msgList[] = {START, STOP, CONTINUE, NULL_MSG};
while (TRUE) {
msg = _waitTimedMsg(MSGQ, msgList, 1000L, TRUE, TRUE);
if (msg->msgNum == TIMEOUT) {
freeMsg(msg);
printf("TIMEOUT error. Exiting.\n");
exitTics();
exit(0);
}
switch (msg->msgNum) {
case START: /* Handle START msg. */ break;
case STOP: /* Handle STOP msg. */ break;
case CONTINUE: /* Handle CONTINUE msg. */ break;
}
freeMsg(msg);
}
}
void taskB(void)
{
long pauseValue = 1000L;
while (TRUE) {
sendMsg(makeMsg(TcbA, START));
pause(pauseValue);
pauseValue += 100L;
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbA = startTask(makeTask(taskA, 0));
startTask(makeTask(taskB, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
*
* P u r p o s e
*
* Shows simple message passing bewtween tasks
* where the destination task wants to peek
* into its message queue. This cannot be done
* with waitMsg because if the message is not
* in the queue, the task will suspend until the
* desired message is received. The code below
* uses rcvMsg, which always returns - a NULL is
* returned if the message is not in the queue,
* otherwise, a pointer to the message is
* returned.
*
* N o t e s
*
* rcvMsg is seldom used. Use waitMsg instead.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define START 1000
#define STOP 1001
#define CONTINUE 1002
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbA;
void taskA(void)
{
typeMsg * msg;
while (TRUE) {
msg = rcvMsg(START);
if (msg == NULL) {
printf("Have not yet received msg. ");
pause(200L);
}
else {
freeMsg(msg);
printf("Got msg.\n");
exitTics();
exit(0);
}
}
}
void taskB(void)
{
while (TRUE) {
pause(200L);
sendMsg(makeMsg(TcbA, START));
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbA = startTask(makeTask(taskA, 0));
startTask(makeTask(taskB, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
*
* P u r p o s e
*
* Shows simple message passing bewtween tasks
* where the destination task wants to peek
* into its message queue AND not remove the
* message. This cannot be done with waitMsg
* because if the message is not in the queue,
* the task will suspend until the desired message
* is received. Nor can it be done with rcvMsg
* since rcvMsg removes the message from the
* queue if it is there. The code below uses
* _rcvMsg, which optionally leaves the message
* in the queue.
*
*
* N o t e s
*
* rcvMsg is seldom used. Use waitMsg instead.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define START 1000
#define STOP 1001
#define CONTINUE 1002
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbA;
void taskA(void)
{
int msgList[] = {START, NULL_MSG};
typeMsg * msg;
while (TRUE) {
msg = _rcvMsg(ActiveTcb, MSGQ, msgList, TRUE, FALSE);
if (msg == NULL) {
printf("Have not yet received msg. ");
pause(200L);
}
else {
/* We got the START msg. At this point the
* msg is still in the queue. We can leave it
* there or remove it as shown below. */
removeMsg(msg);
printf("Got msg. \n");
/* Note that removing the msg from the queue
* does not free it. You must free the msg after
* you are done with it. */
freeMsg(msg);
exitTics();
exit(0);
}
}
}
void taskB(void)
{
while (TRUE) {
pause(200L);
sendMsg(makeMsg(TcbA, START));
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbA = startTask(makeTask(taskA, 0));
startTask(makeTask(taskB, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* Shows how to apply and use msg priorities.
* This example also shows how a task's priority
* can be changed dynamically.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define START_MOTOR 1000
#define STOP_MOTOR 1001
#define EMERGENCY_STOP 1002
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbA;
void interrupt far errorDectect(void)
{
typeMsg * msg;
/* This isr is entered when hardware detects a critical error.
* Motor must be stopped immediately and brake applied.
*/
msg = _makeMsg(TcbA, EMERGENCY_STOP, FALSE);
/* Setting the msg flag BUMP_PRI (see code line following
* this comment) tells sendMsg that the destination
* task's priority is to be temporarily forced high so that
* the destination task (taskA in this case) runs next. After
* taskA is scheduled, its priority is set to its previous value.
* Note also that setting the BUMP_PRI flag is an option. If
* BUMP_PRI is not set, but the msg priority is set high, as
* is done below in the statement "msg->pri = HI_USER_PRI", then
* the msg is still forced to the front of taskA's msg queue,
* however, taskA may not be the next task to run.
*/
msg->flags |= BUMP_PRI;
/* Raise msg priority so that msg goes to the front of
* taskA's msg queue.
*/
msg->pri = HI_USER_PRI;
_sendMsg(msg, FALSE, FALSE);
}
void taskA(void)
{
typeMsg * msg;
while (TRUE) {
msg = waitMsg(ANY_MSG);
switch (msg->msgNum) {
case START_MOTOR:
/* Perform motor startup functions. */
break;
case STOP_MOTOR:
/* Perform motor shutdown functions. */
break;
case EMERGENCY_STOP:
/* Shut off motor and
* apply brake to immediately stop motor. */
break;
}
freeMsg(msg);
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbA = startTask(makeTask(taskA, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* Illusrates the use of dormant msgs.
* A dormant msg is one which remains invisible
* until activated. This is useful where very
* high speed notifications are required, since
* all the overhead of putting the msg into
* the destination task's queue and scheduling the
* task has been done beforehand.
*
* Note that normal msgs are typically fast
* enough. Only use this technique when normal
* msgs wont do.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define SHUT_DOWN 1000
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbShutDown;
typeMsg * ShutDownMsg;
void interrupt far errorDetect(void)
{
/* Do not send msg, as it has already been sent. Simply activate it. */
activateMsg(ShutDownMsg);
}
void shutDown(void)
{
freeMsg(waitMsg(SHUT_DOWN));
/* Do system shutdown here... */
printf("System shutdown.\n");
exitTics();
exit(0);
}
void simulateInterrupt(void)
{
while (TRUE) {
pause(2000L);
errorDetect();
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbShutDown = startTask(makeTask(shutDown, 0));
startTask(makeTask(simulateInterrupt, 0));
ShutDownMsg = makeMsg(TcbShutDown, SHUT_DOWN);
deActivateMsg(ShutDownMsg);
sendMsg(ShutDownMsg);
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
*
* P u r p o s e
*
* Illustrates msg forwarding and how
* the destination task can wait for any
* msg from a given set.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define PRINT_DONE 1000
#define PRINT_ERROR 1001
#define PRINT 1002
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * PrintServerTcb, * PrintDriverTcb;
void printDriver(void)
{
typeMsg * msg;
while (TRUE) {
msg = waitMsg(PRINT);
/* Talk to print driver here... */
/* Use a short-cut to respond. We do not reccomend
* this method - shown here for illustration. */
msg->msgNum = PRINT_DONE;
forwardMsg(msg->senderTcb, msg);
}
}
void printServer(void)
{
int msgList[] = {PRINT_DONE, PRINT_ERROR, NULL_MSG};
typeMsg * msg;
typeTcb * senderTcb;
while (TRUE) {
msg = waitMsg(PRINT);
senderTcb = msg->senderTcb;
forwardMsg(PrintDriverTcb, msg);
msg = _waitMsg(MSGQ, msgList, TRUE, TRUE);
switch (msg->msgNum) {
case PRINT_DONE:
forwardMsg(senderTcb, msg);
break;
case PRINT_ERROR:
setError("Printer error.\n");
break;
default:
setError("PrintServer - unknown msg.\n");
break;
}
}
}
void taskA(void)
{
char filename[] = "myfile.doc";
typeMsg * msg;
while (TRUE) {
msg = makeMsg(PrintServerTcb, PRINT);
msg->pData = filename;
sendMsg(msg);
freeMsg(waitMsg(PRINT_DONE));
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
PrintServerTcb = startTask(makeTask(printServer, 0));
PrintDriverTcb = startTask(makeTask(printDriver, 0));
startTask(makeTask(taskA, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* The code below illustrates how msgs can be
* sent to a task without the task being
* scheduled. This capability is seldom useful.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define MSG00 1001
#define MSG01 1002
#define MSG02 1003
#define BEGIN 1004
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbA;
void taskB(void)
{
typeMsg * msg;
while (TRUE) {
/* The following 3 code blocks queue up the msgs
* MSG00, MSG01, MSG02 to taskA without scheduling the
* task. This is accomplished by setting the
* NO_MSG_NOTIFY flag as shown below.
* This means that the msgs MSG00, MSG01, MSG02
* are put into taskA's msg queue, but taskA remains
* suspended. Finally, the msg BEGIN is sent without the
* NO_MSG_NOTIFY flag set, which will schedule taskA
* to run. Note that when taskA runs it will have 4 msgs
* in its queue and that it will not suspend on each
* waitMsg call; it will return immediately with the msg
* since the desired msg is already in the queue.
*/
msg = makeMsg(TcbA, MSG00);
msg->flags |= NO_MSG_NOTIFY;
sendMsg(msg);
msg = makeMsg(TcbA, MSG01);
msg->flags |= NO_MSG_NOTIFY;
sendMsg(msg);
msg = makeMsg(TcbA, MSG02);
msg->flags |= NO_MSG_NOTIFY;
sendMsg(msg);
sendMsg(makeMsg(TcbA, BEGIN));
/* Let other tasks of the same priority run. */
yield();
}
}
void taskA(void)
{
while (TRUE) {
/* Note that the msgs below are retrieved in reverse order;
* that is, the msgs were put into the queue by taskB in
* the order MSG00, MSG01, MSG02, BEGIN, but are retrieved
* in the reverse order. This is done to illustrate how msgs
* can be retrieved by name. Of course, the msgs could
* have been retrieved in the correct order also.
* To retrieve msgs in fifo order when the names are
* not known, wait for ANY_MSG, i.e., waitMsg(ANY_MSG),
* then use msg->msgNum to determine the msg number.
*/
freeMsg(waitMsg(BEGIN));
freeMsg(waitMsg(MSG02));
freeMsg(waitMsg(MSG01));
freeMsg(waitMsg(MSG00));
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbA = startTask(makeTask(taskA, 0));
startTask(makeTask(taskB, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* The code below illustrates how a receiving
* task can throttle msgs using semaphores. This
* method is inferior to standard throttling,
* which is illustrated in the second example.
*
* In this example, a semaphore called "Port"
* is created with a count of 8. Sending tasks
* must acquire Port before sending and the
* receiving task must release Port after
* receiving the msg. The effect is that no more
* than 8 msgs are allowed in the receiving tasks
* queue.
*
* The semaphore is started in main by creating
* an instance of the semaphore manager task
* "semMgr". The count and maxCount are set as
* shown. maxCount is used for error detection
* and must always be set to the same value
* as count.
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define HELLO 1000
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * Port, * TcbA, * TcbB, * TcbC;
void taskA(void)
{
typeMsg * msg;
while (TRUE) {
pause(1000L);
while ((msg = rcvMsg(HELLO)) != NULL) {
printf("Got msg... ");
freeMsg(msg);
releaseSem(Port);
}
}
}
void taskB(void)
{
while (TRUE) {
acquireSem(Port);
sendMsg(makeMsg(TcbA, HELLO));
yield();
}
}
void taskC(void)
{
while (TRUE) {
acquireSem(Port);
sendMsg(makeMsg(TcbA, HELLO));
yield();
}
}
void main(void)
{
startTics(makeTics(MsgSpace, NUM_MSGS));
Port = makeTask(semMgr, 0);
Port->semCount = Port->semCountMax = 8;
startTask(Port);
TcbA = startTask(makeTask(taskA, 0));
TcbB = startTask(makeTask(taskB, 0));
TcbC = startTask(makeTask(taskC, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* The code below illustrates how a receiving
* task can throttle msgs using standard
* throttling. This method is superior to the
* semaphore method because it is faster, simpler,
* and can be used from within an isr.
*
* Throttling is accomplished by setting the
* msgCount field of the head msg. (The head msg
* is the head of the doubly linked list msg
* queue). If the msgCount field is 0, sendMsg
* will not send the msg and will return a NULL.
*
* Note that it is up the the sender (in this
* case the isr) to check the destination task's
* msg count and refrain from sending if a low
* water mark has been reached.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define DATA 1000
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbDataHandler;
void sendDataMsg(int data)
{
typeMsg * msg;
msg = makeMsg(TcbDataHandler, DATA);
msg->iData = data;
sendMsg(msg);
}
void interrupt far rcvIsr(void)
{
char data;
static int state = 0;
typeMsg * headPtr;
data = getData();
headPtr = TcbDataHandler->msgTable[0];
switch (state) {
case 0: /* Throttling not in effect. */
sendDataMsg(data);
if (headPtr->msgCount <3) { sendXoffToDataSource(); state="1;" } break; case 1: /* Throttling is in effect. */ if (headPtr->msgCount >= 3) {
sendDataMsg(data);
sendXonToDataSource();
state = 0;
}
}
}
void dataHandler(void)
{
typeMsg * msg;
while (TRUE) {
msg = waitMsg(DATA);
processData(msg);
freeMsg(msg);
}
}
void main(void)
{
typeMsg * msgHead;
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbDataHandler = startTask(makeTask(dataHandler, 0));
msgHead = TcbDataHandler->msgTable[0];
/* Do not allow more than 8 msgs in the msg queue. */
msgHead->msgCount = 8;
suspend();
}
Tics Realtime Sample Timer Code
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* Shows simple use of pause.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
typeFreeMsg MsgSpace[NUM_MSGS];
void taskA(void)
{
int data = 0;
while (TRUE) {
pause(100L);
printf("Data value is %d ", data++);
if (data > 100) { exitTics(); exit(0);}
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
startTask(makeTask(taskA, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* Shows simple use of one-shot timer.
*
* One-shot timers are typically used internally
* by Tics to implement time-outs. For example,
* Tics uses a one-shot timer to implement
* the function "waitTimedMsg". The code below
* implements a watchdog timer. The interrupt
* service routine "watchDogIsr" is entered
* once each second due to an external interrupt.
* Concurrently, a task runs that waits
* either for a STROBE message from the interrupt
* service routine, or a TIMEOUT message. The *
* TIMEOUT msg is sent to the task after 2 seconds.
* If the STROBE msg is received first, then
* all is ok, and the TIMEOUT msg is cancelled,
* otherwise the watchdog did not strobe, and an
* error condition exists.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
#define STROBE 1001
typeFreeMsg MsgSpace[NUM_MSGS];
typeTcb * TcbWatchDog;
void interrupt far watchDogIsr(void)
{
typeMsg * msg;
msg = _makeMsg(TcbWatchDog, STROBE, FALSE);
_sendMsg(msg, FALSE, FALSE);
}
void taskWatchDog(void)
{
typeMsg * msg, * timer;
long seqNum;
while (TRUE) {
timer = makeTimer(2000L);
seqNum = timer->seqNum;
startTimer(timer);
msg = waitMsg(ANY_MSG);
switch (msg->msgNum) {
case STROBE:
cancelTimer(timer, seqNum);
break;
case TIMEOUT:
setError("Watchdog timeout error.");
break;
}
freeMsg(msg);
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
TcbWatchDog = startTask(makeTask(taskWatchDog, 0));
suspend();
}
/********************************************************
*
* C o p y r i g h t N o t i c e
*
* Copyright © 2000 Tics Realtime.
* All rights reserved.
*
* Shows simple use of periodic timer.
*
* Periodic timers allow for precise timing
* because the timer is restarted inside the timer
* isr itself, as opposed to the programmer
* restarting the timer by using "pause" in a
* loop. Note that the periodic timer is only
* issued once after which a TIMEOUT msg is
* received by the task at the specified interval
* until the timer is cancelled with
* "cancelTimer".
*
* See "The Art of Real-time Programming",
* or "The Tics Programmer's Guide" for details.
*
********************************************************/
#include "tics.h"
#include "ticsmain.h"
#include "ticsext.h"
#define NUM_MSGS 100
typeFreeMsg MsgSpace[NUM_MSGS];
void taskA(void)
{
typeMsg * timer, * msg;
timer = makeTimer(2000L);
timer->flags |= PERIODIC;
startTimer(timer);
while (TRUE) {
msg = waitMsg(TIMEOUT);
/* Do something... */
freeMsg(msg);
}
}
void main()
{
startTics(makeTics(MsgSpace, NUM_MSGS));
startTask(makeTask(taskA, 0));
suspend();
}
Copyright © 2000, Tics Realtime |
|||||||||||