1. Description

Task 2 extends task 1 by the following:

  1. Instead of "Downloadable Kernel Module" run your application as "Real-Time Process". It requires to replace CreateTasks function with main function. Do not forget that the return from main function implies termination of the application process.

  2. The application involves the task called "announcer" which handles all output messages. This tasks receives messages from message queue and prints them on console. All other tasks prepares messages and instead of calling printf function they send them to the queue. It means that in the whole program there is only one call to printf and it is in "announcer" task.

  3. Every 10 seconds, the announcer displays the actual time.

    Note

    It is not required to use timers to implement this.

  4. The number of shovels is specified as a constant but the number of digger can be changed runtime.

  5. After the start of application there is no digger working.

  6. By pressing p or P button a digger comes to the workplace (capital letter for upper diggers, small letter for lower ones).

  7. By pressing o or O button a digger who came first leaves the workplace.

  8. Pressing K button signals the end of working time it means that all diggers go home and the application terminates. It is assumed that the digger currently working leaves the workplace when he gets tired. It is also assumed that the digger having a rest leaves after that.

2. Hints

2.1. Console input/output

For reading the keys, use proper functions from ansiStdio library (stdio.h header file). Real-Time processes do not have connected its input/output to the system console by default. To see you program I/O, run the program with an allocated console as shown in the following figure. Note that this way, the console is attached only to the initial task. For this reason, don't put the keyboard handling code into a separate task!

Then open WIndows->Show View->Console to see the console of your program:

If you are running multiple processes, you can switch the console of different processes by the marked button on the console toolbar.

2.2. Message queues

Message queue is a communication object that facilitate sending messages of variable lengths between tasks. You must just specify maximal message length.

You can find the description of message queues and its use case examples in chapter VxWorks Programmer's guide (Multitasking ->Intertask and Interprocess Communications) and in introduction to given libraries (see VxWorks Reference Manual, and references to functions in Table 1, “A list of basic message queue functions” ).

Table 1. A list of basic message queue functions

FunctionLibrary
msgQCreatemsgQLib
msgQDeletemsgQLib
msgQSendmsgQLib
msgQReceivemsgQLib
msgQNumMsgsmsgQLib

Do not forget to include msgQLib.h header file.

Example 1. Message queue creation

MSG_Q_ID messages;
char msg[50];

messages = msgQCreate(100, sizeof(msg), MSG_Q_FIFO);


Example 2. Send/receive string

int length;

length = sprintf(msg,"diggerUp %d has taken shovel", digger_id);
msgQSend(messages, (char*) &msg, length+1, NO_WAIT,MSG_PRI_NORMAL);

msgQReceive(messages, (char*) &msg, sizeof(msg), WAIT_FOREVER);


Example 3. Send/receive integer

int task_id;

msgQSend(messages, (char*) &task_id, sizeof(task_id),NO_WAIT,MSG_PRI_NORMAL);

msgQReceive(messages, (char*) &task_id, sizeof(task_id), WAIT_FOREVER);


2.3. Clocks and timers

  • Clocks measures time (with specified resolution) independently from any applications.

  • VxWorks contains the following clocks:

    • CLOCK_REALTIME

    • CLOCK_MONOTONIC

    • CLOCK_THREAD_CPUTIME_ID

  • Timers are created by applications to notify them of elapsed time interval of given length. The notification is delivered as a signal.

  • VxWorks libraries: clockLib a timerLib.

Table 2. Clocks and timers POSIX API

FunctionDescription
clock_getres()Gets clock resolution
clock_gettime()Gets actual time
clock_settime()Set the clock to specified time
timer_create()Creates a timer, which uses the specified clock as a time-base
timer_delete()Deletes a timer
timer_open()Opens a named timer
timer_gettime()Gets remaining time to tiemr expiration
timer_getoverrun()Can be called from timer handler and returns how many times the timer expired between the signal was sent and the handler was called
timer_settime()Sets the timer expiration time (one-shot timer) and optionally expiration period (periodic timer)
nanosleep()Delays task execution for a specified number of nanoseconds
sleep()Delays task execution for a specified number of seconds
alarm()Sets alarm. After a specified number of seconds elapses, the signal will be sent to the process. This can be used for timeout implementation:
alarm(3);
c = getchar(); /* waiting is interrupted after 3 seconds */
alarm(0); /* cancel alarm (if we wait less than 3 seconds) */


Table 3. Clocks and timers – non-POSIX API (VxWorks specific)

FunctionDescription
timer_cancel()An easy way to disable a timer set by timer_settime()
timer_connect()An easy way to connect an user handler function to a timer. It uses sigaction() internally. The handler function is called in the context of task that created the timer.


2.3.1. Timers example

#include <time.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

void timer_handler(
		timer_t timerid,       /* expired timer ID */
		int arg                /* user argument    */
		)
{
	printf("timer %p expired with arg %d\n", timerid, arg);
}
			

void init_timer(void)
{
	timer_t my_timer;
	struct sigevent event;
	struct itimerspec timer_spec;
	int ret;
	
	event.sigev_notify = SIGEV_TASK_SIGNAL;
	event.sigev_signo = SIGRTMIN;
	event.sigev_value.sival_int = 1234;
	ret = timer_create(CLOCK_REALTIME, &event, &my_timer);
	if (ret == ERROR) {
		perror("timer_create");
		return;
	}

	ret = timer_connect(my_timer, timer_handler, 4567);
	if (ret == ERROR) {
		perror("timer_create");
		return;
	}

	/* first expiration in 2 seconds (if zero, the timer is disabled) */
	timer_spec.it_value.tv_sec = 2;
	timer_spec.it_value.tv_nsec = 0;
	/* subsequent periodic expirations after 500 ms */
	timer_spec.it_interval.tv_sec = 0;
	timer_spec.it_interval.tv_nsec = 500*1000*1000;
	
	ret = timer_settime(my_timer, 0, &timer_spec, NULL);
	if (ret == ERROR) {
		perror("timer_create");
		return;
	}
}

void timer_task(void)
{
	  int i;
	 
	  init_timer();
	
	  while (1) {
	     sleep(1000);
	  }
}

int main(int argc, char *argv[])
{
	int i;

	printf("Starting\n");
	taskSpawn("Timer task", 210, 0, 4096, (FUNCPTR) timer_task, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
	sleep(10);

	printf("Waiting\n");
	for (i = 0; i < 10; i ++) 
		sleep(10);               /* sleep is interrupted by timer signal */

		
	printf("Terminating\n");
	return 0;
}