HapticLib  0.7
Haptic Feedback Library for embedded systems
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Developer Guide

In this page are explained internal details of HapticLib. The Developer that wants to extend or modify the library will find this page useful.

SystemDesc system descriptor.

SystemDesc is a global structure holding the references of the application runtime state.

It holds a reference for each initialized haptor and a reference for each initialized pattern.

Using this variable all library code can interact with the rest of the system easily.

Additionally, here are stored the PWM driving signal frequency and the global inter-samples delay.

The scope of this variable would be global, but a preprocessor conditionally inclusion has been made to avoid the exposure of this variable to the user application code.

If the user needs access to this system variable, he must define the HL_SYSTEM_FILE preprocessor symbol on the module using it.

The actual structure definition of system_desc is the following:

   typedef struct system_desc {
        uint8_t              num_haptors;
        haptor_desc          haptors[MAX_HAPTORS];
        pattern_desc         patterns[MAX_HAPTORS];
        uint32_t             pwm_freq;
        uint8_t              samples_delay;
   } system_desc;

MAX_HAPTORS is a platform specific definition to limit the actual maximum number of haptors available.

Note:
Using static arrays to hold patterns and haptors references is not a smart way to use the memory resource. This way, irrespective of the actual number of haptors/patterns initialized, the maximum number of references is hold in memory. Future versions may include a dynamic memory allocator function, or directly link to a C library offering this kind of features (like the newlib C library).

Haptor Descriptor

SystemDesc holds a reference to each haptor initialized. The reference is a descriptor holding the following information about the haptor:

    typedef struct haptor_desc {
         uint8_t             id;
         uint16_t            min_duty;
         uint16_t            max_duty;
         pattern_desc       *activePattern;
         struct haptor_desc *nextHaptor;
        } haptor_desc;

min_duty and max_duty are useful to calibrate the range of operation of the physical device.

activePattern refer to the descriptor of the pattern attached to this haptor (if any).

nextHaptor is a reference to another haptor. This pointer creates a linked list of haptors belonging to the same group. It is used to implement multi-haptor patterns. (see below for further informations)

Pattern Descriptor

SystemDesc hold a reference to each active pattern in the running system.

The reference is a descriptor of a pattern holding the following data:

   typedef struct pattern_desc {
     pattern_name           name;
     user_param        *userParams;
     status_param           statusParams;
     pattern_continuator continuator;
     struct haptor_desc *activeHaptorList;
   } pattern_desc;

pattern_name is a numeric id (int) handled as enumeration ( pattern_name ) to make code cleaner and easy to read.

userParams is a reference to a structure holding the user provided parameters needed by the pattern.

Note:
user_param is defined by the pattern developer. The user application must conform to it. The actual variable holding this data is declared by the user in one of its modules ( generally main.c ) HapticLib just refers to it. ( refer below to understand why )

statusParams is a data structure holding the state of the pattern. This structure is defined by the pattern developer and is not exposed to the user.

continuator is a function pointer to the code that will be executed at every scheduled instant by this active pattern. If this pointer is NULL, then the system will consider this pattern not active.

the continuator is a function defined by the pattern developer and is not exposed to the user.

activeHaptorList points to the first haptor of the linked list forming the group of attached haptors. Using this list a pattern can easily developed as multi-haptor.

Pattern Rendering

When a pattern is initialized, an available slot on SystemDesc is searched for and, if found, the pattern goes there.

The pattern now has no haptor attached to it, so the user must add every haptor to it. At every call of hl_addHaptor() the linked-list is formed for later references by the pattern code.

Now the pattern is ready to be started for the actual rendering.

The rendering of a pattern has two main steps:

  • initiator
  • continuator

When the pattern is started, a function called pattern initiator is called to initialize the pattern initial status. userParams is used to set the initial status of the pattern that is hold in statusParams.

The initiator must set the pattern continuator on its pattern descriptor.

This operation is the actual start of the pattern, as the patternScheduler check for this pointer to be not-NULL to execute the pattern continuator code.

From now on, when the scheduler decides, the pattern continuator is executed.

The actual logic inside the continuator, is up to the pattern developer.

Usually the task carried by the continuator are:

  • read the user parameters for contingent run-time events.
  • update the status to reflect the time flow.
  • implement an exit strategy

The userParams polling is a key features to let the user drive the pattern logic ( as coded by the pattern developer ).

The exit strategy is a way for the pattern to self-deallocate from scheduling. This is not mandatory, but the pattern developer must explicitly document the behavior. For example, a pattern could self-stop after some time of execution. Another pattern could run indefinitely and stop only when the user forces its stop calling hl_stopPattern().

Develop a New Pattern Generator

To create a new pattern generator, the easy way is to copy an existing one and the modify it.

Here are the steps to implement a new test pattern generator:

  1. Create a new directory inside HapticLib/patterns: test2
  2. Create test2.c and test2.h source code files.
  3. add the new pattern in hl_patterns.c / hl_patterns.h

test2.h will contain the definitions of the new pattern:

  • test2StatusParameters
  • test2UserParameters (optional)
  • other optional structures or definitions needed by the pattern.

test2.c will contain at least initiator and continuator code:

  • test2PatternGenerator(): the initiator
  • test2Continuator(): the continuator
  • Doxygen embedded documentation to describe the pattern.

Be sure to implement a correct exit strategy on the continuator triggered by some event (could be a value on some userParam set by the user application code), or explicitly state on pattern documentation that the user must call hl_stopPattern() to stop it.

The documentation template is as follow:

  • Introduction
  • Theory
  • Optional Parameters
  • Usage Examples
  • Debugging Details
  • Additional Notes

Inside hl_patterns.h, references to the new pattern must be added in 4 points:

  • add an include to the header: #include "test2.h"
  • update pattern_name enumeration with the new pattern name before the last entry: Num_Patterns_Available.
  • update status_param union to contain the new statusParams.
  • update user_params (if any) to contain the new userParams.

Inside hl_patterns.c, the new pattern must be added in 2 points:

  • define a new extern pattern initiator
  • add the pointer to the patternMap

Adding a New Platform

Adding a new platform, like for patterns, consists in adding a new sub-directory inside HapticLib/platforms.

Warning:
As for now ( HapticLib v.0.7 ) a cleaner interface between the platform specific module and the rest of the library need to be defined. There are some direct references inside hapticLib.c that are platform specific and need to be moved.

HapticLib vs. bare application comparison

Comparison of HapticLevel demo application with a modified version of MEMS demo application from STM.

Instructions for HapticLevel compilation:

  • Download the workspace_keil.zip environment
  • Launch Keil project for HapticLevel demo
  • Set "REL" target, and compile
  • use arm-none-eabi-objcopy -I ihex HapticLevel.hex -O binary HapticLevel.bin
  • HapticLevel.bin is produced

Instructions for modified demo compilation:

  • Download original package from STM here
  • Download diff patch here
  • Unzip and go into the unzipped directory
  • Apply patch: patch -p1 < ../bare_app.patch
  • Start project using Keil project located in STM32F4-Discovery_FW_V1.1.0/Project/Peripheral_Examples/MEMS/MDK-ARM and compile.
  • launch arm-none-eabi-objcopy -I ihex LIS302DL.hex -O binary LIS302DL.bin inside STM32F4-Discovery_FW_V1.1.0/Project/Peripheral_Examples/MEMS/MDK-ARM/LIS302DL dir
  • LIS302DL.bin is produced