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