普通文本  |  977行  |  38.88 KB

# -*- coding: utf-8 -*-
#
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""This configuration file defines the gestures to perform."""

from collections import defaultdict
from firmware_constants import DEV, GV, VAL
from validators import (CountPacketsValidator,
                        CountTrackingIDNormalFingerValidator,
                        CountTrackingIDFatFingerValidator,
                        DragLatencyValidator,
                        DiscardInitialSecondsValidator,
                        DrumrollValidator,
                        HysteresisValidator,
                        LinearityFatFingerValidator,
                        LinearityNormalFingerValidator,
                        MtbSanityValidator,
                        NoGapValidator,
                        NoReversedMotionValidator,
                        PhysicalClickValidator,
                        PinchValidator,
                        RangeValidator,
                        ReportRateValidator,
                        StationaryValidator,
                        StationaryFingerValidator,
                        StationaryTapValidator,
)


# Define which score aggregator is to be used. A score aggregator collects
# the scores from every tests and calculates the final score for the touch
# firmware test suite.
score_aggregator = 'fuzzy.average'


# Define some common criteria
count_packets_criteria = '>= 3, ~ -3'
drumroll_criteria = '<= 2.0'
# linearity_criteria is used for strictly straight line drawn with a ruler.
linearity_criteria = '<= 0.8, ~ +2.4'
# relaxed_linearity_criteria is used for lines drawn with thumb edge or
# fat fingers which are allowed to be curvy to some extent.
relaxed_linearity_criteria = '<= 1.5, ~ +3.0'
no_gap_criteria = '<= 1.8, ~ +1.0'
no_level_jump_criteria = '<= 10, ~ +30'
no_reversed_motion_criteria = '<= 5, ~ +30'
pinch_criteria = '>= 200, ~ -100'
range_criteria = '<= 0.01, ~ +0.07'
min_report_rate = 60
max_report_interval = 1.0 / min_report_rate * 1000
report_rate_criteria = '>= %d' % min_report_rate
stationary_finger_criteria = '<= 1.0'
stationary_tap_criteria = '<= 1.0'
hysteresis_criteria = '<= 2.0'
drag_latency_criteria = '<= 28.0'

MIN_MOVING_DISTANCE = 20


# Define filenames and paths
docroot = '/tmp'
report_basename = 'touch_firmware_report'
html_ext = '.html'
ENVIRONMENT_REPORT_HTML_NAME = 'REPORT_HTML_NAME'
log_root_dir = '/var/tmp/touch_firmware_test'
fw_prefix = 'fw_'
device_description_dir = 'tests/device'
version_filename = '.version'


# Define parameters for GUI
score_colors = ((0.9, 'blue'), (0.8, 'orange'), (0.0, 'red'))
num_chars_per_row = 28


# Define the validators that are shown only when there are failures.
validators_hidden_when_no_failures = ['PinchValidator',
                                      'CountTrackingIDNormalFingerValidator',
                                      'CountTrackingIDFatFingerValidator',
                                      'CountPacketsValidator']


# Define the parent validators from which the derived validators should be
# merged in the top-level summary table.
merged_validators = [StationaryValidator,]


# Define the path to find the robot gestures library path
robot_lib_path_local = '/usr/local/lib*'
robot_lib_path = '/usr/lib*'
python_package = 'python*\.*'
gestures_sub_path = 'site-packages/touchbotII'


# Define the gesture names
NOISE_LINE = 'noise_line'
NOISE_STATIONARY = 'noise_stationary'
NOISE_STATIONARY_EXTENDED = 'noise_stationary_extended'
ONE_FINGER_TRACKING = 'one_finger_tracking'
ONE_FINGER_TO_EDGE = 'one_finger_to_edge'
TWO_FINGER_TRACKING = 'two_finger_tracking'
FINGER_CROSSING = 'finger_crossing'
ONE_FINGER_SWIPE = 'one_finger_swipe'
TWO_FINGER_SWIPE = 'two_finger_swipe'
PINCH_TO_ZOOM = 'pinch_to_zoom'
ONE_FINGER_TAP = 'one_finger_tap'
TWO_FINGER_TAP = 'two_finger_tap'
ONE_FINGER_PHYSICAL_CLICK = 'one_finger_physical_click'
TWO_FINGER_PHYSICAL_CLICK = 'two_fingers_physical_click'
THREE_FINGER_PHYSICAL_CLICK = 'three_fingers_physical_click'
FOUR_FINGER_PHYSICAL_CLICK = 'four_fingers_physical_click'
FIVE_FINGER_PHYSICAL_CLICK = 'five_fingers_physical_click'
STATIONARY_FINGER_NOT_AFFECTED_BY_2ND_FINGER_TAPS = \
        'stationary_finger_not_affected_by_2nd_finger_taps'
FAT_FINGER_MOVE_WITH_RESTING_FINGER = 'fat_finger_move_with_resting_finger'
DRAG_EDGE_THUMB = 'drag_edge_thumb'
TWO_CLOSE_FINGERS_TRACKING = 'two_close_fingers_tracking'
RESTING_FINGER_PLUS_2ND_FINGER_MOVE = 'resting_finger_plus_2nd_finger_move'
TWO_FAT_FINGERS_TRACKING = 'two_fat_fingers_tracking'
FIRST_FINGER_TRACKING_AND_SECOND_FINGER_TAPS = \
        'first_finger_tracking_and_second_finger_taps'
DRUMROLL = 'drumroll'
RAPID_TAPS = 'rapid_taps_20'
ONE_FINGER_TRACKING_FROM_CENTER = 'one_finger_tracking_from_center'
DRAG_LATENCY = 'drag_latency'
# This following gesture is for pressure calibration.
PRESSURE_CALIBRATION = 'pressure_calibration'

# The gaps in MM required between fingertips for these tests
FINGER_CROSSING_GAP_MM = 1
FAT_FINGER_AND_STATIONARY_FINGER_GAP_MM = 1

# This denotes the list of the numbers of fingers for physical click tests.
# It corresponds to ONE/TWO/THREE/FOUR/FIVE_FINGER_PHYSICAL_CLICK defined above.
fingers_physical_click = [1, 2, 3, 4, 5]


# Define the complete list
gesture_names_complete = {
    DEV.TOUCHPAD: [
        NOISE_LINE,
        NOISE_STATIONARY,
        ONE_FINGER_TRACKING,
        ONE_FINGER_TO_EDGE,
        TWO_FINGER_TRACKING,
        FINGER_CROSSING,
        ONE_FINGER_SWIPE,
        ONE_FINGER_TRACKING_FROM_CENTER,
        TWO_FINGER_SWIPE,
        PINCH_TO_ZOOM,
        ONE_FINGER_TAP,
        TWO_FINGER_TAP,
        ONE_FINGER_PHYSICAL_CLICK,
        TWO_FINGER_PHYSICAL_CLICK,
        THREE_FINGER_PHYSICAL_CLICK,
        FOUR_FINGER_PHYSICAL_CLICK,
        FIVE_FINGER_PHYSICAL_CLICK,
        STATIONARY_FINGER_NOT_AFFECTED_BY_2ND_FINGER_TAPS,
        FAT_FINGER_MOVE_WITH_RESTING_FINGER,
        DRAG_EDGE_THUMB,
        TWO_CLOSE_FINGERS_TRACKING,
        RESTING_FINGER_PLUS_2ND_FINGER_MOVE,
        TWO_FAT_FINGERS_TRACKING,
        FIRST_FINGER_TRACKING_AND_SECOND_FINGER_TAPS,
        DRUMROLL,
        RAPID_TAPS,
        DRAG_LATENCY,
    ],
    DEV.TOUCHSCREEN: [
        NOISE_LINE,
        NOISE_STATIONARY,
        ONE_FINGER_TRACKING,
        ONE_FINGER_TO_EDGE,
        TWO_FINGER_TRACKING,
        FINGER_CROSSING,
        ONE_FINGER_SWIPE,
        ONE_FINGER_TRACKING_FROM_CENTER,
        TWO_FINGER_SWIPE,
        PINCH_TO_ZOOM,
        ONE_FINGER_TAP,
        TWO_FINGER_TAP,
        STATIONARY_FINGER_NOT_AFFECTED_BY_2ND_FINGER_TAPS,
        FAT_FINGER_MOVE_WITH_RESTING_FINGER,
        DRAG_EDGE_THUMB,
        TWO_CLOSE_FINGERS_TRACKING,
        RESTING_FINGER_PLUS_2ND_FINGER_MOVE,
        TWO_FAT_FINGERS_TRACKING,
        FIRST_FINGER_TRACKING_AND_SECOND_FINGER_TAPS,
        DRUMROLL,
        RAPID_TAPS,
        DRAG_LATENCY,
    ],
}


# Define what gestures the robot can perform.
# This also defines the order for the robot to perform the gestures.
# Basically, two-fingers gestures follow one-finger gestures.
robot_capability_list = [
    NOISE_LINE,
    NOISE_STATIONARY,
    ONE_FINGER_TRACKING,
    ONE_FINGER_TO_EDGE,
    ONE_FINGER_SWIPE,
    ONE_FINGER_TRACKING_FROM_CENTER,
    ONE_FINGER_TAP,
    RAPID_TAPS,
    TWO_FINGER_TRACKING,
    TWO_CLOSE_FINGERS_TRACKING,
    TWO_FINGER_SWIPE,
    TWO_FINGER_TAP,
    STATIONARY_FINGER_NOT_AFFECTED_BY_2ND_FINGER_TAPS,
    FIRST_FINGER_TRACKING_AND_SECOND_FINGER_TAPS,
    RESTING_FINGER_PLUS_2ND_FINGER_MOVE,
    FINGER_CROSSING,
    PINCH_TO_ZOOM,
    DRUMROLL,
    TWO_FAT_FINGERS_TRACKING,
    FAT_FINGER_MOVE_WITH_RESTING_FINGER,
    ONE_FINGER_PHYSICAL_CLICK,
    TWO_FINGER_PHYSICAL_CLICK,
    THREE_FINGER_PHYSICAL_CLICK,
    FOUR_FINGER_PHYSICAL_CLICK,
]

NO_FINGER = None
TINY_FINGER = 0
NORMAL_FINGER = 1
LARGE_FINGER = 2
FAT_FINGER = 3
ALL_FINGERTIP_SIZES = [TINY_FINGER, NORMAL_FINGER, LARGE_FINGER, FAT_FINGER]
FINGERTIP_DIAMETER_MM = {TINY_FINGER: 8, NORMAL_FINGER: 10,
                         LARGE_FINGER: 12, FAT_FINGER: 14}

custom_tips_required = {
    DRAG_LATENCY: [NO_FINGER, NO_FINGER, FAT_FINGER, NO_FINGER],
    ONE_FINGER_PHYSICAL_CLICK: [NORMAL_FINGER, NO_FINGER, NO_FINGER, NO_FINGER],
    TWO_FINGER_PHYSICAL_CLICK: [NO_FINGER, NORMAL_FINGER, NO_FINGER,
                                NORMAL_FINGER],
    THREE_FINGER_PHYSICAL_CLICK: [NO_FINGER, NORMAL_FINGER, NORMAL_FINGER,
                                  NORMAL_FINGER],
    TWO_FAT_FINGERS_TRACKING: [FAT_FINGER, FAT_FINGER, FAT_FINGER, FAT_FINGER],
    FAT_FINGER_MOVE_WITH_RESTING_FINGER: [NORMAL_FINGER, NO_FINGER,
                                          FAT_FINGER, NO_FINGER],
    FINGER_CROSSING: [NORMAL_FINGER, NO_FINGER, NORMAL_FINGER, NO_FINGER],
    NOISE_LINE: [NO_FINGER, NORMAL_FINGER, NO_FINGER, NO_FINGER],
    NOISE_STATIONARY: [NORMAL_FINGER, NO_FINGER, NO_FINGER, NO_FINGER],
    NOISE_STATIONARY_EXTENDED: [NORMAL_FINGER, NO_FINGER, NO_FINGER, NO_FINGER],
}
default_tips_required = [NORMAL_FINGER, NORMAL_FINGER,
                         NORMAL_FINGER, NORMAL_FINGER]
finger_tips_required = defaultdict(lambda:default_tips_required,
                                   custom_tips_required)

def get_gesture_names_for_robot(device):
    """Get the gesture names that a robot can do for a specified device."""
    return [gesture for gesture in robot_capability_list
                    if gesture in gesture_names_complete[device]]


# Define the list of one-finger and two-finger gestures to test using the robot.
gesture_names_robot = {
    DEV.TOUCHPAD: get_gesture_names_for_robot(DEV.TOUCHPAD),
    DEV.TOUCHSCREEN: get_gesture_names_for_robot(DEV.TOUCHSCREEN),
}

gesture_names_quickstep = [DRAG_LATENCY]

# Define the list of gestures that require a function generator to run
gesture_names_fngenerator_required = [NOISE_LINE, NOISE_STATIONARY,
                                      NOISE_STATIONARY_EXTENDED]

# Define the list of gestures to test in NOISE mode.
gesture_names_noise_extended = [NOISE_STATIONARY_EXTENDED]


# Define the gesture for pressure calibration
gesture_names_calibration = [PRESSURE_CALIBRATION,]

# Define the relative segment weights of a validator.
# For example, LinearityMiddleValidator : LinearityBothEndsValidator = 7 : 3
segment_weights = {VAL.BEGIN: 0.15,
                   VAL.MIDDLE: 0.7,
                   VAL.END: 0.15,
                   VAL.BOTH_ENDS: 0.15 + 0.15,
                   VAL.WHOLE: 0.15 + 0.7 + 0.15,
}


# Define the validator score weights
weight_rare = 1
weight_common = 2
weight_critical = 3
validator_weights = {'CountPacketsValidator': weight_common,
                     'CountTrackingIDNormalFingerValidator': weight_critical,
                     'CountTrackingIDFatFingerValidator': weight_rare,
                     'DragLatencyValidator': weight_critical,
                     'DrumrollValidator': weight_rare,
                     'LinearityNormalFingerValidator': weight_common,
                     'LinearityFatFingerValidator': weight_rare,
                     'MtbSanityValidator': weight_critical,
                     'NoGapValidator': weight_common,
                     'NoReversedMotionValidator': weight_common,
                     'PhysicalClickValidator': weight_critical,
                     'PinchValidator': weight_common,
                     'RangeValidator': weight_common,
                     'ReportRateValidator': weight_common,
                     'HysteresisValidator': weight_common,
                     'StationaryFingerValidator': weight_common,
                     'StationaryTapValidator': weight_common,
}


# Define the gesture list that the user needs to perform in the test suite.
def get_gesture_dict():
    """Define the dictionary for all gestures."""
    gesture_dict = {
        NOISE_STATIONARY:
        Gesture(
            name=NOISE_STATIONARY,
            variations=((GV.LOW_FREQUENCY, GV.MED_FREQUENCY, GV.HIGH_FREQUENCY),
                        (GV.HALF_AMPLITUDE, GV.MAX_AMPLITUDE),
                        (GV.SQUARE_WAVE,),
                        (GV.TL, GV.TR, GV.BL, GV.BR, GV.TS, GV.BS, GV.LS, GV.RS,
                         GV.CENTER),
            ),
            prompt='Hold one finger on the {3} of the touch surface with a '
                   '{0} {1} {2} in noise.',
            subprompt={
                GV.TL: ('top left corner',),
                GV.TR: ('top right corner',),
                GV.BL: ('bottom left corner',),
                GV.BR: ('bottom right corner',),
                GV.TS: ('top edge',),
                GV.BS: ('bottom side',),
                GV.LS: ('left hand side',),
                GV.RS: ('right hand side',),
                GV.CENTER: ('center',),
                GV.LOW_FREQUENCY: ('5kHz',),
                GV.MED_FREQUENCY: ('500kHz',),
                GV.HIGH_FREQUENCY: ('1MHz',),
                GV.HALF_AMPLITUDE: ('10Vpp',),
                GV.MAX_AMPLITUDE: ('20Vpp',),
                GV.SQUARE_WAVE: ('square wave',),
            },
            validators=(
                DiscardInitialSecondsValidator(
                    CountTrackingIDNormalFingerValidator('== 1')),
                DiscardInitialSecondsValidator(
                    StationaryTapValidator(stationary_tap_criteria, slot=0)),
            ),
        ),
        NOISE_LINE:
        Gesture(
            name=NOISE_LINE,
            variations=((GV.LOW_FREQUENCY, GV.MED_FREQUENCY, GV.HIGH_FREQUENCY),
                        (GV.HALF_AMPLITUDE, GV.MAX_AMPLITUDE),
                        (GV.SQUARE_WAVE,),
                        (GV.BLTR,),
                        (GV.NORMAL,),
            ),
            prompt='Draw a straight line from {3} with a {0} {1} {2} in noise.',
            subprompt={
                GV.LOW_FREQUENCY: ('5kHz',),
                GV.MED_FREQUENCY: ('500kHz',),
                GV.HIGH_FREQUENCY: ('1MHz',),
                GV.HALF_AMPLITUDE: ('10Vpp',),
                GV.MAX_AMPLITUDE: ('20Vpp',),
                GV.SQUARE_WAVE: ('square wave',),
                GV.NORMAL: ('',),
                GV.BLTR: ('bottom left to top right',),
            },
            validators=(
                DiscardInitialSecondsValidator(
                    CountTrackingIDNormalFingerValidator('== 1')),
                DiscardInitialSecondsValidator(
                    LinearityNormalFingerValidator(linearity_criteria, finger=0,
                                                   segments=VAL.MIDDLE)),
                DiscardInitialSecondsValidator(
                    NoGapValidator(no_gap_criteria, slot=0)),
                DiscardInitialSecondsValidator(
                    NoReversedMotionValidator(no_reversed_motion_criteria,
                                              slots=0, segments=VAL.MIDDLE)),
                DiscardInitialSecondsValidator(
                    NoReversedMotionValidator(no_reversed_motion_criteria,
                                              slots=0, segments=VAL.BOTH_ENDS)),
                DiscardInitialSecondsValidator(
                    ReportRateValidator(report_rate_criteria)),
            ),
        ),
        NOISE_STATIONARY_EXTENDED:
        Gesture(
            name=NOISE_STATIONARY_EXTENDED,
            variations=(tuple(GV.EXTENDED_FREQUENCIES),
                        (GV.MAX_AMPLITUDE,),
                        (GV.SQUARE_WAVE,),
                        (GV.CENTER,),
            ),
            prompt='Hold one finger on the {3} of the touch surface with a '
                   '{0} {1} {2} in noise.',
            subprompt=dict({
                GV.CENTER: ('center',),
                GV.MAX_AMPLITUDE: ('20Vpp',),
                GV.SQUARE_WAVE: ('square wave',),
            }.items() +
                {freq: (freq,) for freq in GV.EXTENDED_FREQUENCIES}.items()),
            validators=(
                DiscardInitialSecondsValidator(
                    CountTrackingIDNormalFingerValidator('== 1')),
                DiscardInitialSecondsValidator(
                    StationaryTapValidator(stationary_tap_criteria, slot=0)),
            ),
        ),
        ONE_FINGER_TRACKING:
        Gesture(
            name=ONE_FINGER_TRACKING,
            variations=((GV.LR, GV.RL, GV.TB, GV.BT, GV.BLTR, GV.TRBL),
                        (GV.SLOW, GV.NORMAL),
            ),
            prompt='Take {2} to draw a straight, {0} line {1} using a ruler.',
            subprompt={
                GV.LR: ('horizontal', 'from left to right',),
                GV.RL: ('horizontal', 'from right to left',),
                GV.TB: ('vertical', 'from top to bottom',),
                GV.BT: ('vertical', 'from bottom to top',),
                GV.BLTR: ('diagonal', 'from bottom left to top right',),
                GV.TRBL: ('diagonal', 'from top right to bottom left',),
                GV.SLOW: ('3 seconds',),
                GV.NORMAL: ('1 second',),
            },
            validators=(
                CountTrackingIDNormalFingerValidator('== 1'),
                LinearityNormalFingerValidator(linearity_criteria, finger=0,
                                               segments=VAL.MIDDLE),
                NoGapValidator(no_gap_criteria, slot=0),
                NoReversedMotionValidator(no_reversed_motion_criteria, slots=0,
                                          segments=VAL.MIDDLE),
                NoReversedMotionValidator(no_reversed_motion_criteria, slots=0,
                                          segments=VAL.BOTH_ENDS),
                ReportRateValidator(report_rate_criteria),
            ),
        ),

        ONE_FINGER_TO_EDGE:
        Gesture(
            name=ONE_FINGER_TO_EDGE,
            variations=((GV.CL, GV.CR, GV.CT, GV.CB),
                        (GV.SLOW,),
            ),
            prompt='Take {2} to draw a striaght {0} line {1}.',
            subprompt={
                GV.CL: ('horizontal', 'from the center off left edge',),
                GV.CR: ('horizontal', 'from the center off right edge',),
                GV.CT: ('vertical', 'from the center  off top edge',),
                GV.CB: ('vertical', 'from the center off bottom edge',),
                GV.SLOW: ('2 seconds',),
            },
            validators=(
                CountTrackingIDNormalFingerValidator('== 1'),
                LinearityNormalFingerValidator(linearity_criteria, finger=0,
                                               segments=VAL.MIDDLE),
                NoGapValidator(no_gap_criteria, slot=0),
                NoReversedMotionValidator(no_reversed_motion_criteria, slots=0),
                RangeValidator(range_criteria),
                ReportRateValidator(report_rate_criteria),
            ),
        ),

        TWO_FINGER_TRACKING:
        Gesture(
            name=TWO_FINGER_TRACKING,
            variations=((GV.LR, GV.RL, GV.TB, GV.BT, GV.BLTR, GV.TRBL),
                        (GV.SLOW, GV.NORMAL),
            ),
            prompt='Take {2} to draw a {0} line {1} using a ruler '
                   'with TWO fingers at the same time.',
            subprompt={
                GV.LR: ('horizontal', 'from left to right',),
                GV.RL: ('horizontal', 'from right to left',),
                GV.TB: ('vertical', 'from top to bottom',),
                GV.BT: ('vertical', 'from bottom to top',),
                GV.BLTR: ('diagonal', 'from bottom left to top right',),
                GV.TRBL: ('diagonal', 'from top right to bottom left',),
                GV.SLOW: ('3 seconds',),
                GV.NORMAL: ('1 second',),
            },
            validators=(
                CountTrackingIDNormalFingerValidator('== 2'),
                LinearityNormalFingerValidator(linearity_criteria, finger=0,
                                               segments=VAL.MIDDLE),
                LinearityNormalFingerValidator(linearity_criteria, finger=1,
                                               segments=VAL.MIDDLE),
                NoGapValidator(no_gap_criteria, slot=0),
                NoGapValidator(no_gap_criteria, slot=1),
                NoReversedMotionValidator(no_reversed_motion_criteria, slots=0),
                NoReversedMotionValidator(no_reversed_motion_criteria, slots=1),
                ReportRateValidator(report_rate_criteria),
            ),
        ),

        FINGER_CROSSING:
        Gesture(
            # also covers stationary_finger_not_affected_by_2nd_moving_finger
            name=FINGER_CROSSING,
            variations=((GV.LR, GV.RL, GV.TB, GV.BT, GV.BLTR, GV.TRBL),
                        (GV.SLOW, GV.NORMAL),
            ),
            prompt='Place one stationary finger near the center of the '
                   'touch surface, then take {2} to draw a straight line '
                   '{0} {1} with a second finger',
            subprompt={
                GV.LR: ('from left to right', 'above the stationary finger'),
                GV.RL: ('from right to left', 'below the stationary finger'),
                GV.TB: ('from top to bottom',
                        'on the right to the stationary finger'),
                GV.BT: ('from bottom to top',
                        'on the left to the stationary finger'),
                GV.BLTR: ('from the bottom left to the top right',
                          'above the stationary finger',),
                GV.TRBL: ('from the top right to the bottom left',
                          'below the stationary finger'),
                GV.SLOW: ('3 seconds',),
                GV.NORMAL: ('1 second',),
            },
            validators=(
                CountTrackingIDNormalFingerValidator('== 2'),
                NoGapValidator(no_gap_criteria, slot=1),
                NoReversedMotionValidator(no_reversed_motion_criteria, slots=1),
                ReportRateValidator(report_rate_criteria, finger=1),
                StationaryFingerValidator(stationary_finger_criteria, slot=0),
            ),
        ),

        ONE_FINGER_SWIPE:
        Gesture(
            name=ONE_FINGER_SWIPE,
            variations=(GV.BLTR, GV.TRBL),
            prompt='Use ONE finger to quickly swipe {0}.',
            subprompt={
                GV.BLTR: ('from the bottom left to the top right',),
                GV.TRBL: ('from the top right to the bottom left',),
            },
            validators=(
                CountPacketsValidator(count_packets_criteria, slot=0),
                CountTrackingIDNormalFingerValidator('== 1'),
                NoReversedMotionValidator(no_reversed_motion_criteria, slots=0),
                ReportRateValidator(report_rate_criteria),
            ),
        ),

        TWO_FINGER_SWIPE:
        Gesture(
            name=TWO_FINGER_SWIPE,
            variations=(GV.TB, GV.BT),
            prompt='Use TWO fingers to quickly swipe {0}.',
            subprompt={
                GV.TB: ('from top to bottom',),
                GV.BT: ('from bottom to top',),
            },
            validators=(
                CountPacketsValidator(count_packets_criteria, slot=0),
                CountPacketsValidator(count_packets_criteria, slot=1),
                CountTrackingIDNormalFingerValidator('== 2'),
                NoReversedMotionValidator(no_reversed_motion_criteria, slots=0),
                NoReversedMotionValidator(no_reversed_motion_criteria, slots=1),
                ReportRateValidator(report_rate_criteria),
            ),
        ),

        PINCH_TO_ZOOM:
        Gesture(
            name=PINCH_TO_ZOOM,
            variations=(GV.ZOOM_IN, GV.ZOOM_OUT),
            prompt='Using two fingers, preform a "{0}" pinch by bringing'
                   'your fingers {1}.',
            subprompt={
                GV.ZOOM_IN: ('zoom in', 'farther apart'),
                GV.ZOOM_OUT: ('zoom out', 'closer together'),
            },
            validators=(
                CountTrackingIDNormalFingerValidator('== 2'),
                PinchValidator(pinch_criteria),
                ReportRateValidator(report_rate_criteria),
            ),
        ),

        ONE_FINGER_TAP:
        Gesture(
            name=ONE_FINGER_TAP,
            variations=(GV.TL, GV.TR, GV.BL, GV.BR, GV.TS, GV.BS, GV.LS, GV.RS,
                        GV.CENTER),
            prompt='Use one finger to tap on the {0} of the touch surface.',
            subprompt={
                GV.TL: ('top left corner',),
                GV.TR: ('top right corner',),
                GV.BL: ('bottom left corner',),
                GV.BR: ('bottom right corner',),
                GV.TS: ('top edge',),
                GV.BS: ('bottom side',),
                GV.LS: ('left hand side',),
                GV.RS: ('right hand side',),
                GV.CENTER: ('center',),
            },
            validators=(
                CountTrackingIDNormalFingerValidator('== 1'),
                StationaryTapValidator(stationary_tap_criteria, slot=0),
            ),
        ),

        TWO_FINGER_TAP:
        Gesture(
            name=TWO_FINGER_TAP,
            variations=(GV.HORIZONTAL, GV.VERTICAL, GV.DIAGONAL),
            prompt='Use two fingers aligned {0} to tap the center of the '
                   'touch surface.',
            subprompt={
                GV.HORIZONTAL: ('horizontally',),
                GV.VERTICAL: ('vertically',),
                GV.DIAGONAL: ('diagonally',),
            },
            validators=(
                CountTrackingIDNormalFingerValidator('== 2'),
                StationaryTapValidator(stationary_tap_criteria, slot=0),
                StationaryTapValidator(stationary_tap_criteria, slot=1),
            ),
        ),

        ONE_FINGER_PHYSICAL_CLICK:
        Gesture(
            name=ONE_FINGER_PHYSICAL_CLICK,
            variations=(GV.CENTER, GV.BL, GV.BS, GV.BR),
            prompt='Use one finger to physically click the {0} of the '
                   'touch surface.',
            subprompt={
                GV.CENTER: ('center',),
                GV.BL: ('bottom left corner',),
                GV.BS: ('bottom side',),
                GV.BR: ('bottom right corner',),
            },
            validators=(
                CountTrackingIDNormalFingerValidator('== 1'),
                PhysicalClickValidator('== 1', fingers=1),
                StationaryTapValidator(stationary_tap_criteria, slot=0),
            ),
        ),

        TWO_FINGER_PHYSICAL_CLICK:
        Gesture(
            name=TWO_FINGER_PHYSICAL_CLICK,
            variations=None,
            prompt='Use two fingers physically click the center of the '
                   'touch surface.',
            subprompt=None,
            validators=(
                CountTrackingIDNormalFingerValidator('== 2'),
                PhysicalClickValidator('== 1', fingers=2),
                StationaryTapValidator(stationary_tap_criteria, slot=0),
                StationaryTapValidator(stationary_tap_criteria, slot=1),
            ),
        ),

        THREE_FINGER_PHYSICAL_CLICK:
        Gesture(
            name=THREE_FINGER_PHYSICAL_CLICK,
            variations=None,
            prompt='Use three fingers to physically click '
                   'the center of the touch surface.',
            subprompt=None,
            validators=(
                CountTrackingIDNormalFingerValidator('== 3'),
                PhysicalClickValidator('== 1', fingers=3),
            ),
        ),

        FOUR_FINGER_PHYSICAL_CLICK:
        Gesture(
            name=FOUR_FINGER_PHYSICAL_CLICK,
            variations=None,
            prompt='Use four fingers to physically click '
                   'the center of the touch surface.',
            subprompt=None,
            validators=(
                CountTrackingIDNormalFingerValidator('== 4'),
                PhysicalClickValidator('== 1', fingers=4),
            ),
        ),

        FIVE_FINGER_PHYSICAL_CLICK:
        Gesture(
            name=FIVE_FINGER_PHYSICAL_CLICK,
            variations=None,
            prompt='Use five fingers to physically click '
                   'the center of the touch surface.',
            subprompt=None,
            validators=(
                CountTrackingIDNormalFingerValidator('== 5'),
                PhysicalClickValidator('== 1', fingers=5),
            ),
        ),

        STATIONARY_FINGER_NOT_AFFECTED_BY_2ND_FINGER_TAPS:
        Gesture(
            name=STATIONARY_FINGER_NOT_AFFECTED_BY_2ND_FINGER_TAPS,
            variations=(GV.AROUND,),
            prompt='Place your one stationary finger in the middle of the '
                   'touch surface, and use a second finger to tap '
                   'all around it many times (50)',
            subprompt=None,
            validators=(
                CountTrackingIDNormalFingerValidator('>= 25'),
                StationaryFingerValidator(stationary_finger_criteria, slot=0),
            ),
        ),

        FAT_FINGER_MOVE_WITH_RESTING_FINGER:
        Gesture(
            name=FAT_FINGER_MOVE_WITH_RESTING_FINGER,
            variations=(GV.LR, GV.RL, GV.TB, GV.BT),
            prompt='With a stationary finger on the {0} of the touch surface, '
                   'draw a straight line with a FAT finger {1} {2} it.',
            subprompt={
                GV.LR: ('center', 'from left to right', 'below'),
                GV.RL: ('bottom edge', 'from right to left', 'above'),
                GV.TB: ('center', 'from top to bottom', 'on the right to'),
                GV.BT: ('center', 'from bottom to top', 'on the left to'),
            },
            validators=(
                CountTrackingIDFatFingerValidator('== 2'),
                LinearityFatFingerValidator(relaxed_linearity_criteria,
                                            finger=1, segments=VAL.MIDDLE),
                NoGapValidator(no_gap_criteria, slot=1),
                NoReversedMotionValidator(no_reversed_motion_criteria, slots=1),
                ReportRateValidator(report_rate_criteria, finger=1),
                StationaryFingerValidator(stationary_finger_criteria, slot=0),
            ),
        ),

        DRAG_EDGE_THUMB:
        Gesture(
            name=DRAG_EDGE_THUMB,
            variations=(GV.LR, GV.RL, GV.TB, GV.BT),
            prompt='Drag the edge of your thumb {0} in a straight line '
                   'across the touch surface',
            subprompt={
                GV.LR: ('horizontally from left to right',),
                GV.RL: ('horizontally from right to left',),
                GV.TB: ('vertically from top to bottom',),
                GV.BT: ('vertically from bottom to top',),
            },
            validators=(
                CountTrackingIDFatFingerValidator('== 1'),
                LinearityFatFingerValidator(relaxed_linearity_criteria,
                                            finger=0, segments=VAL.MIDDLE),
                NoGapValidator(no_gap_criteria, slot=0),
                NoReversedMotionValidator(no_reversed_motion_criteria, slots=0),
                ReportRateValidator(report_rate_criteria),
            ),
        ),

        TWO_CLOSE_FINGERS_TRACKING:
        Gesture(
            name=TWO_CLOSE_FINGERS_TRACKING,
            variations=(GV.LR, GV.TB, GV.TLBR),
            prompt='With two fingers close together (lightly touching each '
                   'other) in a two finger scrolling gesture, draw a {0} '
                   'line {1}.',
            subprompt={
                GV.LR: ('horizontal', 'from left to right',),
                GV.TB: ('vertical', 'from top to bottom',),
                GV.TLBR: ('diagonal', 'from the top left to the bottom right',),
            },
            validators=(
                CountTrackingIDFatFingerValidator('== 2'),
                LinearityFatFingerValidator(relaxed_linearity_criteria,
                                            finger=0, segments=VAL.MIDDLE),
                LinearityFatFingerValidator(relaxed_linearity_criteria,
                                            finger=1, segments=VAL.MIDDLE),
                NoGapValidator(no_gap_criteria, slot=0),
                NoReversedMotionValidator(no_reversed_motion_criteria, slots=0),
                ReportRateValidator(report_rate_criteria),
            ),
        ),

        RESTING_FINGER_PLUS_2ND_FINGER_MOVE:
        Gesture(
            name=RESTING_FINGER_PLUS_2ND_FINGER_MOVE,
            variations=((GV.TLBR, GV.BRTL),
                        (GV.SLOW,),
            ),
            prompt='With a stationary finger in the bottom left corner, take '
                   '{1} to draw a straight line {0} with a second finger.',
            subprompt={
                GV.TLBR: ('from the top left to the bottom right',),
                GV.BRTL: ('from the bottom right to the top left',),
                GV.SLOW: ('3 seconds',),
            },
            validators=(
                CountTrackingIDNormalFingerValidator('== 2'),
                LinearityFatFingerValidator(relaxed_linearity_criteria,
                                            finger=1, segments=VAL.MIDDLE),
                NoGapValidator(no_gap_criteria, slot=1),
                NoReversedMotionValidator(no_reversed_motion_criteria, slots=1),
                ReportRateValidator(report_rate_criteria, finger=1),
                StationaryFingerValidator(stationary_finger_criteria, slot=0),
            ),
        ),

        TWO_FAT_FINGERS_TRACKING:
        Gesture(
            name=TWO_FAT_FINGERS_TRACKING,
            variations=(GV.LR, GV.RL),
            prompt='Use two FAT fingers separated by about 1cm to draw '
                   'a straight line {0}.',
            subprompt={
                GV.LR: ('from left to right',),
                GV.RL: ('from right to left',),
            },
            validators=(
                CountTrackingIDFatFingerValidator('== 2'),
                LinearityFatFingerValidator(relaxed_linearity_criteria,
                                            finger=0, segments=VAL.MIDDLE),
                LinearityFatFingerValidator(relaxed_linearity_criteria,
                                            finger=1, segments=VAL.MIDDLE),
                NoGapValidator(no_gap_criteria, slot=0),
                NoGapValidator(no_gap_criteria, slot=1),
                NoReversedMotionValidator(no_reversed_motion_criteria, slots=0),
                NoReversedMotionValidator(no_reversed_motion_criteria, slots=1),
                ReportRateValidator(report_rate_criteria),
            ),
        ),

        FIRST_FINGER_TRACKING_AND_SECOND_FINGER_TAPS:
        Gesture(
            name=FIRST_FINGER_TRACKING_AND_SECOND_FINGER_TAPS,
            variations=(GV.TLBR, GV.BRTL),
            prompt='While drawing a straight line {0} slowly (~3 seconds), '
                   'tap the bottom left corner with a second finger '
                   'gently 3 times.',
            subprompt={
                GV.TLBR: ('from top left to bottom right',),
                GV.BRTL: ('from bottom right to top left',),
            },
            validators=(
                CountTrackingIDNormalFingerValidator('== 4'),
                LinearityFatFingerValidator(relaxed_linearity_criteria,
                                            finger=0, segments=VAL.MIDDLE),
                NoGapValidator(no_gap_criteria, slot=0),
                NoReversedMotionValidator(no_reversed_motion_criteria, slots=0),
                ReportRateValidator(report_rate_criteria),
            ),
        ),

        DRUMROLL:
        Gesture(
            name=DRUMROLL,
            variations=(GV.FAST, ),
            prompt='Use the index and middle finger of one hand to make a '
                   '"drum roll" {0} by alternately tapping each finger '
                   'for 5 seconds.',
            subprompt={
                GV.FAST: ('as fast as possible',),
            },
            validators=(
                CountTrackingIDNormalFingerValidator('>= 5'),
                DrumrollValidator(drumroll_criteria),
            ),
            timeout = 2000,
        ),

        RAPID_TAPS:
        Gesture(
            name=RAPID_TAPS,
            variations=(GV.TL, GV.BR, GV.CENTER),
            prompt='Tap the {0} of the touch surface 20 times quickly',
            subprompt={
                GV.TL: ('top left corner',),
                GV.TS: ('top edge',),
                GV.TR: ('top right corner',),
                GV.LS: ('left edge',),
                GV.CENTER: ('center',),
                GV.RS: ('right edge',),
                GV.BL: ('bottom left corner',),
                GV.BS: ('bottom edge',),
                GV.BR: ('bottom right corner',),
            },
            validators=(
                CountTrackingIDNormalFingerValidator('== 20'),
            ),
            timeout = 2000,
        ),

        ONE_FINGER_TRACKING_FROM_CENTER:
        Gesture(
            name=ONE_FINGER_TRACKING_FROM_CENTER,
            variations=((GV.CR, GV.CT, GV.CUL, GV.CLL),
                        (GV.SLOW, GV.NORMAL),
            ),
            prompt='Place a stationary finger on the center of the touch '
                   'surface for about 1 second, and then take {2} to draw a '
                   '{0} line {1}.',
            subprompt={
                GV.CR: ('horizontal', 'to the right',),
                GV.CT: ('vertical', 'to the top',),
                GV.CUL: ('diagonal', 'to the upper left',),
                GV.CLL: ('diagonal', 'to the lower left',),
                GV.SLOW: ('2 seconds',),
                GV.NORMAL: ('1 second',),
            },
            validators=(
                HysteresisValidator(hysteresis_criteria, finger=0),
            ),
        ),

        DRAG_LATENCY:
        Gesture(
            name=DRAG_LATENCY,
            variations=None,
            prompt='Run one finger back and forth across the pad making sure '
                   'to break the laser completely on each pass.  Make at least '
                   'twenty passes.',
            subprompt=None,
            validators=(
                CountTrackingIDNormalFingerValidator('== 1'),
                DragLatencyValidator(drag_latency_criteria),
            ),
        ),

        PRESSURE_CALIBRATION:
        Gesture(
            name=PRESSURE_CALIBRATION,
            variations=(GV.SIZE0, GV.SIZE1, GV.SIZE2, GV.SIZE3, GV.SIZE4,
                        GV.SIZE5, GV.SIZE6, ),
            prompt='Draw circles continuously for 5 seconds '
                   'using the metal finger of size {0}.',
            subprompt={
                GV.SIZE0: ('0 (the smallest size)',),
                GV.SIZE1: ('1',),
                GV.SIZE2: ('2',),
                GV.SIZE3: ('3',),
                GV.SIZE4: ('4',),
                GV.SIZE5: ('5',),
                GV.SIZE6: ('6 (the largest size)',),
            },
            validators=(
                CountTrackingIDNormalFingerValidator('== 1'),
            ),
        ),
    }
    return gesture_dict


class FileName:
    """A dummy class to hold the attributes in a test file name."""
    pass
filename = FileName()
filename.sep = '-'
filename.ext = 'dat'


class Gesture:
    """A class defines the structure of Gesture."""
    # define the default timeout (in milli-seconds) when performing a gesture.
    # A gesture is considered done when finger is lifted for this time interval.
    TIMEOUT = int(1000/80*10)

    def __init__(self, name=None, variations=None, prompt=None, subprompt=None,
                 validators=None, timeout=TIMEOUT):
        self.name = name
        self.variations = variations
        self.prompt = prompt
        self.subprompt = subprompt
        self.validators = validators
        self.timeout = timeout