Author Topic: Starting/stoping/continuing task...  (Read 18589 times)

Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Starting/stoping/continuing task...
« on: September 08, 2007, 01:29:44 PM »
Hi mark,
  I have a task that will initially be in stop mode, and will be woken up in a certain condition. And when woken , it will have to have a limit number of times ran (like having a for/next loop of say 20), and say the 20th time ran it will have to be stopped. Is it possible to stop a running task from when in that task (if so how is this done)?

Also..
 Within the task (actually same task)is it possible to halt the task , and in another task wake it up to continue again, as an example (including above scenario) of what I wish, if possible:

  when a certain condition appears, start task...

Task routine (not a for/next loop inside task but uses a global counter for each time task ran):
1.  send data out on serial port..
2.  Halt task here, allowing other tasks to run..
3.  woken  up here by interupt (serial or timer)... (see below)
4.  has task ran 20 times
5.  If yes, then stop task...
6.  task routine finished.

Serial routine..
After serial sent , No 1 above, the serial routine will receive data, and restart the task, No3 above..

Second Timer interupt...
if serial not received data (above) in 'x' amount of seconds, the timeout flag set, and above task is started No 3..

Is the above possible? If so how is it done? Not the serial and timer interupts I can handle that no problem, its just the halt/continue/stop a task is the problem..

Regards
Neil

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: Starting/stoping/continuing task...
« Reply #1 on: September 08, 2007, 09:46:09 PM »
Hi Neil

I understand that you would like your task, which is initially 'sleeping' to be set to a run state and then 'poll' may be 20 times before being set back to the 'stop' state.

The task can control this itself by counting the number of times it has been called and setting itself to the stop state after the desired number of polling operations.

Eg.
Code: [Select]
#define RUN_TIMES 20

void fnMyTask(TTASKTABLE *ptrTaskTable)
{
    static int iRunTimes = RUN_TIMES;                    // the amount of times to poll when woken

    if (iRunTimes == RUN_TIMES) {                        // first time woken after sleeping
        uTaskerStateChange(OWN_TASK, UTASKER_GO);  // switch to polling mode
    }
    if (--iRunTimes == 0) {
        iRunTimes = RUN_TIMES;
        uTaskerStateChange(OWN_TASK, UTASKER_STOP); // go back to sleep and wait for next event to start polling mode again
    }
   
    // Do polling operation(s)

}

Assuming that this task is usually in the UTASKER_STOP it will need to be woken (by timer or event or another task setting it to the UTASKER_GO state). The task will set itself to the UTASKER_GO and run in polling mode RUN_TIMES and then set itself back to the sleep mode (UTASKER_STOP).

See also the LCD task in the demo project. It uses a similar technique to poll the busy bit of an LCD.
Originally it is sleeping, until woken up by a message from another task wanting to write something to the display. Some display command take a number of ms to complete so it switched itself to the UTASKER_GO state and effectively becomes a polling task. This means that it is scheduled as often as possible (but allowing other tasks to be scheduled in between) and simply reads the busy bit of the LCD waiting for it to indicate that the next command can be accepted. Once the LCD indicates that it can accept more commands the task continues sending them (eg. each character to be displayed has to be handled like this). Once the task has sent its last command or character to be displayed it switches itself to the UTASKER_STOP state where it sleeps again waiting for a new message to wake it.

Note that there is no risk for a task, or another one, to control the state of itself or another. If an event has already occured which will wake the task again it will not be lost.


More specifically to your requirement, your task will be woken by serial receptions and timer events so will each time be checking its serial and input queue.
When your task sends serial data it will probably set a local state variable to indicate that it has send and is waiting for either an answer or a time out. It can set itself here to polling mode if it wants but can also simply wait for one of the two events to occur in this state.Typically it will have started the monitoring timer when it sent its serial messange and can also kill this timer when the serial reception has been received before the timer actually fired.

At the moment I don't see the real advantage of polling but it should be clear that it is also possible if it is required.

Do you see all the information you need here or is there something which requires more detail?

Regards

