previous page next page reference home emBASIC home page

12 Multitasking

This chapter describes how to use multitasking features of emBASIC.

12.1 TASK

Tasks are called at programmable time intervals, say all 30ms or all 10 minutes and deal with problems that have a pseudo-continuous effect, usually regulation tasks, filter functions, logging and supervision.

Once task is created a special system structure is created automatically to make a convenient access to the task parameters. Hence, if task “REGULATOR” is created a corresponding system structure @REGULATOR is available.

A task is written like a separate process and has its own isolated code segment. A Task has its personal ID and name associated with it. It gets an initial priority and an initial interval depending on the value of a time factor specified in @timefac system variable. Up to 16 tasks are allowed in emBASIC.

A TASK may be created either from WorkShop or manually using an emBASIC shell command:

!TASK name PRIO number ALL interval

with PRIO being an integer between -4 and 4 (lowest priority: -4, default: 0) and interval being a word (an unsigned 16 bit integer: 0..65536), thus allowing TASK repetition times of 10ms (lower system limit) to slightly more than a minute (65.535 seconds).

The "!" denotes a shell command to be executed immediately. The emBASIC command line prompt changes from the current "namespace" to the newly created one. Thus, if the TASK CREATE looks like:

main> !TASK regulator PRIO -2 ALL 3000

then the prompt would be   regulator>   thereafter and you would enter the TASKs or SEQUENCEs code body. To change back to main or to another TASK or SEQUENCE, enter

!EDIT taskname  - or
!EDIT task_id (as shown in 'ps' or @taskname.ID)

To prevent overrun conditions, tasks should not use WAIT constructions.

 

12.2 SEQUENCE

Sequences, however, run start to end from one step enabling condition to the next. They are used for sequential tasks in a typical manufacturing flow:

  • Wait for the part to arrive,
  • fix the part,
  • lower the drill,
  • drill a hole,
  • free the part again

- typically steps waiting for a certain time to elapse or a certain input to become active.

A SEQUENCE may be created either from WorkShop or manually using an emBASIC shell command:

!SEQUENCE name PRIO number

The "!" denotes a shell command to be executed immediately.

Once a SEQUENCE is created a special system structure is created automatically to make a convenient access to the sequence parameters. Hence, if the “CONTROLLER” sequence is created, a corresponding system structure @CONTROLLER is available.

The WAIT condition is typical for a SEQUENCE and a central feature of emBASIC.

EmBasic has a background mechanism to check the WAIT conditions for all SEQUENCEs. Sequences are prioritized so a higher priority sequence may preempt others.

12.3 Data associated with the task or sequence

Once a task or sequence is created a special system structure is created automatically to make a convenient access to the parameters.
The @SELF system structure points to the current task/sequence data and allows to change parameters of the current process.
A configuration parameter reference is a task/sequence system structure name followed by a period and a name:

@SELF.interval

@OtherTask.prio

The following list of parameters is associated with a task:

      @MyTask.ID process identifier system assigned
  @MyTask.NAME task name contains string “MyTask”
  @MyTask.PRIO task priority -4..4
  @MyTask.INTERVAL execution interval 10..65535ms
  @MyTask.LINE currently executed line of code First line = 1
  @MyTask.STATUS task state see table below
  @MyTask.ERRNO last runtime error number  
  @MyTask.ERRLINE runtime error line  

Possible task states:

  STATE_INIT = 0 No process (used as placeholder only)
  STATE_EMPTY = 1 process just created, has no statements yet
  STATE_IDLE = 2 process is ready to be executed (activated) but not yet scheduled
  STATE_MODIFIED = 3 body of task/sequence has been modified from the console or emBASIC WorkBench
  STATE_SUSPENDED = 4 process on hold with SUSPEND command
  STATE_TRAP = 5 process is being debugged, breakpoint is detected
  STATE_RUNNABLE = 6 process is ready to run and waiting to get the processor (the dispatcher assigns it the processor if it is the highest priority waiting process)
  STATE_SCHEDULED = 7 Process is waiting for scheduled time
  STATE_WAIT = 8 Sequence waits for input channel event (key pressed, or <CR> in INPUT, INKEY or INCHAR statements)
  STATE_BLOCKED = 9 process waits for (any) variable change. Generally, a process enters this state when a WAIT FOR statement is encountered

 

