DESCRIPTION: 	This file discusses how user input operates and which
		functions should be modified if more keywords are added. It also
		delves into the communication between user-land and rt-land in
		order to figure out which tasks to run.

AUTHOR:		Stephan Esterhuizen

DATE:		18 July 2003

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

-----------
INPUT FILES
-----------

The OpenGPS codes support reading certain parameters that specify code
operation from text files.

Currently these files include:

input/channels.txt
 - Channel properties, including PRN, which front end to use, doppler bin
 size, doppler window, etc.

input/readTask.txt
 - readTask is the main task that gets woken up every 500us and then
 decides whether new Measurement or IQ data is available. If any of this
 data is available it will wake up any tasks waiting for data. This file
 specify some basic properties of the readTask.

input/surveyTrackTask.txt
 - Survey parameters, including which channels to use, how many
 samples it needs, acquisition thresholds, etc.

input/carrierTrackTask.txt
 - Carrier tracking parameters

input/codeTrackTask.txt
 - Code tracking parameters

--------------
TYPES OF TASKS
--------------

non-command tasks : These are tasks like survey, carrierTrack, codeTrack. These
tasks are written in such a way that they always wait for a message from another
task to wake them up. For instance, carrierTask will not do anything until a
command task tells it to SETUP. When a SETUP message is received from a command
task, this non-command task will register itself with its producer (usually
readTask) and start working on IQ samples.

command tasks : These tasks always have a string that start with 'cmd'. This way
RTInit() knows that it should not start this task until all non-command tasks
have started (since command tasks assume that non-command tasks are ready to
accept messages). Command tasks usually call survey, acqusition, and carrier
tasks in a certain sequence - depending on the messages they return.

readTask : There will usually only be running one of these. This task is
responsible for obtaining IQ and MEASUREMENT samples and storing it in a
buffer. readTask runs periodically (every 500us) by itself.

-------------------
INPUT FILE FEATURES
-------------------

When processFile() encounters a :

STOP : It will automatically skip the rest of the file

@string [instance,instance] : It will save the previous task/chan data to the
global memory structure and start parsing the following keywords given the
string and instance numbers.


!KEYWORD1,KEYWORD2 : This means that KEYWORD1 and KEYWORD2 *must* be defined for
this file. If it is not defined you will get an error. Note: Now all keywords
are implemented. If you want processFile() to throw an error when your keyword
is not entered, you will have to add it to the printReqList() function in
readFiles.h (see Requirements List below for details)

# : A comment, the line will be skipped

keyword: value1, value2 : processTask() or processChan() will be called to
figure out whether this keyword is valid and should be saved.

-----------------------
INPUT PARSING OPERATION
-----------------------

The following two files contain all the input string parsing routines:

src/readFiles.c
include/readFiles.h

The function readFiles() is the main function, which opens the files and
calls processFile(file_descriptor). processFile() then reads the file
line-by-line and decides whether processChannel() or processTask() should
be called.

If Channel-like data is detected, processChannel() is called.
processChannel reads in channel-like keywords and saves it for later use.
Once EOF or another '@' character is detected, saveChannel() is called,
which actually saves the data into the corr->chan and param->chan global
memory structure.

If Task-like data is detected, processTask() is called. processTask()
reads in task-like data and stores it in the global Task[] structure for
access by rt-land.

The Task[] struct looks like this:

struct GPS_TASK {
	pNode *pDummy;
	CONSUMER cons;
	char name[MAX_NAME_LENGTH]; /* Task Name */
	INT16 instance; /* Instance of task */
	surveyData survey;
};

Please read messages.txt to get a better understanding of variables not
covered in this file.

-----------------
TASK NAME PARSING
-----------------

the 'name' variable contains a string with the task name. 'instance' tells
the program what instance of the task we are talking about.

As the input files are read, the line '@taskName[inst1,inst2,inst3]'
specifies task name and instances. readFiles.c will save the string
'taskName' in Task[someindex].name, and the instance number will be saved
in Task[someindex].instance. 'someindex' is sequentially incremented from 0 in
user land. Once RT-land takes over the Task[] structure, it actually rearanges
it so that any task can use its tid (rt_whoami()->tid) to access its task
variables.

Some other important variables are in the CONSUMER structure, accessed
via Task[index].cons.*

The consumer structure can be seen below:

