You are previewing Practical UML Statecharts in C/C++, 2nd Edition.
O'Reilly logo
Practical UML Statecharts in C/C++, 2nd Edition

Book Description

Practical UML Statecharts in C/C++ Second Edition bridges the gap between high-level abstract concepts of the Unified Modeling Language (UML) and the actual programming aspects of modern hierarchical state machines (UML statecharts). The book describes a lightweight, open source, event-driven infrastructure, called QP that enables direct manual coding UML statecharts and concurrent event-driven applications in C or C++ without big tools.

This book is presented in two parts. In Part I, you get a practical description of the relevant state machine concepts starting from traditional finite state automata to modern UML state machines followed by state machine coding techniques and state-machine design patterns, all illustrated with executable examples. In Part II, you find a detailed design study of a generic real-time framework indispensable for combining concurrent, event-driven state machines into robust applications. Part II begins with a clear explanation of the key event-driven programming concepts such as inversion of control (”Hollywood Principle”), blocking versus non-blocking code, run-to-completion (RTC) execution semantics, the importance of event queues, dealing with time, and the role of state machines to maintain the context from one event to the next. This background is designed to help software developers in making the transition from the traditional sequential to the modern event-driven programming, which can be one of the trickiest paradigm shifts.

The lightweight QP event-driven infrastructure goes several steps beyond the traditional real-time operating system (RTOS). In the simplest configuration, QP runs on bare-metal microprocessor, microcontroller, or DSP completely replacing the RTOS. QP can also work with almost any OS/RTOS to take advantage of the existing device drivers, communication stacks, and other middleware. The accompanying website to this book contains complete open source code for QP, ports to popular processors and operating systems, including 80x86, ARM Cortex-M3, MSP430, and Linux, as well as all examples described in the book.

*Focuses on core concepts rather than tools which are always changing allowing the reader to continue to use this information with various projects
*Provides a complete, ready-to-use, open source software architecture for small and large embedded systems
*Includes an extensive example using the ARM Cortex-M3 throughout the book highlighting issues programmers and architects encounter in everyday life