Mark




Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Re: Starting/stoping/continuing task...
« Reply #2 on: September 09, 2007, 07:37:44 AM »
Hi mark,
  Thanks for the reply.
 
  The reason I need this , every 10 mins, I have to take 20 serial readings from an instrument through the uart. I have an interupt from a rtc (DS1337) every second , and when reaches 10 minutes the task is woken up from the IRQ (I am not using the internal RTC, for other reasons). When woken, the task will take one sample, then the next time the task is processed, it will take the next reading, and so on. When all 20 has been read, the task itself will be placed back into stop mode.

In your example :
void fnMyTask(TTASKTABLE *ptrTaskTable)
{
  ....
   if (iRunTimes == RUN_TIMES) {                        // first time woken after sleeping
        uTaskerStateChange(OWN_TASK, UTASKER_GO);  // switch to polling mode
    }
 ...
}

If the task is in stop mode, how can it waken itself up? I will plan to use the uTaskerStateChange(OWN_TASK, UTASKER_GO)  within the IRQ interupt from the RTC.  What is the difference between polling, and running? I thought the UTASKER_GO puts it into run mode?

Is it possible to Halt the thread, and another thread can restart it from the place halted? If so how is this done?

Neil

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: Starting/stoping/continuing task...
« Reply #3 on: September 09, 2007, 03:02:39 PM »
Hi Neil

It is correct that the task can not wake itself when it is not running, but the task can be woken by other tasks, timers, messages or events (by timer or event or another task setting it to the UTASKER_GO state).

When a task is in the UTASKER_GO state it is running continuously. I write 'polling' because it is not typical to run a task in the UTASKER_GO state since the task is running as often as it can get scheduled - which is usually only used (for short periods of time) when some hardware is being 'polled'.

At the bottom I have added a response to the question about whether a task can be halted.


Here is a suggestion as to how you can solve your concrete requirement. It uses one task with timer and input queue, started immediately once on start up and then on events only. There is also no reason why various other jobs can not be performed in the same task.

Code: [Select]
#define OWN_TASK         MY_TASK

#define INITIALISATION   0
#define IDLE             1
#define PERFORM_SEQUENCE 2

#define E_TIMER_TIMEOUT  1

#define E_START_SEQUENCE 1


void fnMyTask(TTASKTABLE *ptrTaskTable)                                  // Task configured to run once at start up and then sleep
{
    static unsigned char ucSerialInput[RX_BUFFER_SIZE];                  // static buffer for collecting UART data
    static int iSerialRxLenth = 0;                                       // length of collected UART data
    static int iRunTimes;
    static int iTaskState = INITIALISATION;
    static QUEUE_HANDLE SerialPortID;
    static QUEUE_HANDLE IICPortID;

    QUEUE_HANDLE        PortIDInternal = ptrTaskTable->TaskID;           // queue ID for task input
    unsigned char       ucInputMessage[RX_BUFFER_SIZE];                  // reserve space for receiving messages


    if (INITIALISATION == iTaskState) {                                  // configure interfaces on initialisation
        SerialPortID = fnConfigureAndOpenUART();
        IICPortID = fnConfigureAndOpenIIC();
        iTaskState = IDLE;
    }

    while ( fnRead( PortIDInternal, ucInputMessage, HEADER_LENGTH )) {   // check input queue
        switch ( ucInputMessage[ MSG_SOURCE_TASK ] ) {                   // switch depending on message source
        case TIMER_EVENT:                                                // timer event
            if (E_TIMER_TIMEOUT == ucInputMessage[ MSG_TIMER_EVENT ]) {  // no reception from serial port, quit present sequence
                iTaskState = IDLE;                                       // return to idle state
            }
            break;

        case INTERRUPT_EVENT:                                            // interrupt event
            if (E_START_SEQUENCE == ucInputMessage[MSG_INTERRUPT_EVENT]) { // wake up event message from RTC interrupt
                if (IDLE == iTaskState) {
                    fnStartIIC_Read();                                   // start read of IIC bus
                    iTaskState = PERFORM_SEQUENCE;                       // mark that we are in the repetition sequence
                    iRunTimes = 20;                                      // set repetition counter
                }
            }
            break;
        }
    }

    if ((PERFORM_SEQUENCE == iTaskState) && (fnMsgs(IICPortID) != 0)) {  // check IIC read completions
        QUEUE_TRANSFER LengthIIC;
        while (LengthIIC = fnRead(IICPortID, ucInputMessage, MEDIUM_MESSAGE)) {
            fnSendUART_Command(ucInputMessage, LengthIIC);
            uTaskerMonoTimer( OWN_TASK, (DELAY_LIMIT)(2*SEC), E_TIMER_TIMEOUT );// start monitor timer
        }
    }

    while (fnRead( SerialPortID, &ucSerialInput[iSerialRxLenth++], 1) != 0) { // collect serial port data
        if (fnMessageComplete(ucSerialInput, iSerialRxLenth) != 0) {
            fnProcessSerialData(ucSerialInput, iSerialRxLenth);
            iSerialRxLenth = 0;                                          // reset UART message length counter
            uTaskerStopTimer(OWN_TASK);                                  // stop monitor timer
            if (iRunTimes != 0) {
                iRunTimes--;                                             // count down repetitions
                fnStartIIC_Read();                                       // start next repetition of sequence
            }
            else {
                iTaskState = IDLE;                                       // this sequence complete
            }
        }
    }
}


