blob: e6bbbceb6d26c4d8dc87fe7500e36bd751a28c52 [file] [log] [blame]
Vernon Mauerye7329c72018-10-08 12:05:16 -07001/**
2 * Copyright © 2018 Intel Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#pragma once
17
18#include <array>
19#include <ipmid/message/types.hpp>
20#include <memory>
21#include <phosphor-logging/log.hpp>
22#include <tuple>
23#include <utility>
24#include <vector>
25
26namespace ipmi
27{
28
29namespace message
30{
31
32namespace details
33{
34
35/**************************************
36 * ipmi return type helpers
37 **************************************/
38
39template <typename NumericType, size_t byteIndex = 0>
40void PackBytes(uint8_t* pointer, const NumericType& i)
41{
42 if constexpr (byteIndex < sizeof(NumericType))
43 {
44 *pointer = static_cast<uint8_t>(i >> (8 * byteIndex));
45 PackBytes<NumericType, byteIndex + 1>(pointer + 1, i);
46 }
47}
48
49template <typename NumericType, size_t byteIndex = 0>
50void PackBytesUnaligned(Payload& p, const NumericType& i)
51{
52 if constexpr (byteIndex < sizeof(NumericType))
53 {
54 p.appendBits(CHAR_BIT, static_cast<uint8_t>(i >> (8 * byteIndex)));
55 PackBytesUnaligned<NumericType, byteIndex + 1>(p, i);
56 }
57}
58
59/** @struct PackSingle
60 * @brief Utility to pack a single C++ element into a Payload
61 *
62 * User-defined types are expected to specialize this template in order to
63 * get their functionality.
64 *
65 * @tparam S - Type of element to pack.
66 */
67template <typename T>
68struct PackSingle
69{
70 /** @brief Do the operation to pack element.
71 *
72 * @param[in] p - Payload to pack into.
73 * @param[out] t - The reference to pack item into.
74 */
75 static int op(Payload& p, T& t)
76 {
77 // if not on a byte boundary, must pack values LSbit/LSByte first
78 if (p.bitCount)
79 {
80 PackBytesUnaligned<T>(p, t);
81 }
82 else
83 {
84 // copy in bits to vector....
85 p.raw.resize(p.raw.size() + sizeof(T));
86 uint8_t* out = p.raw.data() + p.raw.size() - sizeof(T);
87 PackBytes<T>(out, t);
88 }
89 return 0;
90 }
91};
92
93/** @brief Specialization of PackSingle for std::string
94 * represented as a UCSD-Pascal style string
95 */
96template <>
97struct PackSingle<std::string>
98{
99 static int op(Payload& p, std::string& t)
100 {
101 // check length first
102 uint8_t len;
103 if (t.length() > std::numeric_limits<decltype(len)>::max())
104 {
105 using namespace phosphor::logging;
106 log<level::ERR>("long string truncated on IPMI message pack");
107 return 1;
108 }
109 len = static_cast<uint8_t>(t.length());
110 PackSingle<uint8_t>::op(p, len);
111 p.append(t.c_str(), t.c_str() + t.length());
112 return 0;
113 }
114};
115
116/** @brief Specialization of PackSingle for fixed_uint_t types
117 */
118template <unsigned N>
119struct PackSingle<fixed_uint_t<N>>
120{
121 static int op(Payload& p, fixed_uint_t<N>& t)
122 {
123 size_t count = N;
124 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
125 uint64_t bits = t;
126 while (count > 0)
127 {
128 size_t appendCount = std::min(count, static_cast<size_t>(CHAR_BIT));
129 p.appendBits(appendCount, static_cast<uint8_t>(bits));
130 bits >>= CHAR_BIT;
131 count -= appendCount;
132 }
133 return 0;
134 }
135};
136
137/** @brief Specialization of PackSingle for bool. */
138template <>
139struct PackSingle<bool>
140{
141 static int op(Payload& p, bool& b)
142 {
143 p.appendBits(1, b);
144 return 0;
145 }
146};
147
148/** @brief Specialization of PackSingle for std::bitset<N> */
149template <size_t N>
150struct PackSingle<std::bitset<N>>
151{
152 static int op(Payload& p, std::bitset<N>& t)
153 {
154 size_t count = N;
155 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
156 unsigned long long bits = t.to_ullong();
157 while (count > 0)
158 {
159 size_t appendCount = std::min(count, size_t(CHAR_BIT));
160 p.appendBits(appendCount, static_cast<uint8_t>(bits));
161 bits >>= CHAR_BIT;
162 count -= appendCount;
163 }
164 return 0;
165 }
166};
167
168/** @brief Specialization of PackSingle for std::array<T, N> */
169template <typename T, size_t N>
170struct PackSingle<std::array<T, N>>
171{
172 static int op(Payload& p, std::array<T, N>& t)
173 {
174 int ret = 0;
175 for (auto& v : t)
176 {
177 int ret = PackSingle<T>::op(p, v);
178 if (ret)
179 {
180 break;
181 }
182 }
183 return ret;
184 }
185};
186
187/** @brief Specialization of PackSingle for std::vector<T> */
188template <typename T>
189struct PackSingle<std::vector<T>>
190{
191 static int op(Payload& p, std::vector<T>& t)
192 {
193 int ret = 0;
194 for (auto& v : t)
195 {
196 int ret = PackSingle<T>::op(p, v);
197 if (ret)
198 {
199 break;
200 }
201 }
202 return ret;
203 }
204};
205
206/** @brief Specialization of PackSingle for std::vector<uint8_t> */
207template <>
208struct PackSingle<std::vector<uint8_t>>
209{
210 static int op(Payload& p, std::vector<uint8_t>& t)
211 {
212 p.raw.reserve(p.raw.size() + t.size());
213 p.raw.insert(p.raw.end(), t.begin(), t.end());
214 return 0;
215 }
216};
217
218} // namespace details
219
220} // namespace message
221
222} // namespace ipmi