Building an executable process model for embedded devices

Use DITA, PHP, and blobs to build your model

The complexity facing embedded systems architects today is daunting because of added requirements in safety, reliability, and network accessibility. Yet, the tools typically used are often a step behind large-scale software spaces and do not provide the ability to transition smoothly between the detailed device level and a total system view. Learn how to use open source standards such as DITA and PHP and tools such as blob representations to create a system-level environment to address these needs.

Thomas G. Freund, System Architect, DigySol

Photo of Thomas G FreundThomas Freund has had a 35-year focus on software technology in control, monitoring, and diagnostics of industrial equipment as well as enabling Web access to them. He is also a member of the IEEE 1175.5 standard committee (CASE metamodel notation).



23 February 2010

Also available in Chinese Japanese Portuguese

The Darwin Information Typing Architecture (DITA) defines an XML architecture for designing, writing, managing, and publishing many kinds of information both in print and on the Web. It provides a way to organize knowledge about anything in an organization in a consistent structure that is computer sensible and that humans can understand. This organized knowledge can range from assembly instructions for a piece of machinery to procedures for billing customers or recipes for a chemical solvent.

Frequently used acronyms

  • DITA: Darwin Information Typing Architecture
  • DOM: Document Object Model
  • JAUS: Joint Architecture for Autonomous Systems
  • URI: Uniform Resource Identifier
  • XML: Extensible Markup Language

DITA is a collection of XML constructs that represents a variety of ways in which primarily textual knowledge can be structured and stored. These constructs are called topics—a unit of information that is self-contained and can, for example, answer a single question. Several topics can relate to each other by means of DITA maps, or documents that help you navigate among a series of topics.

Take the concept construct. You use this topic to provide background for understanding essential information about a product or process. Listing 1 shows an example of a concept topic for mechanical bearings.

Listing 1. A concept topic for mechanical bearings
<concept id="bearing"> 
     <title>Bearings</title> 
       <conbody> 
          <p>Bearings are a mechanism to minimize friction and 
               loss of rotational energy</p> 
          <example> 
               <p>Common bearings mechanisms</p> 
               <ul> 
                    <li>Ball bearing</li> 
                    <li>Roller bearing</li> 
                    <li>Needle bearing</li> 
               </ul> 
          </example> 
          <p>Fully mechanical bearings require lubrication</p> 
          <example> 
               <p>Common lubricants</p> 
               <ul> 
                    <li>oil</li> 
                    <li>lithium grease</li> 
               </ul> 
          </example> 
     </conbody> 
</concept>

Several kinds of topics are available, but the topic of interest in this article is the task topic.

Building a DITA task topic

The DITA task topic describes how to complete a procedure to accomplish a specific goal. In other words, it answers questions of the type, "How do I . . . " Its key constructs are:

  • <prereq>. Provides the information needed to start a process
  • <context>. Provides background information for carrying out the steps of a task
  • <steps>. Specific actions that must be followed to accomplish a task (Steps must contain one or more command—or <cmd>—elements describing the particular action that must be accomplished.)
  • <result>. The expected outcome for the task
  • <example>. An optional example illustrating use of the task
  • <postreq>. Optional tasks that can be performed after the successful completion of this task

Listing 2 provides an example of a task topic.

Listing 2. Example task topic
<task id='add_auto_oil'>
     <title>Adding oil to an auto engine </title>
     <taskbody>
          <prereq>Oil container with optional opener</prereq>
          <context>Dashboard oil light on or set amount of 
                                      mileage elapsed</context>
          <steps>
               <step id='open_hood'>
                    <cmd>Locate 'Open hood' lever.</cmd>
                    <cmd>Operate 'Open hood' lever.</cmd>
                    <cmd>Raise and retain hood in open position.</cmd>
               </step>
               <step id='open_oil_reserve'>
                    <cmd>Locate oil reserve cap.</cmd>
                    <cmd>Twist open oil reserve cap over
                                           oil reserve opening
                    </cmd> 
               </step>
               <step id='fill_oil_reserve'>
                    <cmd>Locate oil container</cmd>
                    <cmd>Open oil container</cmd>
                    <cmd>Place oil container spout over oil 
                                           reserve opening
                    </cmd>
                    <cmd>Remove oil container when empty</cmd>
               </step>
               <step id='close_oil_reserve'>
                    <cmd>Locate oil reserve cap.</cmd>
                    <cmd>Twist close oil reserve cap over oil 
                                           reserve opening
                    </cmd>
               </step>
               <step id='close_hood'>
                    <cmd>Close and lock hood</cmd>
               </step>
          </steps>
          <result>Dashboard light off or engine running quietly</result>
     </taskbody>