There a few routines that need to be filled in depending on you exact requirements:

fnConfigureAndOpenUART(); This is the standard UART open which returns the handle to the opened interface.
fnConfigureAndOpenIIC(); This is the equivalent for the IIC interface - see the document
http://www.utasker.com/docs/uTasker/uTaskerIIC.PDF for more details.
fnStartIIC_Read(); This is a routine which sends the required IIC commands to initiate the read of the required data. The 'owner' task will be woken when the complete data is ready.
fnSendUART_Command(); sends the UART data, possibly including data which has just been received via IIC.
fnMessageComplete(); is a routine which is checking whether a complete UART message has been received (the operation depends on the protocol and this assumes that each byte is collected and the content analysed until complete.
fnProcessSerialData(); This routine is called when a complete UART rx message is ready and can verify and interpret the message as required. Note that a complete reception always kills the UART monitor timer.

The operation is completely event driven. The events are
  • E_START_SEQUENCE
your interrupt routine can kick the sequence off by sending this
  • IIC Rx message wake up
each time a complete IIC message (a read) is available the task is scheduled
  • UARTRx message wake up
each time a UART rx character is available the task is scheduled (assuming character mode)
  • E_TIMER_TIMEOUT
the UART monitor timer has fired without receiving a UART answer


A few other notes:
- iTaskState is almost superfluous but it is often useful to have a state as programs develop (sometimes it comes in useful where not initially expected).
- iRunTimes could also be integrated with the state (to save the variable) but this doesn't help readability.
- The program can be simulated using the uTasker simulator (the simulator included support for the DS1307 which seems to have the same IIC address as the DS1337) so it can be easily analysed in this mode.


Important discussion about halting tasks.

I have copied here a discussion about this. Basically it it about why the uTasker doesn't support pre-emptive multi-tasking including the reasons this way was chosen.

Regards

Mark



the uTasker is designed to be an easy to use operating system which is suitable for a high quantity of projects without the need of a good level of understanding of synchronisation issues. For this reason it is NOT-pre-emptive and doesn't support 'blocking'. There are a few disadvantages and some users with a lot of pre-emptive experience may find it a little restrictive. On the other hand it generally allows more efficient code and higher programming reliability due to the simplification is achieves.

Personally I have worked with several well known operating systems and have also written a pre-emptive OS for a DSP but have also recognised that about 95+% or real-world projects can easily (and often simpler) be achieved by using the 'super-loop' types strategy. I have been more surprised at the number of users who DON'T WANT (or don't need - as they usually say) an operating system. Many also have modules which they want to combine with the uTasker (such as open source protocol modules) which also assume a super-loop structure and so can be fit in with almost no effort but greatly optimised through replacement of polling tasks with the uTasker timers and interrupt event features. Would you believe that only about 2..3% of users even want to know whether the uTasker OS has pre-emptive capabilities? It has been a big eye-opener for me!!

The uTasker should offer an 'alternative' solution and not attempt to copy/replace/compete with others which are available. This is the path chosen and it has been very successful at achieving its goals (low support levels due to simplicity and low problem count due to the fact that users can not (easily) make errors which involve complex synchronisation issues).

