Multi-file TEA Programming Using Reflexes Example
Last Modified: 2006-11-14
find:

basket

Acroname Robotics PDF webpage version Multi-file TEA Programming Using Reflexes Example PDF

Related
Products

Product image for Brainstem GP 1.0 Module
Brainstem GP 1.0 Module

Contents

Introduction

This example shows how to write a single TEA application with subroutines and functions located in several different TEA Files.  The code takes advantage of some of the multi-tasking features of the BrainStem.  It uses reflexes for controlling multi-file execution. 

A BrainStem GP 1.0 module has a size limit of 1K for executable TEA programs.  However, the GP 1.0 module is capable of running up to four programs concurrently.  By using this feature, one program can call another program as a subroutine.  This makes it possible to write an application that is larger than the 1K limit. 

A program can launch another program by triggering a reflex that issues a cmdVM_RUN command.  A program can write to a raw input port in order to trigger a reflex.  Reflexes can handle a maximum of two bytes as parameters.  Two bytes are enough to specify a file ID and process slot ID.  The parameter-substitution feature of a reflex makes it possible to write multiple bytes into a reflex command (or message).  This provides a method for launching any file in any process slot with a reflex that has only one vector and one message.  Programs can share additional data or pass extra parameters by using scratch pad RAM.  For an application that uses several concurrent processes, each process should receive input parameters in a reserved section of the scratch pad.  If a common area of RAM is used for passing input parameters to subroutines, it is possible that one process could corrupt the input of another. 

Source Code - Overview

A program acting as a subroutine can signal that it is finished by writing to the semaphore of the calling process.  In this example, the aMFR_Run function triggers a reflex to launch a subprogram then waits for its semaphore to be written.  The aMFR_Halt writes to the semaphore of the calling process and in doing so passes back a return value.  This requires a scratch pad byte to save the ID of the calling process.  When subroutines are small, several can be stored in a single TEA program.  A switch statement in the main routine can determine which subroutine to call.  This requires an extra scratch pad byte for the switch parameter. 

For completeness, the example code contains some routines that may be used to control persisting subprocesses.  These are processes that can continue running along with other processes.  The aMFR_Spawn routine triggers a reflex to launch a persisting subprocess.  The aMFR_Kill routine can kill a persisting subpocess. 

Using programs as subroutines is not as efficient as using normal subroutine calls.  There is much more overhead associated with subprocesses than with subroutines, although most of this burden is handled in firmware.  Managing subprocesses also requires more code.  Despite these drawbacks, the techniques in this example provide a effective way to expand a TEA project beyond the 1K limit per TEA file. 

The programming for this example consists of several source files.  Each one is described in detail below. 

Source Code - TEA Include File

The "aMFR_Def.tea" file contains message and vector IDs for the reflexes.  A user must make sure these IDs do not clash with any other reflexes. 

/* filename: aMFR_Def.tea */ #define MODULE 2 /******************************************/ /* USER MUST CHECK FOR MESSAGE ID CLASHES */ /******************************************/ #define aMFR_MSG_VMRUN 127 #define aMFR_MSG_VMKILL 126 /******************************************/ /* USER MUST CHECK FOR VECTOR ID CLASHES */ /******************************************/ #define aMFR_VEC_VMRUN 125 #define aMFR_VEC_VMKILL 124

Source Code - Reflex

The "aMFR.leaf" file contains message and vector defintions for the reflexes.  The "aMFR.bag" file contains the commands that store the reflex after compling the Leaf file with the Console application. 

#include <aCmd.tea> #include "aMFR_Def.tea" module[MODULE] { message[aMFR_MSG_VMRUN] { MODULE, cmdVM_RUN, 7, 0, 0 } message[aMFR_MSG_VMKILL] { MODULE, cmdVM_KILL, 0 } vector[aMFR_VEC_VMRUN] { aMFR_MSG_VMRUN[4] = int } vector[aMFR_VEC_VMKILL] { aMFR_MSG_VMKILL[3] = char } }

Compiling the LEAF file using the Console application should result in a BAG file that can be downloaded onto the BrainStem.  The result should be stored under the aObject folder as "aMRF.bag" and should look like the following:

/* filename: aMRF.bag */ // module 2 (2 messages, 2 vectors) // message 126 2 12 128 126 2 2 22 0 // message 127 2 12 0 2 4 21 7 0 0 2 12 134 127 // vector 124 2 11 128 124 254 243 // vector 125 2 11 128 125 255 244

Store the compiled reflex (aMRF.bag) onto the BrainStem by typing the following command into a Console window:

batch "aMFR.bag"

Source Code - TEA Wrapper Rountines to Trigger Reflexes

The "aMFR.tea" file has TEA wrapper routines that trigger the reflexes. 

/* filename: aMFR.tea */ void aMFR_Spawn(char cFile, char cProc) { asm { /* reflex to launch subtask */ pushss 4 popsm aPortRawInput + aMFR_VEC_VMRUN } } int aMFR_Run(char cFile, char cProc) { int retval = 0; asm { /* reflex to launch subtask */ pushss 6 popsm aPortRawInput + aMFR_VEC_VMRUN /* expect return value so block on semaphore */ pushms aPortProcID pushls aPortSemaphore adds pushmsx popss 2 } return retval; } void aMFR_Kill(char cProc) { asm { /* reflex to kill subtask */ pushsb 3 popsm aPortRawInput + aMFR_VEC_VMKILL } } void aMFR_Halt(char callingProcID, int retval) { asm { pushss 4 pushsb 7 convbs pushls aPortSemaphore adds popsmx } }