12.4 ACTIVATE

TASKs and SEQUENCEs do not start on their own, they have to be activated. Simple activation starts a TASK or a SEQUENCE with the start priorities, Activating an already running TASK or SEQUENCE restarts it from the first line.

ACTIVATE @drill

12.5 SUSPEND

A task or sequence can be suspended which means it is frozen after the line last executed and does not react to a WAIT condition. If it is suspended while WAITing, the WAIT condition will not be checked any further.

SUSPEND @regulator

Suspending an already suspended process does not have any effect.

12.6 RESUME

A RESUME is different from an ACTIVATE in that it makes a TASK or SEQUENCE continue where it left off. If the SEQUENCE is at a WAIT condition, a timeout is reset to its full value.

RESUME @drill_task

12.7 EXEC

EXEC is used to run a SEQUENCE or a TASK just once. If a sequence however contains message handlers and message wait is not disabled, the sequence continues waiting and processing network messages.

EXEC @my_task

12.8 TERMINATE

A TERMINATE statement immediately terminates a task or sequence. All output streams are flushed and the instruction pointer is reset.

TERMINATE @hang_task

12.9 TASKSTAT

### Replaced by:

nStatus = @<taskname>.STATUS

12.10 Change priority

Sometimes it is required to change the priority of a running process. To achieve this, use the following code:

@sometask.PRIO = 100

To change the own priority assign a new value to the @self.priority system variable:

@SELF.PRIO = 4

12.11 Change interval

Tasks are executed at programmable time intervals, which are defined at task creation. To change the execution interval from another emBASIC program use the following statement:

@TASK9.INTERVAL = 1000

The Interval value depends on the value of the time factor specified in the @timefac system variable.
To change the own interval assign a new value to the @interval system variable:

@SELF.INTERVAL = 1000

12.12 SCHEDULE

If you need to start a SEQUENCE at a fixed time of the day, the SCHEDULE function will do so based on the systems RTC.

 

5.8 The WAIT statement

WAIT stops processing a SEQUENCE until an expression is true.

WAIT [MAX timeout] FOR condition [THEN] statement(s) [ELSE statement(s)]

WAIT is used often in processes that control a mechanic flow to wait for some part to arrive at a detector switch. Given that "initiator3" is an i/o variable, the command would be:

WAIT FOR initiator3 == 1

emBASIC would then hold the SEQUENCE this command is encountered in and check the condition in regular intervals depending of the context and priority of the SEQUENCE.

Condition can be an expression involving a variable or process-i/o function. If the condition gets true, the statement(s) under the THEN clause is executed or, if there is no THEN clause, program flow would continue with the next statement after the WAIT.

The optional timeout clause of the WAIT statement allows to limit the time the statement waits for the condition to become true, the timeout is a DWORD given in milliseconds (max 49 days).

WAIT FOR switch == $OFF // infinite wait for switch off
WAIT MAX 60000 FOR switch == $OFF // 1-minute wait
WAIT MAX 1000 FOR switch == $ON THEN ACTIVATE @motor

In a multiline version of this statement, the THEN is (optionally ###?) omitted. Execution continues with the statements on the line after the current line if the event happens and on the line following the ELSE if the timeout is taken until the construct is finished with an END:

WAIT MAX 60000 FOR @mytask.state == $STATE_SUSPENDED
  PRINT “TASK IS SUSPENDED”
ELSE
  PRINT “SUSPEND TIMEOUT”
END

WAIT is a central statement for building sequential applications. A usual mechanical process does something like move a belt until a condition is met. While the condition is not yet true, the processor can serve other TASKs or SEQUENCEs allowing the virtually parallel execution of all of them.

Use caution with multiple condition statements as these might consume lots of processor time for regular condition checking.

Using Timers

While not directly connected to multitasking, another construct often used in emBASIC to synchronize processes is the timer. It is implemented as a data type and modified in the background by the system.

DECL downtimer3 AS ONESHOT TIMER INTERVAL 1000 DEC
downtimer3 = 30000    // downcount to 0 in 30 seconds
WAIT FOR some_input ==$ON
IF downtimer3 < 1 THEN ...

### Explain start assignment and overflow behaviour