One quick example (used in the demo project on the serial and Telnet ports) - rather than blocking on a tx queue there is a routine which checks whether there is space before sending data. If there is adequate space the driver is requested to inform when the space becomes available and the task is woken later to continue with the work. Such jobs involve a little more 'programmer' effort but are very workable in such situations. In fact a comparison of a uTasker based LAN<->RS232 product running on an ARM7 with 32k RAM achieved better and faster TCP<->RS232 throughput while performing file transfers than a well known ARM9 based device with MByte DRAM.

Other situations where time consuming calculations are performed by multiple tasks in parallel really requires a pre-emptive solution (there are methods which can and have been used to get around such issues in certain projects but these are a bit special and doesn't represent recommended or 'standard' procedures). Therefore there are certainly projects where the uTasker solution is less or NOT-suitable. It is however offered as an alternative and it is up to the user to decide its absolute suitability - there are many solutions available (with varying levels of performance, footprint size, complexity, price and support) and the uTasker solution tries to offer a simple, low-cost, well supported and open-source code one which is suitable for a large number of - but not all - projects.

Halting tasks during their execution (like sleep()) is something which is not supported. In exceptional cases, where it is the only viable solution it is possible to do this and schedule the OS itself from that code position (the OS is re-entrant) but this is the rather non-standard solution which is only used in emergencies, but can solve a critical point as long as it is restricted to only one (or maybe two) occurrences. Generally a state-event design [very well suited to communcation tasks] quite easily achieves the same results and is the recommended practice.

Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Re: Starting/stoping/continuing task...
« Reply #4 on: September 09, 2007, 08:20:42 PM »
Hi Mark,
  Thanks for the suggestion to my routine. Im really still getting used of doing things with tasks.. So please excuse my silly questions..

In your piece of code I understand the TIMER_EVENT which comes from the  uTaskerMonoTimer( OWN_TASK, (DELAY_LIMIT)(2*SEC), E_TIMER_TIMEOUT ); The INTERRUPT_EVENT is an interupt event, and the message E_START_SEQUENCE was passed to the task, but how do I pass the E_START_SEQUENCE message to the task ( I understand I can pass it from an IRQ for example, but what command to use)?

What is the fnMsgs(IICPortID)?

You mention it starts immediately once, then on Events only. I assume that this task is set to UTASKER_GO in the TaskTable, and is always getting called? So the message queue is checked to see if there are any messages, if not that task exits , else it deals with the messages . Then next time task is ran, same happens. Is this correct ?  I want to make sure I understand it okay...  :)

As this task is only started , say every 10 minutes, is it feesable to have the task in stop mode, and when the 10 minutes is up, set the task to UTASKER_GO, and within the task set it back to stop after the 20 samples have been carried out? The task still works the same but is only running when its time to sample.

Thanks
Neil



Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: Starting/stoping/continuing task...
« Reply #5 on: September 09, 2007, 10:02:22 PM »
Hi Neil

To send an INTERRUPT_EVENT of type E_START_SEQUENCE, use the command fnInterruptMessage(MY_TASK, E_START_SEQUENCE); from your ISR. If the ISR is not local to the task file, declare it in a project header like application.h. Check system interrupts at the bottom of driver.h - best avoid a colliding define by starting with a low value (from 1).

fnMsgs() returns the amount of waiting messages in the RX queue of the interface. The IIC driver works with messages of the length defined by the write command. When fnMsgs() returns 0 it means that the complete message is not yet available. When it returns 1 it means that a complete message is ready to be read using fnRead();
fnMsgs() is also described in the IIC document:  http://www.utasker.com/docs/uTasker/uTaskerIIC.PDF

The only reason to let the task run once is so that it can configure the interfaces. The interface handles can be local variables. It is of course also possible to perform the initialisation of the interfaces elsewhere (this usually requires the handles to be global variables or the use of cover functions) but it is more logical to perform the initialisation where the interfaces are actually used.

To schedule the task ONCE immediately, define the task like:
  { "My Task", fnMyTask, SMALL_QUEUE, (DELAY_LIMIT)(NO_DELAY_RESERVE_MONO), 0, UTASKER_ACTIVATE},