Source Code - TEA Subroutine and Function Routines

The "mfrx.tea" file contains subroutine and function declarations that wrap the reflex-based multi-tasking routine calls.  Common defined values and include statements are also stored in this file. 

/* filename: mfrx.tea */ #include <aCore.tea> #include <aPrint.tea> #include <aPad.tea> #include "aMFR_Def.tea" #include "aMFR.tea" /* subtasks are in files 1 and 2 */ /* subtasks run in process 1 */ /* 1 byte reserved for parameter passing */ #define SUB1FILE 1 #define SUB2FILE 2 #define SUBSPROC 1 #define SUBSPARAMCX 31 /* calling process ID */ /* functions are in file 3 */ /* functions run in process 2 */ /* 4 bytes reserved for parameter passing */ #define FUNCSFILE 3 #define FUNCSPROC 2 #define FUNCSPARAMCX 30 /* calling process ID */ #define FUNCSPARAMC1 29 /* 1-byte char param */ #define FUNCSPARAMI1 27 /* 2-byte int param */ int subtask1() { aPad_WriteChar(SUBSPARAMCX, aCore_Inportc(aPortProcID)); return aMFR_Run(SUB1FILE,SUBSPROC); } int subtask2() { aPad_WriteChar(SUBSPARAMCX, aCore_Inportc(aPortProcID)); return aMFR_Run(SUB2FILE,SUBSPROC); } int func0() { aPad_WriteChar(FUNCSPARAMCX, aCore_Inportc(aPortProcID)); aPad_WriteChar(FUNCSPARAMC1, 0); return aMFR_Run(FUNCSFILE,FUNCSPROC); } int func1(int n) { aPad_WriteChar(FUNCSPARAMCX, aCore_Inportc(aPortProcID)); aPad_WriteChar(FUNCSPARAMC1, 1); aPad_WriteInt(FUNCSPARAMI1, n); return aMFR_Run(FUNCSFILE,FUNCSPROC); }

Source Code - TEA Main Calling Routine

The "mfr0.tea" program is the main routine.  It calls subtasks and functions located in three different TEA Files.  It should be compiled and loaded into file slot 0. 

/* filename: mfr0.tea */ #include "mfrx.tea" void main() { func0(); func1(100); subtask1(); subtask2(); }

Source Code - TEA Subtask #1

The "mfr1.tea" program contains subtask 1.  It should be compiled and loaded into file slot 1. 

/* filename: mfr1.tea */ #include "mfrx.tea" void main() { aPrint_String("subtask 1\n"); aCore_Sleep(20000); func0(); func1(101); aMFR_Halt(aPad_ReadChar(SUBSPARAMCX),0); }

Source Code - TEA Subtask #2

The "mfr2.tea" program contains subtask 2.  It should be compiled and loaded into file slot 2. 

/* filename: mfr2.tea */ #include "mfrx.tea" void main() { aPrint_String("subtask 2\n"); aCore_Sleep(20000); func0(); func1(102); aMFR_Halt(aPad_ReadChar(SUBSPARAMCX),0); }

Source Code - TEA Function to Wrap Reflex Routines

The "mfrf.tea" program contains some functions that can be used by the main program or the subtasks.  It should be compiled and loaded into file slot 3.  This program contains more than one function.  The wrapper functions include a function code.  A case statement launches the appropriate routine based on that code. 

/* filename: mfrf.tea */ #include "mfrx.tea" int __func0() { aPrint_String("func0\n"); aCore_Sleep(10000); return 0; } int __func1(int n) { aPrint_String("func1 <- "); aPrint_IntDec(n); aPrint_Char('\n'); aCore_Sleep(10000); return 0; } void main() { char c1; int n; int retval=0; c1 = aPad_ReadChar(FUNCSPARAMC1); switch (c1) { case 0: { retval = __func0(); break; } case 1: { n = aPad_ReadInt(FUNCSPARAMI1); retval = __func1(n); break; } } aMFR_Halt(aPad_ReadChar(FUNCSPARAMCX), retval); }

Program Execution

Running this example requires compiling and loading several files.  The following batch files may be used to simplify this process. 

To execute the example, run the main program "mfr0.tea".  It will automatically run in process slot 0 and launch the other programs.  The subtasks are hard coded to run in process slot 1.  If one subtask tries to call the other subtask there will be a process slot conflict.  An error will occur and the program will halt.  The functions run in process slot 2.  The main program and the subtasks can call any of the functions since they run in their own unique process slot. 

This example program prints status messages indicating which routines are active.  It is only intended as a template for multi-file applications that use reflexes for program control. 

Revision History:

  • 2003-04-17: Example Created.
 

Related Examples:

Using Reflexes to configure IR transmit, receive and triggering a TEA program.

voice: 720-564-0373, email: sales@acroname.com, address: 4822 Sterling Dr., Boulder CO, 80301-2350, privacy
© Copyright 1994-2008 Acroname, Inc., Boulder, Colorado. All rights reserved.