</task>

Tasks are adapted in this context to describe a system, and then converted to a useful executable form. A key component of this methodology is the use of blob representations in a relational database.

Incorporating blobs

In a relational database, a blob is a binary large object that can hold a variable amount of data and whose values are treated as binary, or byte, strings—in effect, any sequence of bytes whose value can range from 0x00 to 0xFF.

For example, you can store an image or machine language command sequence within a blob, with the maximum size typically not exceeding 65,536 bytes. A bite string larger that this will be truncated when stored in the appropriate row and column. What binds DITA tasks and blobs together in this context is the use of PHP, which maps tasks into a binary format.

The role of PHP

As mentioned, DITA is made up of XML constructs, one of which is the DITA task topic. What is needed is a streamlined tool to traverse the task structure. Enter PHP and its DOM traversal classes. Translating tasks into a useful structure is done through the strong parsing and DOM traversal capabilities of a command-line PHP script.

Putting it all together

Now that the key elements are in place, here's the methodology that puts it all together. Briefly, the contents of the DITA task topic are constrained to a computer-sensible structure, known as the recipe construct. Following that, you use a recipe construct support database and a compiler to translate the recipe construct into an executable format.


Enhancing the DITA task topic

The first step in enhancing your topic deals with the content of the DITA task topic elements. Going back to Listing 2, the contents of the elements use a free text format. You must change this format to a structured, computer-sensible format. The general description is in Listing 3.

Listing 3. Changing from a free to a structured format
<task> 
     <title>[resourceURI]</title> 
     <taskbody>
          <context>[cont_iteration_yes_no]</context>
          <prereq> [resource_list]</prereq>
          <steps>
               <step id=”[stepID]”>
                    <cmd>[precondition]|[action_list]</cmd>
                    ................................
                    <cmd>[precondition]|[action_list]</cmd>
               </step>
               ....................................
               <step id=”[stepID]”>
                    <cmd>[precondition]|[action_list]</cmd>
                    ................................
                    <cmd>[precondition]|[action_list]</cmd>
               </step>
          </steps>
          <result>[resourceURI]</result>
     </taskbody>
</task>

[resource_list] = [resourceURI],[qty] {| [resource_list]} 
[precondition] = [action]([parm_list]) 
[condition] = [action]([parm_list]) 
[action_list] = [condition]->[action]([parm_list]) {;  [action_list]} 
[parm_list] = [parm]{,[parm_list]}		 
[parm] = [resourceURI] or [stepID] or [literal] 
[literal] = text or number 
[resourceURI] = URN 
[stepID] = label 
[action] = label  
[qty] = number 
[cont_iteration_yes_no] = iterate or oneshot
iterate = repeat the steps in the sequence they appear continually
oneshot = repeat the steps in the sequence they appear only once

{...} = optional element(s)

In effect, the steps in a task are executed in the sequence stated in the task using the resources outlined under the <prereq> element. The <result> points to a resource that contains or is the result of operating this task, and <context> relates the number of times that this task operates (once or continually).

You use the precondition component in the <cmd> element to detect whether a particular condition is present prior to executing the rest of the command:

if [precondition] is true then perform [action_list]

Here, [action_list] is simply a set of rule structures in which the action to the left of the greater than (>) symbol returns a Boolean value (true or false); if that action returns a true value, the action to the right of the greater than (>) symbol is performed.

As an example, part of the task topic in Listing 2, when converted to a format consistent with Listing 3, becomes the code in Listing 4.

Listing 4. Recipe construct for a robotic oil cap opener
<task> 
     <title>urn:auto:oil:access</title> 
     <taskbody> 
          <context>oneshot</context> 
          <prereq>
               urn:robot:sense:image, 1 |
               urn:robot:arm, 2 |
               urn:auto:dashboard:hood_lever, 1 |
               urn:auto:engine:hood, 1 |
               urn:auto:engine:hood_lock, 1 |
               urn:auto:engine:oil_reserve_cap, 1 |
               urn:auto:engine:oil_reserve_intake, 1 |
               urn:robot:storage_pocket, 1
          </prereq> 
          <steps> 
               <step id='open_hood'> 
                    <cmd>
                    always() | always() ->
                         locate(urn:robot:sense:image,
                                urn:auto:dashboard:hood_lever)
                    </cmd>
                    <cmd>
                    always() | always() ->
                    activate(urn:robot:arm,
                              urn:auto:dashboard:hood_lever);
                         locate(urn:robot:sense:image,
                              urn:auto:engine:hood);
                    activate(urn:robot:arm,urn:auto:engine:hood)
                    </cmd>
                    <cmd>
                    fault_detected(urn:robot:sense:image) |
                    always() ->
                    report(urn:robot:sense:image);
                    always() -> shutdown(urn:robot);
                    </cmd> 
                    <cmd>
                    fault_detected(urn:robot:arm) |
                         status(urn:auto:engine:hood, "closed") ->
                         report(urn:robot:arm);
                         always() -> shutdown(urn:robot);
                    </cmd>
                    <cmd>
                    fault_detected(urn:robot:arm)|always() ->
                         lock(urn:robot:arm)
                    </cmd>
               </step>
          </steps>
          <result>urn:auto:engine:oil_reserve</result>
     </taskbody> 