To schedule the task ONCE after an initial delay, like:
  { "My Task", fnMyTask, SMALL_QUEUE, (DELAY_LIMIT)(0.25 * SEC), 0, UTASKER_STOP},

UTASKER_ACTIVATE causes the task to be scheduled once and then automatically set back to the UTASKER_STOP state.

I see no advantage of ever using the UTASKER_GO state for your work because it will cause the task to be scheduled continuously, polling the queues (where events generally arrive) during that state. By letting the task be scheduled purely on events which are of interest to it it will only be run when it has something to actually do.

Regards

Mark

Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Re: Starting/stoping/continuing task...
« Reply #6 on: September 09, 2007, 10:38:06 PM »
Mark,
 
To schedule the task ONCE immediately, define the task like:
  { "My Task", fnMyTask, SMALL_QUEUE, (DELAY_LIMIT)(NO_DELAY_RESERVE_MONO), 0, UTASKER_ACTIVATE},

To schedule the task ONCE after an initial delay, like:
  { "My Task", fnMyTask, SMALL_QUEUE, (DELAY_LIMIT)(0.25 * SEC), 0, UTASKER_STOP},

UTASKER_ACTIVATE causes the task to be scheduled once and then automatically set back to the UTASKER_STOP state.

I see no advantage of ever using the UTASKER_GO state for your work because it will cause the task to be scheduled continuously, polling the queues (where events generally arrive) during that state. By letting the task be scheduled purely on events which are of interest to it it will only be run when it has something to actually do.

If the initialisation part is done globally, as the serial is also used elsewhere, I would therefore do the initialisation at another part. In this case I would do :
{ "My Task", fnMyTask, SMALL_QUEUE, (DELAY_LIMIT)(NO_DELAY_RESERVE_MONO), 0, UTASKER_STOP},


And the call fnInterruptMessage(MY_TASK, E_START_SEQUENCE); would wake it up and place it is UTASKER_GO, as the task has to be processed 20 times, this correct?

After the 20th time wouldnt I put the task back into UTASKER_STOP?

Neil


Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: Starting/stoping/continuing task...
« Reply #7 on: September 09, 2007, 10:49:18 PM »
Hi Neil

Quote
And the call fnInterruptMessage(MY_TASK, E_START_SEQUENCE); would wake it up and place it is UTASKER_GO, as the task has to be processed 20 times, this correct?

After the 20th time wouldnt I put the task back into UTASKER_STOP?

This is not exactly so because an interrupt event (or a timer or other wakeup event) doesn't set the task to UTASKER_GO, but to UTASKER_ACTIVATE.
UTASKER_ACTIVATE schedules the task just ONCE, after which it returns automatically to the UTASKER_STOP state (unless there are other events waiting or the task itself changes its own state). Therefore the task never needs to put itself back to the UTASKER_STOP state.

Regards

Mark

Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Re: Starting/stoping/continuing task...
« Reply #8 on: September 15, 2007, 08:29:53 PM »
Hi Mark,
  Your example below has the following:

while (fnRead( SerialPortID, &ucSerialInput[iSerialRxLenth++], 1) != 0) {
...
...
            }
   
You mention that the event gets woken up by timer, or interupt event. Would the task get woken up by a serial character coming in?

Neil

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: Starting/stoping/continuing task...
« Reply #9 on: September 15, 2007, 10:19:16 PM »
Hi Neil

As long as the UART interface has been configured to wake the task on every characters it will do so.

To wake on every character it must simply be set to character mode (in other modes it will be woken on a terminator character only) and the owner task must be entered:

tInterfaceParameters.usConfig = (CHAR_8 + NO_PARITY + ONE_STOP + CHAR_MODE);
tInterfaceParameters.Task_to_wake =
OWN_TASK;
SerialPortID = fnOpen( TYPE_TTY, ucDriverMode, &tInterfaceParameters );


These are the relevant lines which would cause the task "OWN_TASK" to be woken on each character reception.

Regards

Mark

Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Re: Starting/stoping/continuing task...
« Reply #10 on: June 03, 2008, 12:05:18 PM »
Hi Mark,
  I am starting my first task again (had a break for quiet a few months from utasker, another project came up, but now have time to start working on it again), and looked at this thread.

