1/*
2 * Copyright (c) 2011-2015, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation and/or
13 * other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 * may be used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30#include "BitParameterType.h"
31#include "BitParameter.h"
32#include <stdlib.h>
33#include <sstream>
34#include "ParameterAccessContext.h"
35#include "BitParameterBlockType.h"
36#include "Utility.h"
37
38#define base CTypeElement
39
40using std::string;
41
42CBitParameterType::CBitParameterType(const string& strName) : base(strName), _uiBitPos(0), _uiBitSize(0), _uiMax(uint64_t(-1))
43{
44}
45
46// CElement
47string CBitParameterType::getKind() const
48{
49    return "BitParameter";
50}
51
52// Element properties
53void CBitParameterType::showProperties(string& strResult) const
54{
55    base::showProperties(strResult);
56
57    // Bit Pos
58    strResult += "Bit pos: ";
59    strResult += CUtility::toString(_uiBitPos);
60    strResult += "\n";
61
62    // Bit size
63    strResult += "Bit size: ";
64    strResult += CUtility::toString(_uiBitSize);
65    strResult += "\n";
66
67    // Max
68    strResult += "Max: ";
69    strResult += CUtility::toString(_uiMax);
70    strResult += "\n";
71}
72
73// From IXmlSink
74bool CBitParameterType::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext)
75{
76    // Pos
77    _uiBitPos = xmlElement.getAttributeInteger("Pos");
78
79    // Size
80    _uiBitSize = xmlElement.getAttributeInteger("Size");
81
82    // Validate bit pos and size still fit into parent type
83    const CBitParameterBlockType* pBitParameterBlockType = static_cast<const CBitParameterBlockType*>(getParent());
84
85    uint32_t uiParentBlockBitSize = pBitParameterBlockType->getSize() * 8;
86
87    if (_uiBitPos + _uiBitSize > uiParentBlockBitSize) {
88
89        // Range exceeded
90	std::ostringstream strStream;
91
92        strStream << "Pos and Size attributes inconsistent with maximum container element size (" << uiParentBlockBitSize << " bits) for " + getKind();
93
94        serializingContext.setError(strStream.str());
95
96        return false;
97    }
98
99    // Max
100    if (xmlElement.hasAttribute("Max")) {
101
102        _uiMax = xmlElement.getAttributeInteger("Max");
103
104        if (_uiMax > getMaxEncodableValue()) {
105
106            // Max value exceeded
107	    std::ostringstream strStream;
108
109            strStream << "Max attribute inconsistent with maximum encodable size (" << getMaxEncodableValue() << ") for " + getKind();
110
111            serializingContext.setError(strStream.str());
112
113            return false;
114        }
115    } else {
116
117        _uiMax = getMaxEncodableValue();
118    }
119
120    // Base
121    return base::fromXml(xmlElement, serializingContext);
122}
123
124// Conversion
125bool CBitParameterType::toBlackboard(const string& strValue, uint64_t& uiValue, CParameterAccessContext& parameterAccessContext) const
126{
127    // Hexa
128    bool bValueProvidedAsHexa = !strValue.compare(0, 2, "0x");
129
130    // Get value
131    uint64_t uiConvertedValue = strtoull(strValue.c_str(), NULL, 0);
132
133    if (uiConvertedValue > _uiMax) {
134
135        // Range exceeded
136	std::ostringstream strStream;
137
138        strStream << "Value " << strValue << " standing out of admitted range [";
139
140        if (bValueProvidedAsHexa) {
141
142            strStream << "0x0, " << "0x" << std::hex << std::uppercase;
143        } else {
144
145            strStream << "0, ";
146        }
147        strStream << _uiMax << "] for " + getKind();
148
149        parameterAccessContext.setError(strStream.str());
150
151        return false;
152    }
153
154    // Do bitwise RMW operation
155    uiValue = (uiValue & ~getMask()) | (uiConvertedValue << _uiBitPos);
156
157    return true;
158}
159
160void CBitParameterType::fromBlackboard(string& strValue, const uint64_t& uiValue, CParameterAccessContext& parameterAccessContext) const
161{
162    uint64_t uiConvertedValue = (uiValue & getMask()) >> _uiBitPos;
163
164    // Format
165    std::ostringstream strStream;
166
167    // Take care of format
168    if (parameterAccessContext.valueSpaceIsRaw() && parameterAccessContext.outputRawFormatIsHex()) {
169
170        strStream << "0x" << std::hex << std::uppercase;
171    }
172
173    strStream << uiConvertedValue;
174
175    strValue = strStream.str();
176}
177
178// Value access
179// Integer
180bool CBitParameterType::toBlackboard(uint64_t uiUserValue, uint64_t& uiValue, CParameterAccessContext& parameterAccessContext) const
181{
182    if (uiUserValue > _uiMax) {
183
184        parameterAccessContext.setError("Value out of range");
185
186        return false;
187    }
188
189    // Do bitwise RMW operation
190    uiValue = (uiValue & ~getMask()) | (uiUserValue << _uiBitPos);
191
192    return true;
193}
194
195void CBitParameterType::fromBlackboard(uint32_t& uiUserValue, uint64_t uiValue, CParameterAccessContext& parameterAccessContext) const
196{
197    (void)parameterAccessContext;
198
199    uiUserValue = (uiValue & getMask()) >> _uiBitPos;
200}
201
202// Access from area configuration
203uint64_t CBitParameterType::merge(uint64_t uiOriginData, uint64_t uiNewData) const
204{
205    return (uiOriginData & ~getMask()) | (uiNewData & getMask());
206}
207
208// Bit Size
209uint32_t CBitParameterType::getBitSize() const
210{
211    return _uiBitSize;
212}
213
214CInstanceConfigurableElement* CBitParameterType::doInstantiate() const
215{
216    return new CBitParameter(getName(), this);
217}
218
219// Max value
220uint64_t CBitParameterType::getMaxEncodableValue() const
221{
222    return (uint64_t)-1L >> (8 * sizeof(uint64_t) - _uiBitSize);
223}
224
225// Biwise mask
226uint64_t CBitParameterType::getMask() const
227{
228    return getMaxEncodableValue() << _uiBitPos;
229}
230
231// Check data has no bit set outside available range
232bool CBitParameterType::isEncodable(uint64_t uiData) const
233{
234    uint32_t uiShift = 8 * sizeof(uiData) - _uiBitSize;
235
236    if (uiShift) {
237
238        // Check high bits are clean
239        return !(uiData >> uiShift);
240    }
241
242    return true;
243}
244
245// From IXmlSource
246void CBitParameterType::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
247{
248    // Position
249    xmlElement.setAttributeString("Pos", CUtility::toString(_uiBitPos));
250
251    // Size
252    xmlElement.setAttributeString("Size", CUtility::toString(_uiBitSize));
253
254    // Maximum
255    xmlElement.setAttributeString("Max", CUtility::toString(_uiMax));
256
257    base::toXml(xmlElement, serializingContext);
258
259}
260