</task>

where:

  • always() = always return a value of True
  • locate(resourceURI, resourceURI) = locate second resource using first resource
  • activate(resourceURI, resourceURI) = activate the second resource using the first resource
  • fault_detected(resourceURI) = returns True if a fault condition was detected in a resource
  • report(resourceURI) = broadcast a message giving the status of a resource
  • shutdown(resourceURI) = shut down a resource
  • lock(resourceURI) = freeze operation of a resource in its current state
  • move(resourceURI, resourceURI, resource URI) = move the second resource URI to the third resource URI (a container) using the first resource URI
  • turn(resourceURI, direction, final_state) = turn a resource in a direction (clockwise or counterclockwise) until a final state (open or close)

Listing 4 assumes that a robotic device exists that can perform the functions outlined in the steps of the auto oil filling task. These functions are defined in a supporting database used in translating the task into an executable form.

This code shows a one-step task that opens the auto hood (open_hood) and the oil reserve cap (open_oil_reserve). The commands in the first step (opening the hood), are:

  1. Use the robot's image sensor to unconditionally locate the lever to open the hood (locate function).
  2. Use the robot's arm to pull the hood lever (activate function), and then use the image sensor to position the robot at the hood (locate function).
  3. Use the robot arms to open the hood.

The remaining three commands deal with faulty behavior for either the robot image sensor or the arms. In both cases, the fault is reported (report function) and—in the case of the arms—the arms are mechanically locked into their current state (lock function). You use the fault_detected action to determine whether the robot is in a fault state before sensing what fault was encountered.

You can use this adaptation of the DITA task topic to describe any cyclical process that also covers contingencies—that is, recovery from anomalies. This adaptation is also the basis for the recipe construct.

Looking back at Listing 4, the process of adding oil to an auto engine is described with its core process (open hood, open oil reserve cap, add oil, close oil reserve cap, close hood), and each step can include procedures for handling out-of the-ordinary situations.

Briefly, that is a recipe construct—a DITA task topic whose element contents can be compiled into an executable form. Other things to note about a recipe construct are:

  • A recipe construct can invoke another recipe construct in an asynchronous manner—that is, a recipe construct can start the execution of another recipe construct in a separate thread of execution.
  • As a consequence, multiple recipe constructs can inherently run in a multitasking environment.
  • Because recipe constructs are referred through Uniform Resource Name (URN) addressing, a recipe construct can invoke another recipe construct remotely—that is, the invoked recipe construct is addressed through a network.

The execution space for a recipe construct, therefore, can range over a network of devices and operate as asynchronous tasks over that network.


Recipe-centered software

Recipe constructs are the basis for a process that converts a task description into an executable form targeted to a multitasking environment within a high-end (for example, 32-bit) microcontroller environment. Recipe constructs can be built by using either a text editor or a tool specifically geared to develop recipe constructs.

A recipe construct is analogous to a cooking recipe, in which ingredients are used in a set of steps that you must follow in a consistent sequence to arrive at a finished dish. In this case, a recipe construct uses an identified set of resources and steps to arrive at a desired result—a product or change in a monitored environment.

Start the recipe construct design process by outlining a set of high-end operations that resolve themselves into <task> constructs. An example can be a set of networked batch manufacturing machines used to bake a cake: a mixer, an oven, and a coater. You can specify the respective mixing, heating, and coating equipment operations—along with related equipment diagnostics—through <task> constructs similar to the contents of Listing 4.

As was done in Listing 4, the outlined functions will be stored in a recipe construct development database. This database, along with a recipe construct compiler, comprises the core of the recipe construct development environment. But first, you must understand the target environment for the compiled recipe constructs.

RecipeJAUS

