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 info(self, message): 43 self.__logger.info(message) 44 45 def warning(self, message): 46 self.__logger.warning(message) 47 48class 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 204class 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 232if __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