Home | History | Annotate | Download | only in test-fixed-point-parameter
      1 #!/usr/bin/python2.7
      2 #
      3 # Copyright (c) 2014-2015, Intel Corporation
      4 # All rights reserved.
      5 #
      6 # Redistribution and use in source and binary forms, with or without modification,
      7 # are permitted provided that the following conditions are met:
      8 #
      9 # 1. Redistributions of source code must retain the above copyright notice, this
     10 # list of conditions and the following disclaimer.
     11 #
     12 # 2. Redistributions in binary form must reproduce the above copyright notice,
     13 # this list of conditions and the following disclaimer in the documentation and/or
     14 # other materials provided with the distribution.
     15 #
     16 # 3. Neither the name of the copyright holder nor the names of its contributors
     17 # may be used to endorse or promote products derived from this software without
     18 # specific prior written permission.
     19 #
     20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     21 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     22 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     23 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
     24 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     25 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     26 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     27 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     29 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 import PyPfw
     32 
     33 import logging
     34 from decimal import Decimal
     35 from math import log10
     36 
     37 class PfwLogger(PyPfw.ILogger):
     38     def __init__(self):
     39         super(PfwLogger, self).__init__()
     40         self.__logger = logging.root.getChild("parameter-framework")
     41 
     42     def log(self, is_warning, message):
     43         log_func = self.__logger.warning if is_warning else self.__logger.info
     44         log_func(message)
     45 
     46 class FixedPointTester():
     47     """ Made for testing a particular Qn.m number
     48 
     49     As a convention, we use:
     50         * n is the fractional part
     51         * m is the integral part
     52 
     53     This class computes several specific numbers for a given Qn.m number.
     54 
     55     For each of those numbers, we run 4 checks:
     56         * Bound check
     57         * Sanity check
     58         * Consistency check
     59         * Bijectivity check
     60     Which are documented below.
     61     """
     62     def __init__(self, pfwClient, size, integral, fractional):
     63         self._pfwClient = pfwClient
     64         self._paramPath = '/Test/test/%d/q%d.%d' % (size, integral, fractional)
     65 
     66         # quantum is the step we have between two numbers
     67         # encoded in Qn.m format
     68         self._quantum = 2 ** -fractional
     69 
     70         # The maximum value we can encode for a given Qn.m.
     71         # Since we also need to encode the 0, we have one quantum missing on
     72         # the positive maximum
     73         self._upperAllowedBound = (2 ** integral) - self._quantum
     74 
     75         # The minimum value that we can encode for a given Qn.m.
     76         # This one does not need a quantum substraction since we already did
     77         # that on the maximum
     78         self._lowerAllowedBound = -(2 ** integral)
     79 
     80         self._shouldWork = [
     81                 Decimal(0),
     82                 Decimal(self._lowerAllowedBound),
     83                 Decimal(self._upperAllowedBound)
     84                 ]
     85 
     86         # bigValue is to be sure a value far out of range is refused
     87         bigValue = (2 * self._quantum)
     88         # little is to be sure a value just out of range is refused
     89         littleValue = 10 ** -(int(fractional * log10(2)))
     90         self._shouldBreak = [
     91                 Decimal(self._lowerAllowedBound) - Decimal(bigValue),
     92                 Decimal(self._upperAllowedBound) + Decimal(bigValue),
     93                 Decimal(self._lowerAllowedBound) - Decimal(littleValue),
     94                 Decimal(self._upperAllowedBound) + Decimal(littleValue)
     95                 ]
     96 
     97         self._chainingTests = [
     98                 ('Bound', self.checkBounds),
     99                 ('Sanity', self.checkSanity),
    100                 ('Consistency', self.checkConsistency),
    101                 ('Bijectivity', self.checkBijectivity)]
    102 
    103 
    104     def run(self):
    105         """ Runs the test suite for a given Qn.m number
    106         """
    107 
    108         runSuccess = True
    109 
    110         for value in self._shouldWork:
    111             value = value.normalize()
    112             print('Testing %s for %s' % (value, self._paramPath))
    113 
    114             for testName, testFunc in self._chainingTests:
    115                 value, success = testFunc(value)
    116                 if not success:
    117                     runSuccess = False
    118                     print("%s ERROR for %s" % (testName, self._paramPath))
    119                     break
    120 
    121         for value in self._shouldBreak:
    122             value = value.normalize()
    123             print('Testing invalid value %s for %s' % (value, self._paramPath))
    124             value, success = self.checkBounds(value)
    125             if success:
    126                 runSuccess = False
    127                 print("ERROR: This test should have failed but it has not")
    128 
    129         return runSuccess
    130 
    131     def checkBounds(self, valueToSet):
    132         """ Checks if we are able to set valueToSet via the parameter-framework
    133 
    134         valueToSet -- the value we are trying to set
    135 
    136         returns: the value we are trying to set
    137         returns: True if we are able to set, False otherwise
    138         """
    139         (success, errorMsg) = self._pfwClient.set(self._paramPath, str(valueToSet))
    140 
    141         return valueToSet, success
    142 
    143 
    144     def checkSanity(self, valuePreviouslySet):
    145         """ Checks if the value we get is still approximately the same
    146         as we attempted to set. The value can have a slight round error which
    147         is tolerated.
    148 
    149         valuePreviouslySet -- the value we had previously set
    150 
    151         returns: the value the parameter-framework returns us after the get
    152         returns: True if we are able to set, False otherwise
    153         """
    154         firstGet = self._pfwClient.get(self._paramPath)
    155 
    156         try:
    157             returnValue = Decimal(firstGet)
    158         except ValueError:
    159             print("ERROR: Can't convert %s to a decimal" % firstGet)
    160             return firstGet, False
    161 
    162         upperAllowedValue = Decimal(valuePreviouslySet) + (Decimal(self._quantum) / Decimal(2))
    163         lowerAllowedValue = Decimal(valuePreviouslySet) - (Decimal(self._quantum) / Decimal(2))
    164 
    165         if not (lowerAllowedValue <= returnValue <= upperAllowedValue):
    166             print('%s <= %s <= %s is not true' %
    167                     (lowerAllowedValue, returnValue, upperAllowedValue))
    168             return firstGet, False
    169 
    170         return firstGet, True
    171 
    172     def checkConsistency(self, valuePreviouslyGotten):
    173         """ Checks if we are able to set the value that the parameter framework
    174         just returned to us.
    175 
    176         valuePreviouslyGotten -- the value we are trying to set
    177 
    178         valueToSet -- the value we are trying to set
    179         returns: True if we are able to set, False otherwise
    180         """
    181         (success, errorMsg) = pfw.set(self._paramPath, valuePreviouslyGotten)
    182 
    183         return valuePreviouslyGotten, success
    184 
    185     def checkBijectivity(self, valuePreviouslySet):
    186         """ Checks that the second get value is strictly equivalent to the
    187         consistency set. This ensures that the parameter-framework behaves as
    188         expected.
    189 
    190         valuePreviouslySet -- the value we had previously set
    191 
    192         returns: value the parameter-framework returns us after the second get
    193         returns: True if we are able to set, False otherwise
    194         """
    195         secondGet = pfw.get(self._paramPath)
    196 
    197         if secondGet != valuePreviouslySet:
    198             return secondGet, False
    199 
    200         return secondGet, True
    201 
    202 class PfwClient():
    203 
    204     def __init__(self, configPath):
    205         self._instance = PyPfw.ParameterFramework(configPath)
    206 
    207         self._logger = PfwLogger()
    208         self._instance.setLogger(self._logger)
    209         # Disable the remote interface because we don't need it and it might
    210         # get in the way (e.g. the port is already in use)
    211         self._instance.setForceNoRemoteInterface(True)
    212 
    213         self._instance.start()
    214         self._instance.setTuningMode(True)
    215 
    216     def set(self, parameter, value):
    217         print('set %s <--- %s' % (parameter, value))
    218         (success, _, errorMsg) = self._instance.accessParameterValue(parameter, str(value), True)
    219         return success, errorMsg
    220 
    221     def get(self, parameter):
    222         (success, value, errorMsg) = self._instance.accessParameterValue(parameter, "", False)
    223         if not success:
    224             raise Exception("A getParameter failed, which is unexpected. The"
    225                             "parameter-framework answered:\n%s" % errorMsg)
    226 
    227         print('get %s ---> %s' % (parameter, value))
    228         return value
    229 
    230 if __name__ == '__main__':
    231     # It is necessary to add a ./ in front of the path, otherwise the parameter-framework
    232     # does not recognize the string as a path.
    233     pfw = PfwClient('./ParameterFrameworkConfiguration.xml')
    234 
    235     success = True
    236 
    237     for size in [8, 16, 32]:
    238         for integral in range(0,  size):
    239             for fractional in range (0,  size - integral):
    240                 tester = FixedPointTester(pfw, size, integral, fractional)
    241                 success = tester.run() and success
    242 
    243     exit(0 if success else 1)
    244