Joint Architecture for Autonomous Systems (JAUS) is a standard developed through the U.S. Department of Defense that has the goal of a providing a consistent messaging framework between components of an autonomous system—primarily vehicles. It has been transformed into an open source technology through the advent of OpenJAUS (see the links in Resources for more information).

As it relates to recipe constructs, JAUS defines a command structure that operates like opcodes in the low-level machine language of, say, a microcontroller. Some JAUS commands have been adapted to provide a target platform for recipe constructs known as RecipeJAUS. It consists of an interpreter for the output of a recipe construct compiler coupled with an execution thread manager to handle recipe construct elements that can be multitasked. Finally, the recipe construct undergoes translation to a RecipeJAUS command sequence through a compiler and associated support database.

The packaging process

The recipe-centered software (RCS) database supports the recipe construct compilation process by translating functions used in recipe construct task steps into a corresponding RecipeJAUS command sequence. Listing 5 provides the metadata structure of the RCS database.

Listing 5. RCS database metadata structure
# 
#       RC support database schema 
# 
# 

DROP DATABASE IF EXISTS RCSDB; 
CREATE DATABASE RCSDB; 
USE RCSDB; 

# 
#     Source for a recipe using DITA task format 
# 
#     NOTES - 
# 
#          (1) DITARecipeID - resource URI assigned to the recipe 
# 

CREATE TABLE DITATaskRecipe 
( 
       DITARecipeID     VARCHAR(50) NOT NULL, 
     TaskRecipeBody     TEXT,      
     PRIMARY KEY (DITARecipeID ASC) 
}; 
 
# 
#     Compilation of a DITA recipe into RecipeJAUS code 
# 
#     NOTES - 
# 
#          (1) JAUSRecipeID - DITARecipeID + ":" + date-time stamp (YYYYMMDDHHMMSS) 
# 

CREATE TABLE JAUSRecipe 
( 
       JAUSRecipeID     VARCHAR(60)     NOT NULL, 
       DITARecipeID      VARCHAR(50)     NOT NULL, 
     JAUSPackage          BLOB,
     PRIMARY KEY     (JAUSRecipeID ASC) 
}; 

#
#     Catalog of all possible actions that can be incorporated in a recipe source
#     organized by domain and action ID
#
#     NOTES -
#
#          (1) DomainURI - URI for the domain of this action
#          (2) ActionID - label for this action
#          (3) ParmList - comma-delimited list of arguments for this action with
#                      each argument in resourceURI format. Position in
#                      the list is important since the position index
#                      is used in the JAUSMapping below
#          (4) JAUSMapping - parametrized code for this action with links 
#                      to ParmList entries. These links are in inserted
#                       as a hex byte in the appropriate parameter position
#                      of a JAUS opcode. The value of this byte
#                      is the position index (0x00 - 0xFF) in the ParmList
#                      above
#

CREATE TABLE ActionCatalog 
( 
       DomainURI               VARCHAR(50) NOT NULL, 
       ActionID             VARCHAR(50) NOT NULL, 
       ParmList          TEXT, 
       JAUSMapping            BLOB, 
       PRIMARY KEY (DomainURI ASC, ActionID ASC) 
}; 

# 
#     Catalog of all possible resource URIs that can be incorporated in a recipe source 
#     organized by domain and action ID 
# 
#     NOTES - 
# 
#          (1) DomainURI - URI for the domain of this action 
#          (2) ResourceID - URI for this parameter type 
#          (3) Units - measurement units for this resource 
#          [4] JAUSEncoding - target JAUS reference for this resource 
# 

CREATE TABLE ResourceCatalog 
( 
       DomainURI                 VARCHAR(50) NOT NULL, 
       ResourceID                  VARCHAR(50) NOT NULL, 
       Units               VARCHAR(22), 
     JAUSEncoding     BLOB, 
       PRIMARY KEY (DomainURI ASC, ResourceID ASC) 
};

The DITARecipe table is used to store recipe construct source task constructs, while the JAUSRecipe table is used to store the resulting packet sequence of a recipe construct. Thus, the recipe construct compiler keeps an archive of recipe constructs and their compiled output for reuse or for mapping a recipe construct design into a prior recipe construct with similar characteristics.

The ActionCatalog contains a parametrized RecipeJAUS command sequence for recipe construct step functions. The function definitions are targeted to a specific domain. So, for example, a function called lock for a robot domain (urn:robot) resource will have a different definition from a similarly named function but for an automated access domain (urn:access:door).

