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