| #!/usr/bin/python2.7 |
| # |
| # Copyright (c) 2014-2015, Intel Corporation |
| # All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without modification, |
| # are permitted provided that the following conditions are met: |
| # |
| # 1. Redistributions of source code must retain the above copyright notice, this |
| # list of conditions and the following disclaimer. |
| # |
| # 2. Redistributions in binary form must reproduce the above copyright notice, |
| # this list of conditions and the following disclaimer in the documentation and/or |
| # other materials provided with the distribution. |
| # |
| # 3. Neither the name of the copyright holder nor the names of its contributors |
| # may be used to endorse or promote products derived from this software without |
| # specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
| # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| import PyPfw |
| |
| import logging |
| from decimal import Decimal |
| from math import log10 |
| |
| class PfwLogger(PyPfw.ILogger): |
| def __init__(self): |
| super(PfwLogger, self).__init__() |
| self.__logger = logging.root.getChild("parameter-framework") |
| |
| def log(self, is_warning, message): |
| log_func = self.__logger.warning if is_warning else self.__logger.info |
| log_func(message) |
| |
| class FixedPointTester(): |
| """ Made for testing a particular Qn.m number |
| |
| As a convention, we use: |
| * n is the fractional part |
| * m is the integral part |
| |
| This class computes several specific numbers for a given Qn.m number. |
| |
| For each of those numbers, we run 4 checks: |
| * Bound check |
| * Sanity check |
| * Consistency check |
| * Bijectivity check |
| Which are documented below. |
| """ |
| def __init__(self, pfwClient, size, integral, fractional): |
| self._pfwClient = pfwClient |
| self._paramPath = '/Test/test/%d/q%d.%d' % (size, integral, fractional) |
| |
| # quantum is the step we have between two numbers |
| # encoded in Qn.m format |
| self._quantum = 2 ** -fractional |
| |
| # The maximum value we can encode for a given Qn.m. |
| # Since we also need to encode the 0, we have one quantum missing on |
| # the positive maximum |
| self._upperAllowedBound = (2 ** integral) - self._quantum |
| |
| # The minimum value that we can encode for a given Qn.m. |
| # This one does not need a quantum substraction since we already did |
| # that on the maximum |
| self._lowerAllowedBound = -(2 ** integral) |
| |
| self._shouldWork = [ |
| Decimal(0), |
| Decimal(self._lowerAllowedBound), |
| Decimal(self._upperAllowedBound) |
| ] |
| |
| # bigValue is to be sure a value far out of range is refused |
| bigValue = (2 * self._quantum) |
| # little is to be sure a value just out of range is refused |
| littleValue = 10 ** -(int(fractional * log10(2))) |
| self._shouldBreak = [ |
| Decimal(self._lowerAllowedBound) - Decimal(bigValue), |
| Decimal(self._upperAllowedBound) + Decimal(bigValue), |
| Decimal(self._lowerAllowedBound) - Decimal(littleValue), |
| Decimal(self._upperAllowedBound) + Decimal(littleValue) |
| ] |
| |
| self._chainingTests = [ |
| ('Bound', self.checkBounds), |
| ('Sanity', self.checkSanity), |
| ('Consistency', self.checkConsistency), |
| ('Bijectivity', self.checkBijectivity)] |
| |
| |
| def run(self): |
| """ Runs the test suite for a given Qn.m number |
| """ |
| |
| runSuccess = True |
| |
| for value in self._shouldWork: |
| value = value.normalize() |
| print('Testing %s for %s' % (value, self._paramPath)) |
| |
| for testName, testFunc in self._chainingTests: |
| value, success = testFunc(value) |
| if not success: |
| runSuccess = False |
| print("%s ERROR for %s" % (testName, self._paramPath)) |
| break |
| |
| for value in self._shouldBreak: |
| value = value.normalize() |
| print('Testing invalid value %s for %s' % (value, self._paramPath)) |
| value, success = self.checkBounds(value) |
| if success: |
| runSuccess = False |
| print("ERROR: This test should have failed but it has not") |
| |
| return runSuccess |
| |
| def checkBounds(self, valueToSet): |
| """ Checks if we are able to set valueToSet via the parameter-framework |
| |
| valueToSet -- the value we are trying to set |
| |
| returns: the value we are trying to set |
| returns: True if we are able to set, False otherwise |
| """ |
| (success, errorMsg) = self._pfwClient.set(self._paramPath, str(valueToSet)) |
| |
| return valueToSet, success |
| |
| |
| def checkSanity(self, valuePreviouslySet): |
| """ Checks if the value we get is still approximately the same |
| as we attempted to set. The value can have a slight round error which |
| is tolerated. |
| |
| valuePreviouslySet -- the value we had previously set |
| |
| returns: the value the parameter-framework returns us after the get |
| returns: True if we are able to set, False otherwise |
| """ |
| firstGet = self._pfwClient.get(self._paramPath) |
| |
| try: |
| returnValue = Decimal(firstGet) |
| except ValueError: |
| print("ERROR: Can't convert %s to a decimal" % firstGet) |
| return firstGet, False |
| |
| upperAllowedValue = Decimal(valuePreviouslySet) + (Decimal(self._quantum) / Decimal(2)) |
| lowerAllowedValue = Decimal(valuePreviouslySet) - (Decimal(self._quantum) / Decimal(2)) |
| |
| if not (lowerAllowedValue <= returnValue <= upperAllowedValue): |
| print('%s <= %s <= %s is not true' % |
| (lowerAllowedValue, returnValue, upperAllowedValue)) |
| return firstGet, False |
| |
| return firstGet, True |
| |
| def checkConsistency(self, valuePreviouslyGotten): |
| """ Checks if we are able to set the value that the parameter framework |
| just returned to us. |
| |
| valuePreviouslyGotten -- the value we are trying to set |
| |
| valueToSet -- the value we are trying to set |
| returns: True if we are able to set, False otherwise |
| """ |
| (success, errorMsg) = pfw.set(self._paramPath, valuePreviouslyGotten) |
| |
| return valuePreviouslyGotten, success |
| |
| def checkBijectivity(self, valuePreviouslySet): |
| """ Checks that the second get value is strictly equivalent to the |
| consistency set. This ensures that the parameter-framework behaves as |
| expected. |
| |
| valuePreviouslySet -- the value we had previously set |
| |
| returns: value the parameter-framework returns us after the second get |
| returns: True if we are able to set, False otherwise |
| """ |
| secondGet = pfw.get(self._paramPath) |
| |
| if secondGet != valuePreviouslySet: |
| return secondGet, False |
| |
| return secondGet, True |
| |
| class PfwClient(): |
| |
| def __init__(self, configPath): |
| self._instance = PyPfw.ParameterFramework(configPath) |
| |
| self._logger = PfwLogger() |
| self._instance.setLogger(self._logger) |
| # Disable the remote interface because we don't need it and it might |
| # get in the way (e.g. the port is already in use) |
| self._instance.setForceNoRemoteInterface(True) |
| |
| self._instance.start() |
| self._instance.setTuningMode(True) |
| |
| def set(self, parameter, value): |
| print('set %s <--- %s' % (parameter, value)) |
| (success, _, errorMsg) = self._instance.accessParameterValue(parameter, str(value), True) |
| return success, errorMsg |
| |
| def get(self, parameter): |
| (success, value, errorMsg) = self._instance.accessParameterValue(parameter, "", False) |
| if not success: |
| raise Exception("A getParameter failed, which is unexpected. The" |
| "parameter-framework answered:\n%s" % errorMsg) |
| |
| print('get %s ---> %s' % (parameter, value)) |
| return value |
| |
| if __name__ == '__main__': |
| # It is necessary to add a ./ in front of the path, otherwise the parameter-framework |
| # does not recognize the string as a path. |
| pfw = PfwClient('./ParameterFrameworkConfiguration.xml') |
| |
| success = True |
| |
| for size in [8, 16, 32]: |
| for integral in range(0, size): |
| for fractional in range (0, size - integral): |
| tester = FixedPointTester(pfw, size, integral, fractional) |
| success = tester.run() and success |
| |
| exit(0 if success else 1) |