Similarly, the ResourceCatalog defines the URI for resources used within an application domain. It also provides an internal address reference (JAUSEncoding) within the RecipeJAUS platform for that resource. This reference corresponds to a physical connection that accesses that resource in the hardware platform operating the RecipeJAUS platform.

The RCS compiler

The RCS compiler is a PHP script that employs the DOM class and its methods to traverse the task construct of a recipe construct and formulate its RecipeJAUS packet sequence. The script is provided (see Download), and it is invoked using the PHP command-line interface (CLI) as follows:

php RCC.php <RC>.xml

<RC> is the name of the source file containing the recipe construct task construct. The output file with the RecipeJAUS step packet sequence is stored in the RCS database as a JAUSRecipe table record whose key is displayed in the console at the end of the compilation.

The RCS compiler is a prototype version that generates the RecipeJAUS sequences prior to conversion to RecipeJAUS code through the ResourceCatalog and ActionCatalog tables of the RCS database. It currently compiles a file with one task construct.


A sample recipe construct application

To illustrate the above recipe construct translation process, look at a sample application represented as a recipe construct along with its intermediate output prior to conversion into a RecipeJAUS command sequence.

Listing 6 provides the task, or recipe construct, description of a smart thermostat. It takes into account current temperature, current humidity, and current season of the year in determining the heating or air conditioning setting for the area being monitored.

Listing 6. The smart thermostat recipe construct
<task> 
     <title>urn:hvac:thermo>/title> 
     <taskbody> 
          <context>iterate</context> 
          <prereq> 
               urn:hvac:settings_lib,1| 
               urn:hvac:season_setting,1| 
               urn:hvac:tod_setting,1| 
               urn:hvac:temp_setting,1| 
               urn:hvac:hum_setting,1| 
               urn:hvac:temp_reading,1|
               urn:hvac:hum_reading,1| 
               urn:hvac:h_trigger,1| 
               urn:hvac:v_trigger,1|urn:hvac:ac_trigger,1 
          </prereq> 
          <steps> 
               <step id='S0'> 
                    <cmd>always() | always()->
                    get_setting(urn:hvac:settings_lib, 
                              urn:hvac:tod_setting,
                              urn:hvac:season_setting)
                    </cmd> 
                    <cmd> setting_set(urn:hvac:settings_lib,
                    urn:hvac:season_setting,urn:hvac:tod_setting) | 
                    always()-> 
                    set_setting(urn:hvac:settings_lib,
                              urn:hvac:temp_setting,
                              urn:hvac:hum_setting) 
                    </cmd> 
               </step> 
               <step id='S1'> 
                    <cmd> 
                    step_OK("S0") | always() ->
                    get_reading(urn:hvac:temp_reading,
                              urn:hvac:hum_reading) 
                    </cmd> 
                    <cmd> 
                    setting_at(urn:hvac:season_setting,"Fall") | 
                    reading(urn:hvac:hum_reading,A,
                         urn:hvac:hum_setting)->
                    set_trigger(urn:hvac:v_trigger);
                    reading(urn:hvac:hum_reading,B,
                         urn:hvac:hum_setting)->
                    reset_trigger(urn:hvac:v_trigger); 
                    reading(urn:hvac:temp_reading,B,
                         urn:hvac:temp_setting)->
                    set_trigger(urn:hvac:h_trigger); 
                    </cmd> 
               </step> 
               <step id='S2'> 
                    <cmd>
                    step_OK("S0") | always()->
                    get_reading(urn:hvac:temp_reading,
                         urn:hvac:hum_reading)
                    </cmd> 
                    <cmd>
                    setting_at(urn:hvac:season_setting,"Winter") | 
                    reading(urn:hvac:hum_reading,A,
                         urn:hvac:hum_setting)->
                    set_trigger(urn:hvac:v_trigger); 
                    reading(urn:hvac:hum_reading,B,
                         urn:hvac:hum_setting)->
                    reset_trigger(urn:hvac:v_trigger); 
                    reading(urn:hvac:temp_reading,B,
                         urn:hvac:temp_setting)->
                    set_trigger(urn:hvac:h_trigger); 
                    </cmd> 
               </step> 
               <step id='S3'> 
                    <cmd>step_OK("S0") | always()->
                    get_reading(urn:hvac:temp_reading,urn:hvac:hum_reading)
                    </cmd> 
                    <cmd> 
                    setting_at(urn:hvac:season_setting,"Spring") | 
                    reading(urn:hvac:hum_reading,A,
                         urn:hvac:hum_setting)->
                    set_trigger(urn:hvac:v_trigger);
                    reading(urn:hvac:hum_reading,B,
                         urn:hvac:hum_setting)->
                    reset_trigger(urn:hvac:v_trigger); 
                    reading(urn:hvac:temp_reading,A,
                         urn:hvac:temp_setting)->
                    set_trigger(urn:hvac:v_trigger); 
                    reading(urn:hvac:temp_reading,B,
                         urn:hvac:temp_setting)->
                    reset_trigger(urn:hvac:v_trigger) 
                    </cmd> 
               </step> 
               <step id='S4'> 
                    <cmd>
                    step_OK("S0") | always()->
                    get_reading(urn:hvac:temp_reading,urn:hvac:hum_reading)
                    </cmd> 
                    >cmd> 
                    setting_at(urn:hvac:season_setting,"Summer") | 
                    reading(urn:hvac:hum_reading,A,
                         urn:hvac:hum_setting)->
                    set_trigger(urn:hvac:v_trigger);
                    reading(urn:hvac:hum_reading,B,
                         urn:hvac:hum_setting)->
                    reset_trigger(urn:hvac:v_trigger); 
                    reading(urn:hvac:temp_reading,A,
                         urn:hvac:temp_setting)->
                    set_trigger(urn:hvac:ac_trigger); 
                       reading(urn:hvac:temp_reading,B,
                         urn:hvac:temp_setting)->
                    reset_trigger(urn:hvac:v_trigger) 
                    </cmd> 
               </step> 
          </steps> 
          <result>urn:hvac:comfort_setting</result> 
     </taskbody> 
