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 31import PyPfw 32 33import logging 34from decimal import Decimal 35from math import log10 36 37class 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 46class 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 202class 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 230if __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