What I wish to do (just to get familiar with tasks again), is to have a serial task woken up with every key pressed. After the first key is pressed, a 5 second timer is set, and I have to press 'Enter' before the 5 seconds elapsed.

The task gets woken up okay with the key pressed, but doesnt get called when timer times out, here  is what I done:

#define TASK_OWNSERIAL         'O'
{ "OSerialComm",fnTaskSerialComm, SMALL_QUEUE,   0, 0,  UTASKER_STOP},     // and have included in node.

set up serial port to wake up task 'fnTaskSerialComm' when key pressed with following line:
tInterfaceParameters.Task_to_wake = TASK_OWNSERIAL;

Task rountine:
#define E_TIMER_TIMEOUT 1
void fnTaskSerialComm(TTASKTABLE *ptrTaskTable)
{
     unsigned char       ucInputMessage[RX_BUFFER_SIZE];                  // reserve space for receiving messages
     char Tmp[10];
     static char RecReturn=0,TimerOn=0;
     QUEUE_HANDLE        PortIDInternal = ptrTaskTable->TaskID;           // queue ID for task input
    
    while ( fnRead( PortIDInternal, ucInputMessage, HEADER_LENGTH ))
    {   // check input queue
        switch ( ucInputMessage[ MSG_SOURCE_TASK ] )
        {                   // switch depending on message source
           case TIMER_EVENT:                                                // timer event
               if (E_TIMER_TIMEOUT == ucInputMessage[ MSG_TIMER_EVENT ])
              { 
               if(!RecReturn) //only if Enter key not pressed.. BUT also left this out to make sure below called, but didnt work
                fnDebugMsg("\n\r   ** RET NOT ENTERED IN 5 SECONDS ** \n\r");
           
               RecReturn=TimerOn=0;   
            }
        }
    }
    
//serial catch here... simply display 'pressed' if a key is pressed...
     while (fnMsgs(SerialPortID))
     {
          fnRead( SerialPortID, &ucInputMessage[0], 1) ;
          if(ucInputMessage[0]==13)           
            RecReturn=1;
          
                 fnDebugMsg("pressed");
          
              if(!TimerOn)
          {
               uTaskerMonoTimer( TASK_OWNSERIAL, (DELAY_LIMIT)(5*SEC), E_TIMER_TIMEOUT );// start monitor timer
            TimerOn=1;
          }
   }
}



I tried removing the 'if(!TimerOn) ' and 'if(!RecReturn)' , and press key once,just to  make sure the timer gets called. But The timer never times out. I never get 'fnDebugMsg("\n\r   ** RET NOT ENTERED IN 5 SECONDS ** \n\r");'

I set  a breakpoint at when the timer gets called, so I know it does get called, and when it does, I then set breakpoint at start of task to catch timeout , which never gets called..

Can you point me to where I am going wrong?

Thanks
Neil
« Last Edit: June 03, 2008, 12:25:48 PM by neil »

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: Starting/stoping/continuing task...
« Reply #11 on: June 03, 2008, 01:01:51 PM »
Hi Neil

The problem is the definition of the task:

{ "OSerialComm",fnTaskSerialComm, SMALL_QUEUE,   0, 0,  UTASKER_STOP},

Here it is defined to have neither delayed start nor periodic timer. This means that it doesn't receive any resources for a timer of its own. The delay uTaskerMonoTimer( TASK_OWNSERIAL, (DELAY_LIMIT)(5*SEC), E_TIMER_TIMEOUT ); will therefore not work since it can not find a timer belonging to the task.

The following will assign the timer resource and I would expect it to then operate correctly.
{ "OSerialComm",fnTaskSerialComm, SMALL_QUEUE,   (DELAY_LIMIT)(NO_DELAY_RESERVE_MONO), 0,  UTASKER_STOP},

There is a relatively new guide here which may help:
http://www.utasker.com/docs/uTasker/uTaskerV1.3_user_guide.PDF

Regards

Mark

Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Re: Starting/stoping/continuing task...
« Reply #12 on: June 03, 2008, 01:05:02 PM »
Hi Mark,
  Thanks, that worked..

Neil