</task>

where:

  • always() = always return a value of True
  • get_setting(resourceURI, resourceURI, resourceURI) = retrieve the settings for the second and third resources from the first resource (a reference structure)
  • setting_set(resourceURI, resourceURI, resourceURI) = return True if there are settings for the second and third resources based on the first resource
  • step_OK(step_ID) = return True if a step completed correctly
  • get_reading(resourceURI, resourceURI) = retrieve readings from two resources, both sensors
  • reading(resourceURI, comparator, resourceURI) = compare a reading from the first resource using the comparator operation (B = below, A = above) against the second resource (a reference value)
  • set_trigger(resourceURI) = enable resourceURI (relay switch behavior)
  • reset_trigger(resourceURI) = disable resourceURI (relay switch behavior)

This task uses the following resources in the HVAC domain, as outlined in the prereq element:

  • A settings library that includes a current time of day (tod_setting), current season (season_setting), temperature set point (temp_setting) , and humidity set point (hum_setting)
  • A sensed temperature reading (temp_reading)
  • A sensed humidity reading (hum_reading)

The settings library is a storage facility in the thermostat whose values are externally set either manually or through a network source through another task that precedes this one.

The task operates continuously per the value in the context element and accomplished its result—a comfort setting in the HVAC domain—through five steps:

  1. Retrieve unconditionally the current time-of-today and season settings from the settings library (using the setting_set function to query the availability of settings and set points and set_setting to retrieve the settings).
  2. Retrieve unconditionally the latest temperature and humidity sensor readings and, during the autumn season, activate external ventilation or heating based on the following conditions:
    • If humidity is not within the set point, turn on external ventilation.
    • If the temperature reading is below the set point, turn on heating.
  3. Retrieve unconditionally the latest temperature and humidity sensor readings and, during the winter season, activate external ventilation or heating based on the following conditions:
    • If humidity not within the set point, turn on external ventilation.
    • If the temperature reading is below the set point, turn on heating.
  4. Retrieve unconditionally the latest temperature and humidity sensor readings and, during the spring season, activate or deactivate the external ventilation based on the following conditions:
    • If the humidity is above the set point, turn on external ventilation.
    • If the humidity is below the set point, turn off external ventilation.
    • If the temperature reading is above the set point, turn on external ventilation.
    • If the temperature reading is below the set point, turn off external ventilation.
  5. Retrieve unconditionally the latest temperature and humidity sensor readings and, during the summer season, activate external ventilation or air conditioning based on the following conditions:
    • If humidity is not within the set point, turn on external ventilation.
    • If the temperature reading is above the set point, turn on air conditioning.
    • If the temperature reading is below the set point, turn on external ventilation.

The last four steps are designed to run in parallel with each other or as multithreaded command sequences.

Compiling the smart thermostat recipe construct

The compiler is invoked as follows:

cd <source_file_path>
php RCC.php Thermo.xml

