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 info(self, message):
     43         self.__logger.info(message)
     44 
     45     def warning(self, message):
     46         self.__logger.warning(message)
     47 
     48 class FixedPointTester():
     49     """ Made for testing a particular Qn.m number
     50 
     51     As a convention, we use:
     52         * n is the fractional part
     53         * m is the integral part
     54 
     55     This class computes several specific numbers for a given Qn.m number.
     56 
     57     For each of those numbers, we run 4 checks:
     58         * Bound check
     59         * Sanity check
     60         * Consistency check
     61         * Bijectivity check
     62     Which are documented below.
     63     """
     64     def __init__(self, pfwClient, size, integral, fractional):
     65         self._pfwClient = pfwClient
     66         self._paramPath = '/Test/test/%d/q%d.%d' % (size, integral, fractional)
     67 
     68         # quantum is the step we have between two numbers
     69         # encoded in Qn.m format
     70         self._quantum = 2 ** -fractional
     71 
     72         # The maximum value we can encode for a given Qn.m.
     73         # Since we also need to encode the 0, we have one quantum missing on
     74         # the positive maximum
     75         self._upperAllowedBound = (2 ** integral) - self._quantum
     76 
     77         # The minimum value that we can encode for a given Qn.m.
     78         # This one does not need a quantum substraction since we already did
     79         # that on the maximum
     80         self._lowerAllowedBound = -(2 ** integral)
     81 
     82         self._shouldWork = [
     83                 Decimal(0),
     84                 Decimal(self._lowerAllowedBound),
     85                 Decimal(self._upperAllowedBound)
     86                 ]
     87 
     88         # bigValue is to be sure a value far out of range is refused
     89         bigValue = (2 * self._quantum)
     90         # little is to be sure a value just out of range is refused
     91         littleValue = 10 ** -(int(fractional * log10(2)))
     92         self._shouldBreak = [
     93                 Decimal(self._lowerAllowedBound) - Decimal(bigValue),
     94                 Decimal(self._upperAllowedBound) + Decimal(bigValue),
     95                 Decimal(self._lowerAllowedBound) - Decimal(littleValue),
     96                 Decimal(self._upperAllowedBound) + Decimal(littleValue)
     97                 ]
     98 
     99         self._chainingTests = [
    100                 ('Bound', self.checkBounds),
    101                 ('Sanity', self.checkSanity),
    102                 ('Consistency', self.checkConsistency),
    103                 ('Bijectivity', self.checkBijectivity)]
    104 
    105 
    106     def run(self):
    107         """ Runs the test suite for a given Qn.m number
    108         """
    109 
    110         runSuccess = True
    111 
    112         for value in self._shouldWork:
    113             value = value.normalize()
    114             print('Testing %s for %s' % (value, self._paramPath))
    115 
    116             for testName, testFunc in self._chainingTests:
    117                 value, success = testFunc(value)
    118                 if not success:
    119                     runSuccess = False
    120                     print("%s ERROR for %s" % (testName, self._paramPath))
    121                     break
    122 
    123         for value in self._shouldBreak:
    124             value = value.normalize()
    125             print('Testing invalid value %s for %s' % (value, self._paramPath))
    126             value, success = self.checkBounds(value)
    127             if success:
    128                 runSuccess = False
    129                 print("ERROR: This test should have failed but it has not")
    130 
    131         return runSuccess
    132 
    133     def checkBounds(self, valueToSet):
    134         """ Checks if we are able to set valueToSet via the parameter-framework
    135 
    136         valueToSet -- the value we are trying to set
    137 
    138         returns: the value we are trying to set
    139         returns: True if we are able to set, False otherwise
    140         """
    141         (success, errorMsg) = self._pfwClient.set(self._paramPath, str(valueToSet))
    142 
    143         return valueToSet, success
    144 
    145 
    146     def checkSanity(self, valuePreviouslySet):
    147         """ Checks if the value we get is still approximately the same
    148         as we attempted to set. The value can have a slight round error which
    149         is tolerated.
    150 
    151         valuePreviouslySet -- the value we had previously set
    152 
    153         returns: the value the parameter-framework returns us after the get
    154         returns: True if we are able to set, False otherwise
    155         """
    156         firstGet = self._pfwClient.get(self._paramPath)
    157 
    158         try:
    159             returnValue = Decimal(firstGet)
    160         except ValueError:
    161             print("ERROR: Can't convert %s to a decimal" % firstGet)
    162             return firstGet, False
    163 
    164         upperAllowedValue = Decimal(valuePreviouslySet) + (Decimal(self._quantum) / Decimal(2))
    165         lowerAllowedValue = Decimal(valuePreviouslySet) - (Decimal(self._quantum) / Decimal(2))
    166 
    167         if not (lowerAllowedValue <= returnValue <= upperAllowedValue):
    168             print('%s <= %s <= %s is not true' %
    169                     (lowerAllowedValue, returnValue, upperAllowedValue))
    170             return firstGet, False
    171 
    172         return firstGet, True
    173 
    174     def checkConsistency(self, valuePreviouslyGotten):
    175         """ Checks if we are able to set the value that the parameter framework
    176         just returned to us.
    177 
    178         valuePreviouslyGotten -- the value we are trying to set
    179 
    180         valueToSet -- the value we are trying to set
    181         returns: True if we are able to set, False otherwise
    182         """
    183         (success, errorMsg) = pfw.set(self._paramPath, valuePreviouslyGotten)
    184 
    185         return valuePreviouslyGotten, success
    186 
    187     def checkBijectivity(self, valuePreviouslySet):
    188         """ Checks that the second get value is strictly equivalent to the
    189         consistency set. This ensures that the parameter-framework behaves as
    190         expected.
    191 
    192         valuePreviouslySet -- the value we had previously set
    193 
    194         returns: value the parameter-framework returns us after the second get
    195         returns: True if we are able to set, False otherwise
    196         """
    197         secondGet = pfw.get(self._paramPath)
    198 
    199         if secondGet != valuePreviouslySet:
    200             return secondGet, False
    201 
    202         return secondGet, True
    203 
    204 class PfwClient():
    205 
    206     def __init__(self, configPath):
    207         self._instance = PyPfw.ParameterFramework(configPath)
    208 
    209         self._logger = PfwLogger()
    210         self._instance.setLogger(self._logger)
    211         # Disable the remote interface because we don't need it and it might
    212         # get in the way (e.g. the port is already in use)
    213         self._instance.setForceNoRemoteInterface(True)
    214 
    215         self._instance.start()
    216         self._instance.setTuningMode(True)
    217 
    218     def set(self, parameter, value):
    219         print('set %s <--- %s' % (parameter, value))
    220         (success, _, errorMsg) = self._instance.accessParameterValue(parameter, str(value), True)
    221         return success, errorMsg
    222 
    223     def get(self, parameter):
    224         (success, value, errorMsg) = self._instance.accessParameterValue(parameter, "", False)
    225         if not success:
    226             raise Exception("A getParameter failed, which is unexpected. The"
    227                             "parameter-framework answered:\n%s" % errorMsg)
    228 
    229         print('get %s ---> %s' % (parameter, value))
    230         return value
    231 
    232 if __name__ == '__main__':
    233     # It is necessary to add a ./ in front of the path, otherwise the parameter-framework
    234     # does not recognize the string as a path.
    235     pfw = PfwClient('./ParameterFrameworkConfiguration.xml')
    236 
    237     success = True
    238 
    239     for size in [8, 16, 32]:
    240         for integral in range(0,  size):
    241             for fractional in range (0,  size - integral):
    242                 tester = FixedPointTester(pfw, size, integral, fractional)
    243                 success = tester.run() and success
    244 
    245     exit(0 if success else 1)
    246