Table of Contents

  1. Preface
    1. What's New in the Second Edition?
      1. New Code
      2. Open Source and Dual Licensing
      3. C as the Primary Language of Exposition
      4. More Examples
      5. Preemptive Multitasking Support
      6. Testing Support
      7. Ultra-Lightweight QP-nano Version
      8. Removed Quantum Metaphor
    2. What You Need to Use QP
    3. Intended Audience
    4. The Companion Websites
  2. Acknowledgments
  3. Copyright Page
  4. Introduction
    1. Inversion of Control
    2. The Importance of the Event-Driven Framework
    3. Active Object Computing Model
    4. The Code-Centric Approach
    5. Focus on Real-Life Problems
    6. Object Orientation
    7. More Fun
    8. How to Contact Me
  5. I. Uml State Machines
    1. I. UML State Machines
    2. 1. Getting Started with UML State Machines and Event-Driven Programming
      1. 1.1. Installing the Accompanying Code
      2. 1.2. Let's Play
        1. 1.2.1. Running the DOS Version
        2. 1.2.2. Running the Stellaris Version
      3. 1.3. The main() Function
      4. 1.4. The Design of the “Fly ‘n’ Shoot” Game
      5. 1.5. Active Objects in the “Fly ‘n’ Shoot” Game
        1. 1.5.1. The Missile Active Object
        2. 1.5.2. The Ship Active Object
        3. 1.5.3. The Tunnel Active Object
        4. 1.5.4. The Mine Components
      6. 1.6. Events in the “Fly ‘n’ Shoot” Game
        1. 1.6.1. Generating, Posting, and Publishing Events
      7. 1.7. Coding Hierarchical State Machines
        1. 1.7.1. Step 1: Defining the Ship Structure
        2. 1.7.2. Step 2: Initializing the State Machine
        3. 1.7.3. Step 3: Defining State-Handler Functions
      8. 1.8. The Execution Model
        1. 1.8.1. Simple Nonpreemptive “Vanilla” Scheduler
        2. 1.8.2. The QK Preemptive Kernel
        3. 1.8.3. Traditional OS/RTOS
      9. 1.9. Comparison to the Traditional Approach
      10. 1.10. Summary
    3. 2. A Crash Course in UML State Machines
      1. 2.1. The Oversimplification of the Event-Action Paradigm
      2. 2.2. Basic State Machine Concepts
        1. 2.2.1. States
        2. 2.2.2. State Diagrams
        3. 2.2.3. State Diagrams versus Flowcharts
        4. 2.2.4. Extended State Machines
        5. 2.2.5. Guard Conditions
        6. 2.2.6. Events
        7. 2.2.7. Actions and Transitions
        8. 2.2.8. Run-to-Completion Execution Model
      3. 2.3. UML Extensions to the Traditional FSM Formalism
        1. 2.3.1. Reuse of Behavior in Reactive Systems
        2. 2.3.2. Hierarchically Nested States
        3. 2.3.3. Behavioral Inheritance
        4. 2.3.4. Liskov Substitution Principle for States
        5. 2.3.5. Orthogonal Regions
        6. 2.3.6. Entry and Exit Actions
        7. 2.3.7. Internal Transitions
        8. 2.3.8. Transition Execution Sequence
        9. 2.3.9. Local versus External Transitions
        10. 2.3.10. Event Types in the UML
        11. 2.3.11. Event Deferral
        12. 2.3.12. Pseudostates
        13. 2.3.13. UML Statecharts and Automatic Code Synthesis
        14. 2.3.14. The Limitations of the UML State Diagrams
        15. 2.3.15. UML State Machine Semantics: An Exhaustive Example
      4. 2.4. Designing A UML State Machine
        1. 2.4.1. Problem Specification
        2. 2.4.2. High-Level Design
        3. 2.4.3. Scavenging for Reuse
        4. 2.4.4. Elaborating Composite States
        5. 2.4.5. Refining the Behavior
        6. 2.4.6. Final Touches
      5. 2.5. Summary
    4. 3. Standard State Machine Implementations
      1. 3.1. The Time-Bomb Example
        1. 3.1.1. Executing the Example Code
      2. 3.2. A Generic State Machine Interface
        1. 3.2.1. Representing Events
      3. 3.3. Nested Switch Statement
        1. 3.3.1. Example Implementation
        2. 3.3.2. Consequences
        3. 3.3.3. Variations of the Technique
      4. 3.4. State Table
        1. 3.4.1. Generic State-Table Event Processor
        2. 3.4.2. Application-Specific Code
        3. 3.4.3. Consequences
        4. 3.4.4. Variations of the Technique
      5. 3.5. Object-Oriented State Design Pattern
        1. 3.5.1. Example Implementation
        2. 3.5.2. Consequences
        3. 3.5.3. Variations of the Technique
      6. 3.6. QEP FSM Implementation
        1. 3.6.1. Generic QEP Event Processor
        2. 3.6.2. Application-Specific Code
        3. 3.6.3. Consequences
        4. 3.6.4. Variations of the Technique
      7. 3.7. General Discussion of State Machine Implementations
        1. 3.7.1. Role of Pointers to Functions
        2. 3.7.2. State Machines and C++ Exception Handling
        3. 3.7.3. Implementing Guards and Choice Pseudostates
        4. 3.7.4. Implementing Entry and Exit Actions
      8. 3.8. Summary
    5. 4. Hierarchical Event Processor Implementation
      1. 4.1. Key Features of the QEP Event Processor
      2. 4.2. QEP Structure
        1. 4.2.1. QEP Source Code Organization
      3. 4.3. Events
        1. 4.3.1. Event Signal (QSignal)
        2. 4.3.2. QEvent Structure in C
        3. 4.3.3. QEvent Structure in C++
      4. 4.4. Hierarchical State-Handler Functions
        1. 4.4.1. Designating the Superstate (Q_SUPER() Macro)
        2. 4.4.2. Hierarchical State-Handler Function Example in C
      5. 4.4.3. Hierarchical State-Handler Function Example in C++
      6. 4.5. Hierarchical State Machine Class
        1. 4.5.1. Hierarchical State Machine in C (Structure QHsm)
        2. 4.5.2. Hierarchical State Machine in C++ (Class QHsm)
        3. 4.5.3. The Top State and the Initial Pseudostate
        4. 4.5.4. Entry/Exit Actions and Nested Initial Transitions
        5. 4.5.5. Reserved Events and Helper Macros in QEP
        6. 4.5.6. Topmost Initial Transition (QHsm_init())
        7. 4.5.7. Dispatching Events (QHsm_dispatch(), General Structure)
        8. 4.5.8. Executing a Transition in the State Machine (QHsm_dispatch(), Transition)
      7. 4.6. Summary of Steps for Implementing HSMs with QEP
        1. 4.6.1. Step 1: Enumerating Signals
        2. 4.6.2. Step 2: Defining Events
        3. 4.6.3. Step 3: Deriving the Specific State Machine
        4. 4.6.4. Step 4: Defining the Initial Pseudostate
        5. 4.6.5. Step 5: Defining the State-Handler Functions
        6. 4.6.6. Coding Entry and Exit Actions
        7. 4.6.7. Coding Initial Transitions
        8. 4.6.8. Coding Internal Transitions
        9. 4.6.9. Coding Regular Transitions
        10. 4.6.10. Coding Guard Conditions
      8. 4.7. Pitfalls to Avoid While Coding State Machines with QEP
        1. 4.7.1. Incomplete State Handlers
        2. 4.7.2. Ill-Formed State Handlers
        3. 4.7.3. State Transition Inside Entry or Exit Action
        4. 4.7.4. Incorrect Casting of Event Pointers
        5. 4.7.5. Accessing Event Parameters in Entry/Exit Actions or Initial Transitions
        6. 4.7.6. Targeting a Nonsubstate in the Initial Transition
        7. 4.7.7. Code Outside the switch Statement
        8. 4.7.8. Suboptimal Signal Granularity
        9. 4.7.9. Violating the Run-to-Completion Semantics
        10. 4.7.10. Inadvertent Corruption of the Current Event
      9. 4.8. Porting and Configuring QEP
      10. 4.9. Summary
    6. 5. State Patterns
      1. 5.1. Ultimate Hook
        1. 5.1.1. Intent
        2. 5.1.2. Problem
        3. 5.1.3. Solution
        4. 5.1.4. Sample Code
        5. 5.1.5. Consequences
      2. 5.2. Reminder
        1. 5.2.1. Intent
        2. 5.2.2. Problem
        3. 5.2.3. Solution
        4. 5.2.4. Sample Code
        5. 5.2.5. Consequences
      3. 5.3. Deferred Event
        1. 5.3.1. Intent
        2. 5.3.2. Problem
        3. 5.3.3. Solution
        4. 5.3.4. Sample Code
        5. 5.3.5. Consequences
        6. 5.3.6. Known Uses
      4. 5.4. Orthogonal Component
        1. 5.4.1. Intent
        2. 5.4.2. Problem
        3. 5.4.3. Solution
        4. 5.4.4. Sample Code
        5. 5.4.5. Consequences
        6. 5.4.6. Known Uses
      5. 5.5. Transition to History
        1. 5.5.1. Intent
        2. 5.5.2. Problem
        3. 5.5.3. Solution
        4. 5.5.4. Sample Code
        5. 5.5.5. Consequences
        6. 5.5.6. Known Uses
      6. 5.6. Summary
  6. II. Real-Time Framework
    1. II. Real-Time Framework
    2. 6. Real-Time Framework Concepts
      1. 6.1. Inversion of Control
      2. 6.2. CPU Management
        1. 6.2.1. Traditional Sequential Systems
        2. 6.2.2. Traditional Multitasking Systems
        3. 6.2.3. Traditional Event-Driven Systems
      3. 6.3. Active Object Computing Model
        1. 6.3.1. System Structure
        2. 6.3.2. Asynchronous Communication
        3. 6.3.3. Run-to-Completion
        4. 6.3.4. Encapsulation
        5. 6.3.5. Support for State Machines
        6. 6.3.6. Traditional Preemptive Kernel/RTOS
        7. 6.3.7. Cooperative Vanilla Kernel
        8. 6.3.8. Preemptive RTC Kernel
      4. 6.4. Event Delivery Mechanisms
        1. 6.4.1. Direct Event Posting
        2. 6.4.2. Publish-Subscribe
      5. 6.5. Event Memory Management
        1. 6.5.1. Copying Entire Events
        2. 6.5.2. Zero-Copy Event Delivery
        3. 6.5.3. Static and Dynamic Events
        4. 6.5.4. Multicasting Events and the Reference-Counting Algorithm
        5. 6.5.5. Automatic Garbage Collection
        6. 6.5.6. Event Ownership
        7. 6.5.7. Memory Pools
      6. 6.6. Time Management
        1. 6.6.1. Time Events
        2. 6.6.2. System Clock Tick
      7. 6.7. Error and Exception Handling
        1. 6.7.1. Design by Contract
        2. 6.7.2. Errors versus Exceptional Conditions
        3. 6.7.3. Customizable Assertions in C and C++
        4. 6.7.4. State-Based Handling of Exceptional Conditions
        5. 6.7.5. Shipping with Assertions
        6. 6.7.6. Asserting Guaranteed Event Delivery
      8. 6.8. Framework-Based Software Tracing
      9. 6.9. Summary
    3. 7. Real-Time Framework Implementation
      1. 7.1. Key Features of the QF Real-Time Framework
        1. 7.1.1. Source Code
        2. 7.1.2. Portability
        3. 7.1.3. Scalability
        4. 7.1.4. Support for Modern State Machines
        5. 7.1.5. Direct Event Posting and Publish-Subscribe Event Delivery
        6. 7.1.6. Zero-Copy Event Memory Management
        7. 7.1.7. Open-Ended Number of Time Events
        8. 7.1.8. Native Event Queues
        9. 7.1.9. Native Memory Pool
        10. 7.1.10. Built-in “Vanilla” Scheduler
        11. 7.1.11. Tight Integration with the QK Preemptive Kernel
        12. 7.1.12. Low-Power Architecture
        13. 7.1.13. Assertion-Based Error Handling
        14. 7.1.14. Built-in Software Tracing Instrumentation
      2. 7.2. QF Structure
        1. 7.2.1. QF Source Code Organization
      3. 7.3. Critical Sections in QF
        1. 7.3.1. Saving and Restoring the Interrupt Status
        2. 7.3.2. Unconditional Locking and Unlocking Interrupts
        3. 7.3.3. Internal QF Macros for Interrupt Locking/Unlocking
      4. 7.4. Active Objects
        1. 7.4.1. Internal State Machine of an Active Object
        2. 7.4.2. Event Queue of an Active Object
        3. 7.4.3. Thread of Execution and Active Object Priority
      5. 7.5. Event Management in QF
        1. 7.5.1. Event Structure
        2. 7.5.2. Dynamic Event Allocation
        3. 7.5.3. Automatic Garbage Collection
        4. 7.5.4. Deferring and Recalling Events
      6. 7.6. Event Delivery Mechanisms in QF
        1. 7.6.1. Direct Event Posting
        2. 7.6.2. Publish-Subscribe Event Delivery
      7. 7.7. Time Management
        1. 7.7.1. Time Event Structure and Interface
        2. 7.7.2. The System Clock Tick and the QF_tick() Function
        3. 7.7.3. Arming and Disarming a Time Event
      8. 7.8. Native QF Event Queue
        1. 7.8.1. The QEQueue Structure
        2. 7.8.2. Initialization of QEQueue
        3. 7.8.3. The Native QF Active Object Queue
        4. 7.8.4. The “Raw” Thread-Safe Queue
      9. 7.9. Native QF Memory Pool
        1. 7.9.1. Initialization of the Native QF Memory Pool
        2. 7.9.2. Obtaining a Memory Block from the Pool
        3. 7.9.3. Recycling a Memory Block Back to the Pool
      10. 7.10. Native QF Priority Set
      11. 7.11. Native Cooperative “Vanilla” Kernel
        1. 7.11.1 The qvanilla.c Source File
        2. 7.11.2 The qvanilla.h Header File
      12. 7.12. QP Reference Manual
      13. 7.13. Summary
    4. 8. Porting and Configuring QF
      1. 8.1. The QP Platform Abstraction Layer
        1. 8.1.1. Building QP Applications
        2. 8.1.2. Building QP Libraries
        3. 8.1.3. Directories and Files
        4. 8.1.4. The qep_port.h Header File
        5. 8.1.5. The qf_port.h Header File
          1. Types of Platform-Specific QActive Data Members
          2. Base Class for Derivation of QActive
          3. The Maximum Number of Active Objects in the Application
          4. Various Object Sizes Within the QF Framework
          5. QF Critical Section Mechanism
          6. Include Files Used by this QF Port
          7. Interface Used Only Inside QF, But Not in Applications
          8. Active Object Event Queue Operations
          9. QF Event Pool Operations
        6. 8.1.6. The qf_port.c Source File
        7. 8.1.7. The qp_port.h Header File
        8. 8.1.8. Platform-Specific QF Callback Functions
          1. void QF_onStartup(void)
          2. void QF_onCleanup(void)
          3. void QF_onIdle(void) or void QF_onIdle(QF_INT_KEY_TYPE lockKey)
          4. void Q_onAssert(char const Q_ROM * const Q_ROM_VAR file, int line)
        9. 8.1.9. System Clock Tick (Calling QF_tick())
        10. 8.1.10. Building the QF Library
      2. 8.2. Porting the Cooperative “Vanilla” Kernel
        1. 8.2.1. The qep_port.h Header File
        2. 8.2.2. The qf_port.h Header File
        3. 8.2.3. The System Clock Tick (QF_tick())
        4. 8.2.4. Idle Processing (QF_onIdle())
      3. 8.3. QF Port to μC/OS-II (Conventional RTOS)
        1. 8.3.1. The qep_port.h Header File
        2. 8.3.2. The qf_port.h Header File
        3. 8.3.3. The qf_port.c Source File
        4. 8.3.4. Building the μC/OS-II Port
        5. 8.3.5. The System Clock Tick (QF_tick())
        6. 8.3.6. Idle Processing
      4. 8.4. QF Port to Linux (Conventional POSIX-Compliant OS)
        1. 8.4.1. The qep_port.h Header File
        2. 8.4.2. The qf_port.h Header File
        3. 8.4.3. The qf_port.c Source File
      5. 8.5. Summary
    5. 9. Developing QP Applications
      1. 9.1. Guidelines for Developing QP Applications
        1. 9.1.1. Rules
        2. 9.1.2. Heuristics
      2. 9.2. The Dining Philosopher Problem
        1. 9.2.1. Step 1: Requirements
        2. 9.2.2. Step 2: Sequence Diagrams
        3. 9.2.3. Step 3: Signals, Events, and Active Objects
        4. 9.2.4. Step 4: State Machines
        5. 9.2.5. Step 5: Initializing and Starting the Application
        6. 9.2.6. Step 6: Gracefully Terminating the Application
      3. 9.3. Running DPP on Various Platforms
        1. 9.3.1. “Vanilla” Kernel on DOS
        2. 9.3.2. “Vanilla” Kernel on Cortex-M3
        3. 9.3.3. μC/OS-II
        4. 9.3.4. Linux
      4. 9.4. Sizing Event Queues and Event Pools
        1. 9.4.1. In Sizing Event Queues
        2. 9.4.2. Sizing Event Pools
        3. 9.4.3. System Integration
      5. 9.5. Summary
    6. 10. Preemptive Run-to-Completion Kernel
      1. 10.1. Reasons for Choosing a Preemptive Kernel
      2. 10.2. Introduction to RTC Kernels
        1. 10.2.1. Preemptive Multitasking with a Single Stack
        2. 10.2.2. Nonblocking Kernel
        3. 10.2.3. Synchronous and Asynchronous Preemptions
        4. 10.2.4. Stack Utilization
        5. 10.2.5. Comparison to Traditional Preemptive Kernels
      3. 10.3. QK Implementation
        1. 10.3.1. QK Source Code Organization
        2. 10.3.2. The qk.h Header File
        3. 10.3.3. Interrupt Processing
        4. 10.3.4. The qk_sched.c Source File (QK Scheduler)
        5. 10.3.5. The qk.c Source File (QK Startup and Idle Loop)
      4. 10.4. Advanced QK Features
        1. 10.4.1. Priority-Ceiling Mutex
        2. 10.4.2. Thread-Local Storage
        3. 10.4.3. Extended Context Switch (Coprocessor Support)
      5. 10.5. Porting QK
        1. 10.5.1. The qep_port.h Header File
        2. 10.5.2. The qf_port.h Header File
        3. 10.5.3. The qk_port.h Header File
        4. 10.5.4. Saving and Restoring FPU Context
      6. 10.6. Testing the QK Port
        1. 10.6.1. Asynchronous Preemption Demonstration
        2. 10.6.2. Priority-Ceiling Mutex Demonstration
        3. 10.6.3. TLS Demonstration
        4. 10.6.4. Extended Context Switch Demonstration
      7. 10.7. Summary
    7. 11. Software Tracing for Event-Driven Systems
      1. 11.1. Software Tracing Concepts
      2. 11.2. Quantum Spy Software-Tracing System
        1. 11.2.1. Example of a Software-Tracing Session
        2. 11.2.2. The Human-Readable Trace Output
      3. 11.3. QS Target Component
        1. 11.3.1. QS Source Code Organization
        2. 11.3.2. The QS Platform-Independent Header Files qs.h and qs_dummy.h
        3. 11.3.3. QS Critical Section
        4. 11.3.4. General Structure of QS Records
        5. 11.3.5. QS Filters
          1. Global On/Off Filter
          2. Local Filters
        6. 11.3.6. QS Data Protocol
          1. Transparency
          2. Endianness
      4. 11.3.7. QS Trace Buffer
        1. Initializing the QS Trace Buffer QS_initBuf()
        2. Byte-Oriented Interface: QS_getByte()
        3. Block-Oriented Interface: QS_getBlock()
      5. 11.3.8. Dictionary Trace Records
        1. Object Dictionaries
        2. Function Dictionaries
        3. Signal Dictionaries
      6. 11.3.9. Application-Specific QS Trace Records
      7. 11.3.10. Porting and Configuring QS
      8. 11.4. The QSPY Host Application
        1. 11.4.1. Installing QSPY
        2. 11.4.2. Building QSPY Application from Sources
          1. Building QSPY for Windows with Visual C++ 2005
          2. Building QSPY for Windows with MinGW
          3. Building QSPY for Linux
        3. 11.4.3. Invoking QSPY
      9. 11.5. Exporting Trace Data to MATLAB
        1. 11.5.1. Analyzing Trace Data with MATLAB
        2. 11.5.2. MATLAB Output File
        3. 11.5.3. MATLAB Script qspy.m
        4. 11.5.4. MATLAB Matrices Generated by qspy.m
      10. 11.6. Adding QS Software Tracing to a QP Application
        1. 11.6.1. Initializing QS and Setting Up the Filters
        2. 11.6.2. Defining Platform-Specific QS Callbacks
        3. 11.6.3. Generating QS Timestamps with the QS_onGetTime() Callback
        4. 11.6.4. Generating QS Dictionary Records from Active Objects
        5. 11.6.5. Adding Application-Specific Trace Records
        6. 11.6.6. “QSPY Reference Manual”
      11. 11.7. Summary
    8. 12. QP-nano: How Small Can You Go?
      1. 12.1. Key Features of QP-nano
      2. 12.2. Implementing the “Fly ‘n’ Shoot” Example with QP-nano
        1. 12.2.1. The main() function
        2. 12.2.2. The qpn_port.h Header File
        3. 12.2.3. Signals, Events, and Active Objects in the “Fly ‘n’ Shoot” Game
        4. 12.2.4. Implementing the Ship Active Object in QP-nano
        5. 12.2.5. Time Events in QP-nano
        6. 12.2.6. Board Support Package for “Fly ‘n’ Shoot” Application in QP-nano
        7. 12.2.7. Building the “Fly ‘n’ Shoot” QP-nano Application
      3. 12.3. QP-nano Structure
        1. 12.3.1. QP-nano Source Code, Examples, and Documentation
        2. 12.3.2. Critical Sections in QP-nano
          1. Task-Level Interrupt Locking
          2. ISR-Level Interrupt Locking
        3. 12.3.3. State Machines in QP-nano
        4. 12.3.4. Active Objects in QP-nano
        5. 12.3.5. The System Clock Tick in QP-nano
      4. 12.4. Event Queues in QP-nano
        1. 12.4.1. The Ready-Set in QP-nano (QF_readySet_)
        2. 12.4.2. Posting Events from the Task Level (QActive_post())
        3. 12.4.3. Posting Events from the ISR Level (QActive_postISR())
      5. 12.5. The Cooperative “Vanilla” Kernel in QP-nano
        1. 12.5.1. Interrupt Processing Under the “Vanilla” Kernel
        2. 12.5.2. Idle Processing under the “Vanilla” Kernel
      6. 12.6. The Preemptive Run-to-Completion QK-nano Kernel
        1. 12.6.1. QK-nano Interface qkn.h
        2. 12.6.2. Starting Active Objects and the QK-nano Idle Loop
        3. 12.6.3. The QK-nano Scheduler
        4. 12.6.4. Interrupt Processing in QK-nano
        5. 12.6.5. Priority Ceiling Mutex in QK-nano
      7. 12.7. The PELICAN Crossing Example
        1. 12.7.1. PELICAN Crossing State Machine
        2. 12.7.2. The Pedestrian Active Object
        3. 12.7.3. QP-nano Port to MSP430 with QK-nano Kernel
        4. 12.7.4. QP-nano Memory Usage
      8. 12.8. Summary
  7. A. Licensing Policy for QP and QP-nano
    1. A.1. Open-Source Licensing
    2. A.2. Closed-Source Licensing
    3. A.3. Evaluating the Software
    4. A.4. Nonprofits, Academic Institutions, and Private Individuals
    5. A.5. GNU General Public License Version 2
  8. B. Guide to Notation
    1. B.1. Class Diagrams
    2. B.2. State Diagrams
    3. B.3. Sequence Diagrams
    4. B.4. Timing Diagrams
  9. Bibliography
    1. Bibliography