DESCRIPTION:	This file discusses the implementation of tasks running on
		different sets of channels and integration times

AUTHOR:		Stephan Esterhuizen

DATE:		24 June 2003

--------------------------------------------------------------------------------

DIFFERENT TASKS
---------------

In order to create a flexible and generic software GPS receiver, it has been
decided that many different tasks will run on the host computer. Each of these
tasks will handle a certain aspect of the GPS receiver, including:

 - A task to READ the gp2021 registers and store dumps and measurement data in a
 buffer for later access by other tasks. This task is also responsible to let
 other tasks know that new data is available.

 - A task to SURVEY given a certain doppler window, code phase window, code chip
 increment, etc. This task is also responsible to let other tasks know that new
 survey data is available.

 - A task to ACQUIRE the satellite signal. This task will examine I/Q samples
 and determine if a satellite signal is present. This task is also responsible
 to let the caller task know wheter a signal has been acquired or not (see
 command task below)

 - A task to CARRIER_TRACK the GPS signal, this task will usually run after a
 signal is acquired. This task is also responsible to let the caller task know
 whether carrier lock was lost/acquired.

 - A task to CODE_TRACK the GPS signal, this task will usually run after a
 signal is acquired. This task is also responsible to let the caller task know
 whether code lock has been lost/acquired.

 - A task to DEMOD the data bits and try to frame sync

 - A task to COMMAND the sequence in which the aforementioned tasks will
 execute. No task other than the command task can run by itself, the command
 task is responsible to resume/block tasks as need be. This way no single task
 (except for the command task) knows about any other task - creating a very
 flexible GPS receiver.

TASK DATA
---------

Some tasks must wake up whenever a certain type of data is ready. Each task is
required to register itself with the task responsible for creating the data. As
an example, the acquisition task needs to run whenever survey task has data
ready. Thus when survey task runs for the first time, it registers itself with
acquisition task. Then, whenever new data is available survey task sends a
message to acquistion task to let it know that new survey data is available.
Registering yourself should be viewed as a synchronising event, you are telling
the task you are registering with to synchronise your task with data that is
being generated by the other task. From now on we shall call the data generation
task the PRODUCER task and the task waiting on the data the CONSUMER task. Note
that some tasks can be a consumer and a producer at the same time. The
survey task (below) is a sample of such a case.

Now one might ask why do Acquisition task not just time itself off read task?
The read task, after all, creates all the data. The problem for doing it that
way is that what happens when you want to acquire over a 4ms integration period?
Somebody needs to tell acquisition task that 4ms worth of data is ready. Now, in
order to acquire over a 4ms integration time, survey needs to dwell 4ms at each
code phase. So task survey is the best task to tell acquisition that new data is
ready (synchronise). This way acquistion will only wake up when it has to.

Another argument one might raise is this: If we want a 4ms integration time, why
does task acquisition and task survey not register both with read task, who
creates the data? The problem with this is, what if survey task modifies CODE
DCO to slide us relative to the incoming code? When this sliding is in progress,
any IQ dumps being generated by readTask is invalid, meaning that if
acquisition's timing is based off read task, it will get corrupt data at times.
The only way to fix this is to have survey task (who knows when survey data is
correct) tell acquisition task when to run.

In order to REGISTER a consumer task with  a producer task, the following is 
necessary:

 - Each task must be able to accept certain type of RTAI messages. So far these
 messages can be

 	1) SETUP: The task will re-initialise its data, perhaps initialise some
	channels, register itself with  the producer task, and remove any tasks 
	for whom IT (this task) is producing data. A task must always be sent
	the 'setup' message the first time it is used, or whenever some
	channel/task parameters change. After a setup is performed, a channel
	returns SETUP_OK, or some type of error message, like ENOTREGISTER,
	etc.

	2) STOP: Stop what the task is doing, unregister itself with any tasks
	that it registered to, also tell any task which it is producing data for
	that it has been unregistered (via UNREGISTER message)

	3) UNREGISTERED: When this message is received, the received task just
	got unregistered by another task who was producing data for it. This 
	should usually not happen, unless COMMAND task is incorrectly written.

	4) REGISTER: Another task is requesting to be registered as a consumer
	of data that this task is producing. The task that receives this
	message must add the consumer task to its list of tasks to wake up when
	data arrives. On successful register, return REGISTER_OK

	5) NEW_DUMP: This message is received by the consumer task when the
	producer task has new IQ data available.

	6) NEW_MEAS: This message is received by the consumer task when the
	producer task has new measurement data available.

	-----------------

	All tasks must be able to handle the above mentioned messages
	correctly. Tasks can also add task-specific messages, like whenever a
	survey has completed scanning all doppler and code then it can send
	back a message to the task that called SETUP that is is DONE.

	If a consumer task wants to register itself with another task, it needs 
	to send a message of type REGISTER to producer task TASK. In order for
	this to happen, it needs to know from which task it is supposed to get
	data from, how many samples it wants, and which channels it wants this
	data from. Any task can access these values by using the argument that
	was passed to it at initialisation-time to index into a structure that
	contains this data. This structure will look something like:

	typedef struct {
		RT_TASK* producerTask; // contains pointer to producer task 
		RT_TASK* consumerTask; // contains pointer to consumer task 
		UINT16 dataUsed; // MEASUREMENT, DUMP (#define somewhere)
		UINT16 channelsUsed; //ea. bit indicates which channel data it
				      // needs
		UINT16 samplesUsed; // # of dataUsed samples needed

		/* linked list info here */
	} CONSUMER; // data the producer access from the consumer TASK_DATA
			// in order to fill in its own REGISTERED block 
			// consumer data, basically.

	typedef struct {
		CONSUMER* runTask; // pointer to consumer tasks REGISTER_TO
		// data. Producer can use this to figure out whether it should
		// wake up this consumer or not.
		UINT16 count; // number of samples collected for this task
		// ** LINKED LIST INFO HERE **
	} PRODUCER; // data the producer uses to message tasks whenever new
		      // data is available.
		     // producer data, basically

	typedef struct {
		CONSUMER consumer; //data consumer fills in
		PRODUCER producer; //data producer fills in
	} GPS_TASK


	GPS_TASK will always be initialised as a static array of size, say, 50.
	Initially consumerTask* and producerTask* will be NULL, indicating an  
	invalid task. Once a task is run for the first time, it will initialise 
	the consumerTask pointer to itself. Thus no other tasks need to worry
	that this pointer is not initialised. The correct GPS_TASK array
	element is accessed by indexing into the GPS_TASK array with the
	current tasks taskid (RT_TASK->tid). 

	Once the producer task receives this REGISTER call, it accessess the
	consumer tasks' GPS_TASK structure (GPS_TASK[consumer_tid].consumer) and sees
	whether consumer[i].producerTask matches the current task, if it does,
	then it adds the address in its own GPS_TASK structure's producer
	linked list. 

	Since PRODUCER will have a variable number of items, it must better be
	a linked list. This way Items can be easily added and removed at will.

	Now that the producer has a list of tasks that require information it
	produces, every time a new piece of data is produced, the producer
	steps through the task list stored in 'producer' and increments the
	counter of that task if it matches the data that was just produced. If
	the counter reaches samplesUsed, then a message is sent to wake up that
	task.