Thermo.xml is the name of the source file containing the contents. The resultant RecipeJAUS step packet support file for the smart thermostat packet is in Listing 7. You use this code to create the RecipeJAUS packet sequence.

The RecipeJAUS packet sequence consists of 6 sections, each preceded by a byte count for each of the sections. The sections are:

  • the contents of the __URI__ section in Listing 7 translated into JAUSEncoding per the ResourceCatalog table in Listing 6
  • the setting in the __CTX__ section in Listing 7 translated to 0x00 (iterate) or 0x01 (oneshot)
  • the contents of the __RES__ section in Listing 7 translated into JAUSEncoding per the ResourceCatalog table in Listing 6
  • the contents of the __RSC__ section in Listing 7 organized with quantity as a one-byte entry followed by translated into JAUSEncoding per the ResourceCatalog table in Listing 6 for the resource URN for each resource
  • the contents of the __THR__ section in Listing 7 organized as a list of two-byte unsigned hex numbers corresponding to the step IDs with 0xFF indicating a break into the next multithreading level
  • the contents of the __CMD__ section translated to the corresponding RecipeJAUS code using the ActionCatalog table in Listing 6

The RecipeJAUS runtime environment is a essentially a thread manager coupled with a RecipeJAUS code interpreter that loads and executes a RecipeJAUS packet sequence.

Listing 7. The smart thermostat RecipeJAUS packet
__URI__ 
urn:hvac:thermo 
__CTX__ 
iterate 
__RES__ 
urn:hvac:comfort_setting 
__RSC__ 
urn:hvac:settings_lib_1 
urn:hvac:season_setting_1 
urn:hvac:tod_setting_1 
urn:hvac:temp_setting_1 
urn:hvac:hum_setting_1 
urn:hvac:temp_reading_1 
urn:hvac:hum_reading_1 
urn:hvac:h_trigger_1 
urn:hvac:v_trigger_1 
urn:hvac:ac_trigger_1 
__CMD__ 
always()_always()_get_setting(urn:hvac:settings_lib, 
urn:hvac:tod_setting, urn:hvac:season_setting)_S0:0 
setting_set(urn:hvac:settings_lib,urn:hvac:season_setting,urn:hvac:tod_setting)
_always()
_get_setting(urn:hvac:settings_lib,urn:hvac:temp_setting,urn:hvac:hum_setting)_S0:1 
step_OK("S0")_always()_get_reading(urn:hvac:temp_reading,urn:hvac:hum_reading)_S1:0 
setting_at(urn:hvac:season_setting,"Fall")
_reading(urn:hvac:hum_reading,A,urn:hvac:hum_setting)
_set_trigger(urn:hvac:v_trigger)_S1:1 
setting_at(urn:hvac:season_setting,"Fall")
_reading(urn:hvac:hum_reading,B,urn:hvac:hum_setting)
_reset_trigger(urn:hvac:v_trigger)_S1:2 
setting_at(urn:hvac:season_setting,"Fall")
_reading(urn:hvac:temp_reading,B,urn:hvac:temp_setting)
_set_trigger(urn:hvac:h_trigger)_S1:3 
setting_at(urn:hvac:season_setting,"Fall")
_reading(urn:hvac:hum_reading,A,urn:hvac:temp_setting)
_reset_trigger(urn:hvac:h_trigger)_S1:4 
step_OK("S0")_always()_get_reading(urn:hvac:temp_reading,urn:hvac:hum_reading)_S2:0 
setting_at(urn:hvac:season_setting,"Winter")
_reading(urn:hvac:hum_reading,A,urn:hvac:hum_setting)
_set_trigger(urn:hvac:v_trigger)_S2:1 
setting_at(urn:hvac:season_setting,"Winter")
_reading(urn:hvac:hum_reading,B,urn:hvac:hum_setting)
_reset_trigger(urn:hvac:v_trigger)_S2:2 
setting_at(urn:hvac:season_setting,"Winter")
_reading(urn:hvac:temp_reading,B,urn:hvac:temp_setting)
_set_trigger(urn:hvac:h_trigger)_S2:3 
setting_at(urn:hvac:season_setting,"Winter")
_reading(urn:hvac:hum_reading,A,urn:hvac:temp_setting)
_reset_trigger(urn:hvac:h_trigger)_S2:4 
step_OK("S0")_always()_get_reading(urn:hvac:temp_reading,urn:hvac:hum_reading)_S3:0 
setting_at(urn:hvac:season_setting,"Spring")
_reading(urn:hvac:hum_reading,A,urn:hvac:hum_setting)
_set_trigger(urn:hvac:v_trigger)_S3:1 
setting_at(urn:hvac:season_setting,"Spring")
_reading(urn:hvac:hum_reading,B,urn:hvac:hum_setting)
_reset_trigger(urn:hvac:v_trigger)_S3:2 
setting_at(urn:hvac:season_setting,"Spring")
_reading(urn:hvac:temp_reading,A,urn:hvac:temp_setting)
_set_trigger(urn:hvac:v_trigger)_S3:3 
setting_at(urn:hvac:season_setting,"Spring")
_reading(urn:hvac:hum_reading,B,urn:hvac:temp_setting)
_reset_trigger(urn:hvac:v_trigger)_S3:4 
step_OK("S0")_always()_get_reading(urn:hvac:temp_reading,urn:hvac:hum_reading)_S4:0 
setting_at(urn:hvac:season_setting,"Summer")
_reading(urn:hvac:hum_reading,A,urn:hvac:hum_setting)
_set_trigger(urn:hvac:v_trigger)_S4:1 
setting_at(urn:hvac:season_setting,"Summer")
_reading(urn:hvac:hum_reading,B,urn:hvac:hum_setting)
_reset_trigger(urn:hvac:v_trigger)_S4:2 
setting_at(urn:hvac:season_setting,"Summer")
_reading(urn:hvac:temp_reading,A,urn:hvac:temp_setting)
_set_trigger(urn:hvac:ac_trigger)_S4:3 
setting_at(urn:hvac:season_setting,"Summer")
_reading(urn:hvac:hum_reading,B,urn:hvac:temp_setting)
_reset_trigger(urn:hvac:ac_trigger)_S4 
__THR__ 
S0 
S1,S2,S3,S4 
__SRD__ 
S0|urn:hvac:settings_lib,urn:hvac:season_setting,urn:hvac:tod_setting,
urn:hvac:temp_setting,urn:hvac:hum_setting 
S1|urn:hvac:season_setting,urn:hvac:temp_setting,urn:hvac:hum_setting,
urn:hvac:temp_reading,urn:hvac:hum_reading,urn:hvac:h_trigger,urn:hvac:v_trigger 
S2|urn:hvac:season_setting,urn:hvac:temp_setting,urn:hvac:hum_setting,
urn:hvac:temp_reading,urn:hvac:hum_reading,urn:hvac:h_trigger,urn:hvac:v_trigger 
S3|urn:hvac:season_setting,urn:hvac:temp_setting,urn:hvac:hum_setting,
urn:hvac:temp_reading,urn:hvac:hum_reading,urn:hvac:v_trigger 
S4|urn:hvac:season_setting,urn:hvac:temp_setting,urn:hvac:hum_setting,
urn:hvac:temp_reading,urn:hvac:hum_reading,urn:hvac:v_trigger,urn:hvac:ac_trigger