struct GPS_CONSUMER {
	struct rt_task_struct *consTask; //pointer to consumer TASK (itself)
	struct rt_task_struct *prodTask; //pointer to producer TASK (who is producing data)
	char producerName[MAX_NAME_LENGTH]; /* Filled in by user land */
	INT16 producerInstance; /* Filled in by user land */

	INT16 numSamples; /* # of samples needed */
	UINT16 chanUsed; /* Channels data is read from, bit0=ch0, etc */
	enum messageType_t dataConsume; // type of message I consume
	enum messageType_t dataProduce[MAX_DATA_TYPES]; // type of messages I produce
};

consTask points to the current task. This pointer is not known to
user-land, but the string and instance of the producer is read from an
input file, thus the producerName and producerInstance will be read from
an input file and saved. It is the task of the rt-side of things then to
use producerName and producerInstance to figure out what the prodTask and
consTask pointer should be. This is done in RTInit() in rtproc.c

Actually when the user specifies that:

producerTask: readTask[0]

is it's producer, this gets saved in producerName and producerInstance.
Then during RTInit(), we search through the taskTable[] structure to see
what string matches what function pointer and RT_TASK block. taskTable[]
struct can be seen below:

/* Format:
 *  <taskString>, <RT_TASK pointer> <functionName>
 */
taskTable_t taskTable[]= {
	{ "readTask", 		_readTask,		readTask },
	{ "surveyTask", 	_surveyTask,	surveyTask },
};

Whenever a user adds another type of task that some task might want to
REGISTER with for data, the task must:

1) be added to this static list.  RT-land uses this table to correlate the 
string 'readTask' with what RT_TASK pointer to use and what function to call.

2) Create a new input file (taskname.txt) and add it to the readFiles() function
call.

3) If new keywords are needed, add these new keywords to processTask() and to
saveTask().

Note: If this new task is a command-type task, the string must start with 'cmd',
otherwise it won't be processed correctly by RTInit().

-----------------------
TOKEN AND VALUE PARSING
-----------------------

All keywords are read using the read_key_value_pair_* functions. These functions
take a keyword to extract and usually some type of variable to save the
keyword's value in.

For instance, in order to read the number of samples, you will need an entry
like this:

		/* -- numSamples -- */
        ret = read_key_value_pair_int( token, 
            "numSamples", &kw->Task.cons.numSamples.value, sep);

		if (ret) {
			kw->Task.cons.numSamples.changed=TRUE;
		} 

If the keyword was found, ret will be non zero and the integer value will be
saved in numSamples.value. You will note that numSamples is a structure with
three entries:

/* ---- cINT16_t ---- */
struct cINT16_t {
	INT16 value; /* value of variable */
	int changed; /* BOOLEN flag */
	int count[MAX_TASKS]; /* number of times changed */
};

value: this is contain the actual integer value
changed: this variable notifies readFiles.c that numSamples has changed.
count: with this array we keep track of how many times each instance of a value
were changed.

Going back to the /* -- numSamples -- */ code:

If we read "numSamples" correctly (if (ret)), then we set
numSamples.changed=TRUE. This is used by saveTask() to decide whether it should
update the global Task[] structure with a new value or not. Below follows and
example of why this is needed:

************

@ch[0,1,2]
# Satellite PRN
PRN: 2 

# Source Select
sourceSel: 0

# Minimum doppler to search, units (Hz)
dopplerWindowMin: -4000

# Maximum doppler to search, units (Hz)                         
dopplerWindowMax: +5000

@ch[0]
PRN: 23

@ch[1]
PRN: 26

@ch[2]
PRN: 30

************

In the above sample input file, we set the values for channels 0, 1, and 2. Now,
since we keep track of which variables have changed, this means that each
@ch[number] entry doesn't HAVE to contain all possible keywords. We can define a
global set of values and then OVERRIDE specific channel parameters with
individual @ch[number] commands.

-----------------
REQUIREMENTS LIST
-----------------

When a '!' is found, processFile() reads in a comma-separated list of strings.
Once EOF is detected, printReqList() is called. This function then compares
value.count with  each instances number and sees whether that instance changed
the required keyword. If the required keyword wasn't changed an error will be
thrown. Please note: if you add a new keyword to the !required list, then make
sure that the keyword exists in printReqList().