This file has the following sections:

  • __URI__. The URN for this recipe
  • __CTX__. The execution context for this recipe
  • __RES__. The result URN for this recipe, where the contents of the output for this recipe are stored
  • __RSC__. The list of resource URNs used in this recipe
  • __CMD__. The list of precondition-condition-action triplets for all commands of this recipe (Note that the last entry indicates the step associated with a particular triplet.)
  • __THR__. Multithreading bundles for steps in this recipe
  • __SRD__. Step resource dependencies

The compiler converts the resources in __RSC__ into register addresses for the target RecipeJAUS platform through the ResourceCatalog table in the RCS database. It also converts the functions in __CMD__ to their RecipeJAUS equivalent through the ActionCategory and resolves the function parameters to locations in the converted __RSC__ list.

The __THR__ section shows the sequence of steps that can be executed in waves of multithreading. So, in Listing 6, step S0 is executed followed by steps S1 through S4, which are executed simultaneously.

The source code in PHP for the prototype compiler is available from Download.


Conclusion

Because of increasing demands in functionality, reliability, and safety, embedded systems developers need a methodology that captures both high-end and low-end system details while providing a total view of the system. This article outlined a methodology that adapts the DITA task topic as a recipe construct using PHP, a supporting compilation database to design and develop a total solution for complex embedded systems, and RecipeJAUS, an open platform that enables deployment of such systems. In addition, it's possible to extend this approach to a system on a large (enterprise) scale.


Download

DescriptionNameSize
Recipe construct prototype compilerRCC.zip4KB

Resources

Learn

Get products and technologies

  • IBM product evaluation versions: Download and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into XML on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML, Open source
ArticleID=468835
ArticleTitle=Building an executable process model for embedded devices
publish-date=02232010