Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
MbedCRC.h
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2018 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 #ifndef MBED_CRC_API_H 00017 #define MBED_CRC_API_H 00018 00019 #include <stdint.h> 00020 #include "drivers/TableCRC.h" 00021 #include "platform/mbed_assert.h" 00022 00023 /* This is invalid warning from the compiler for below section of code 00024 if ((width < 8) && (NULL == _crc_table)) { 00025 p_crc = (uint32_t)(p_crc << (8 - width)); 00026 } 00027 Compiler warns of the shift operation with width as it is width=(std::uint8_t), 00028 but we check for ( width < 8) before performing shift, so it should not be an issue. 00029 */ 00030 #if defined ( __CC_ARM ) 00031 #pragma diag_suppress 62 // Shift count is negative 00032 #elif defined ( __GNUC__ ) 00033 #pragma GCC diagnostic push 00034 #pragma GCC diagnostic ignored "-Wshift-count-negative" 00035 #endif 00036 00037 namespace mbed { 00038 /** \addtogroup drivers */ 00039 /** @{*/ 00040 00041 /** CRC Polynomial value 00042 * 00043 * Different polynomial values supported 00044 */ 00045 typedef enum crc_polynomial { 00046 POLY_OTHER = 0, 00047 POLY_8BIT_CCITT = 0x07, // x8+x2+x+1 00048 POLY_7BIT_SD = 0x9, // x7+x3+1; 00049 POLY_16BIT_CCITT = 0x1021, // x16+x12+x5+1 00050 POLY_16BIT_IBM = 0x8005, // x16+x15+x2+1 00051 POLY_32BIT_ANSI = 0x04C11DB7, // x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1 00052 } crc_polynomial_t; 00053 00054 /** CRC object provides CRC generation through hardware/software 00055 * 00056 * ROM polynomial tables for supported polynomials (:: crc_polynomial_t) will be used for 00057 * software CRC computation, if ROM tables are not available then CRC is computed runtime 00058 * bit by bit for all data input. 00059 * 00060 * @tparam polynomial CRC polynomial value in hex 00061 * @tparam width CRC polynomial width 00062 * 00063 * Example: Compute CRC data 00064 * @code 00065 * 00066 * #include "mbed.h" 00067 * 00068 * int main() { 00069 * MbedCRC<POLY_32BIT_ANSI, 32> ct; 00070 * 00071 * char test[] = "123456789"; 00072 * uint32_t crc = 0; 00073 * 00074 * printf("\nPolynomial = 0x%lx Width = %d \n", ct.get_polynomial(), ct.get_width()); 00075 * 00076 * ct.compute((void *)test, strlen((const char*)test), &crc); 00077 * 00078 * printf("The CRC of data \"123456789\" is : 0x%lx\n", crc); 00079 * return 0; 00080 * } 00081 * @endcode 00082 * Example: Compute CRC with data available in parts 00083 * @code 00084 * 00085 * #include "mbed.h" 00086 * int main() { 00087 * MbedCRC<POLY_32BIT_ANSI, 32> ct; 00088 * 00089 * char test[] = "123456789"; 00090 * uint32_t crc = 0; 00091 * 00092 * printf("\nPolynomial = 0x%lx Width = %d \n", ct.get_polynomial(), ct.get_width()); 00093 * 00094 * ct.compute_partial_start(&crc); 00095 * ct.compute_partial((void *)&test, 4, &crc); 00096 * ct.compute_partial((void *)&test[4], 5, &crc); 00097 * ct.compute_partial_stop(&crc); 00098 * 00099 * printf("The CRC of data \"123456789\" is : 0x%lx\n", crc); 00100 * return 0; 00101 * } 00102 * @endcode 00103 * @ingroup drivers 00104 */ 00105 00106 template <uint32_t polynomial=POLY_32BIT_ANSI, uint8_t width=32> 00107 class MbedCRC 00108 { 00109 public: 00110 typedef uint64_t crc_data_size_t; 00111 00112 /** Lifetime of CRC object 00113 * 00114 * @param initial_xor Inital value/seed to Xor 00115 * @param final_xor Final Xor value 00116 * @param reflect_data 00117 * @param reflect_remainder 00118 * @note Default constructor without any arguments is valid only for supported CRC polynomials. :: crc_polynomial_t 00119 * MbedCRC <POLY_7BIT_SD, 7> ct; --- Valid POLY_7BIT_SD 00120 * MbedCRC <0x1021, 16> ct; --- Valid POLY_16BIT_CCITT 00121 * MbedCRC <POLY_16BIT_CCITT, 32> ct; --- Invalid, compilation error 00122 * MbedCRC <POLY_16BIT_CCITT, 32> ct (i,f,rd,rr) Consturctor can be used for not supported polynomials 00123 * MbedCRC<POLY_16BIT_CCITT, 16> sd(0, 0, false, false); Constructor can also be used for supported 00124 * polynomials with different intial/final/reflect values 00125 * 00126 */ 00127 MbedCRC(uint32_t initial_xor, uint32_t final_xor, bool reflect_data, bool reflect_remainder) : 00128 _initial_value(initial_xor), _final_xor(final_xor), _reflect_data(reflect_data), 00129 _reflect_remainder(reflect_remainder), _crc_table(NULL) 00130 { 00131 mbed_crc_ctor(); 00132 } 00133 MbedCRC(); 00134 virtual ~MbedCRC() 00135 { 00136 // Do nothing 00137 } 00138 00139 /** Compute CRC for the data input 00140 * 00141 * @param buffer Data bytes 00142 * @param size Size of data 00143 * @param crc CRC is the output value 00144 * @return 0 on success, negative error code on failure 00145 */ 00146 int32_t compute(void *buffer, crc_data_size_t size, uint32_t *crc) 00147 { 00148 MBED_ASSERT(crc != NULL); 00149 int32_t status; 00150 if (0 != (status = compute_partial_start(crc))) { 00151 *crc = 0; 00152 return status; 00153 } 00154 if (0 != (status = compute_partial(buffer, size, crc))) { 00155 *crc = 0; 00156 return status; 00157 } 00158 if (0 != (status = compute_partial_stop(crc))) { 00159 *crc = 0; 00160 return status; 00161 } 00162 return 0; 00163 } 00164 00165 /** Compute partial CRC for the data input. 00166 * 00167 * CRC data if not available fully, CRC can be computed in parts with available data. 00168 * Previous CRC output should be passed as argument to the current compute_partial call. 00169 * @pre: Call \ref compute_partial_start to start the partial CRC calculation. 00170 * @post: Call \ref compute_partial_stop to get the final CRC value. 00171 * 00172 * @param buffer Data bytes 00173 * @param size Size of data 00174 * @param crc CRC value is intermediate CRC value filled by API. 00175 * @return 0 on success or a negative error code on failure 00176 * @note: CRC as output in compute_partial is not final CRC value, call @ref compute_partial_stop 00177 * to get final correct CRC value. 00178 */ 00179 int32_t compute_partial(void *buffer, crc_data_size_t size, uint32_t *crc) 00180 { 00181 if (NULL == _crc_table) { 00182 // Compute bitwise CRC 00183 return bitwise_compute_partial(buffer, size, crc); 00184 } else { 00185 // Table CRC 00186 return table_compute_partial(buffer, size, crc); 00187 } 00188 } 00189 00190 /** Compute partial start, indicate start of partial computation 00191 * 00192 * This API should be called before performing any partial computation 00193 * with compute_partial API. 00194 * 00195 * @param crc Initial CRC value set by the API 00196 * @return 0 on success or a negative in case of failure 00197 * @note: CRC is an out parameter and must be reused with compute_partial 00198 * and compute_partial_stop without any modifications in application. 00199 */ 00200 int32_t compute_partial_start(uint32_t *crc) 00201 { 00202 MBED_ASSERT(crc != NULL); 00203 *crc = _initial_value; 00204 return 0; 00205 } 00206 00207 /** Get the final CRC value of partial computation. 00208 * 00209 * CRC value available in partial computation is not correct CRC, as some 00210 * algorithms require remainder to be reflected and final value to be XORed 00211 * This API is used to perform final computation to get correct CRC value. 00212 * 00213 * @param crc CRC result 00214 */ 00215 int32_t compute_partial_stop(uint32_t *crc) 00216 { 00217 MBED_ASSERT(crc != NULL); 00218 uint32_t p_crc = *crc; 00219 if ((width < 8) && (NULL == _crc_table)) { 00220 p_crc = (uint32_t)(p_crc << (8 - width)); 00221 } 00222 *crc = (reflect_remainder(p_crc) ^ _final_xor) & get_crc_mask(); 00223 return 0; 00224 } 00225 00226 /** Get the current CRC polynomial 00227 * 00228 * @return Polynomial value 00229 */ 00230 uint32_t get_polynomial(void) const 00231 { 00232 return polynomial; 00233 } 00234 00235 /** Get the current CRC width 00236 * 00237 * @return CRC width 00238 */ 00239 uint8_t get_width(void) const 00240 { 00241 return width; 00242 } 00243 00244 private: 00245 uint32_t _initial_value; 00246 uint32_t _final_xor; 00247 bool _reflect_data; 00248 bool _reflect_remainder; 00249 uint32_t *_crc_table; 00250 00251 /** Get the current CRC data size 00252 * 00253 * @return CRC data size in bytes 00254 */ 00255 uint8_t get_data_size(void) const 00256 { 00257 return (width <= 8 ? 1 : (width <= 16 ? 2 : 4)); 00258 } 00259 00260 /** Get the top bit of current CRC 00261 * 00262 * @return Top bit is set high for respective data width of current CRC 00263 * Top bit for CRC width less then 8 bits will be set as 8th bit. 00264 */ 00265 uint32_t get_top_bit(void) const 00266 { 00267 return (width < 8 ? (1u << 7) : (uint32_t)(1ul << (width - 1))); 00268 } 00269 00270 /** Get the CRC data mask 00271 * 00272 * @return CRC data mask is generated based on current CRC width 00273 */ 00274 uint32_t get_crc_mask(void) const 00275 { 00276 return (width < 8 ? ((1u << 8) - 1) : (uint32_t)((uint64_t)(1ull << width) - 1)); 00277 } 00278 00279 /** Final value of CRC is reflected 00280 * 00281 * @param data final crc value, which should be reflected 00282 * @return Reflected CRC value 00283 */ 00284 uint32_t reflect_remainder(uint32_t data) const 00285 { 00286 if (_reflect_remainder) { 00287 uint32_t reflection = 0x0; 00288 uint8_t const nBits = (width < 8 ? 8 : width); 00289 00290 for (uint8_t bit = 0; bit < nBits; ++bit) { 00291 if (data & 0x01) { 00292 reflection |= (1 << ((nBits - 1) - bit)); 00293 } 00294 data = (data >> 1); 00295 } 00296 return (reflection); 00297 } else { 00298 return data; 00299 } 00300 } 00301 00302 /** Data bytes are reflected 00303 * 00304 * @param data value to be reflected 00305 * @return Reflected data value 00306 */ 00307 uint32_t reflect_bytes(uint32_t data) const 00308 { 00309 if(_reflect_data) { 00310 uint32_t reflection = 0x0; 00311 00312 for (uint8_t bit = 0; bit < 8; ++bit) { 00313 if (data & 0x01) { 00314 reflection |= (1 << (7 - bit)); 00315 } 00316 data = (data >> 1); 00317 } 00318 return (reflection); 00319 } else { 00320 return data; 00321 } 00322 } 00323 00324 /** Bitwise CRC computation 00325 * 00326 * @param buffer data buffer 00327 * @param size size of the data 00328 * @param crc CRC value is filled in, but the value is not the final 00329 * @return 0 on success or a negative error code on failure 00330 */ 00331 int32_t bitwise_compute_partial(const void *buffer, crc_data_size_t size, uint32_t *crc) const 00332 { 00333 MBED_ASSERT(crc != NULL); 00334 MBED_ASSERT(buffer != NULL); 00335 00336 const uint8_t *data = static_cast<const uint8_t *>(buffer); 00337 uint32_t p_crc = *crc; 00338 00339 if (width < 8) { 00340 uint8_t data_byte; 00341 for (crc_data_size_t byte = 0; byte < size; byte++) { 00342 data_byte = reflect_bytes(data[byte]); 00343 for (uint8_t bit = 8; bit > 0; --bit) { 00344 p_crc <<= 1; 00345 if (( data_byte ^ p_crc) & get_top_bit()) { 00346 p_crc ^= polynomial; 00347 } 00348 data_byte <<= 1; 00349 } 00350 } 00351 } else { 00352 for (crc_data_size_t byte = 0; byte < size; byte++) { 00353 p_crc ^= (reflect_bytes(data[byte]) << (width - 8)); 00354 00355 // Perform modulo-2 division, a bit at a time 00356 for (uint8_t bit = 8; bit > 0; --bit) { 00357 if (p_crc & get_top_bit()) { 00358 p_crc = (p_crc << 1) ^ polynomial; 00359 } else { 00360 p_crc = (p_crc << 1); 00361 } 00362 } 00363 } 00364 } 00365 *crc = p_crc & get_crc_mask(); 00366 return 0; 00367 } 00368 00369 /** CRC computation using ROM tables 00370 * 00371 * @param buffer data buffer 00372 * @param size size of the data 00373 * @param crc CRC value is filled in, but the value is not the final 00374 * @return 0 on success or a negative error code on failure 00375 */ 00376 int32_t table_compute_partial(const void *buffer, crc_data_size_t size, uint32_t *crc) const 00377 { 00378 MBED_ASSERT(crc != NULL); 00379 MBED_ASSERT(buffer != NULL); 00380 00381 const uint8_t *data = static_cast<const uint8_t *>(buffer); 00382 uint32_t p_crc = *crc; 00383 uint8_t data_byte = 0; 00384 00385 if (width <= 8) { 00386 uint8_t *crc_table = (uint8_t *)_crc_table; 00387 for (crc_data_size_t byte = 0; byte < size; byte++) { 00388 data_byte = reflect_bytes(data[byte]) ^ p_crc; 00389 p_crc = crc_table[data_byte]; 00390 } 00391 } else if (width <= 16) { 00392 uint16_t *crc_table = (uint16_t *)_crc_table; 00393 for (crc_data_size_t byte = 0; byte < size; byte++) { 00394 data_byte = reflect_bytes(data[byte]) ^ (p_crc >> (width - 8)); 00395 p_crc = crc_table[data_byte] ^ (p_crc << 8); 00396 } 00397 } else { 00398 uint32_t *crc_table = (uint32_t *)_crc_table; 00399 for (crc_data_size_t byte = 0; byte < size; byte++) { 00400 data_byte = reflect_bytes(data[byte]) ^ (p_crc >> (width - 8)); 00401 p_crc = crc_table[data_byte] ^ (p_crc << 8); 00402 } 00403 } 00404 *crc = p_crc & get_crc_mask(); 00405 return 0; 00406 } 00407 00408 /** Constructor init called from all specialized cases of constructor 00409 * Note: All construtor common code should be in this function. 00410 */ 00411 void mbed_crc_ctor(void) const 00412 { 00413 MBED_STATIC_ASSERT(width <= 32, "Max 32-bit CRC supported"); 00414 } 00415 }; 00416 00417 #if defined ( __CC_ARM ) 00418 #elif defined ( __GNUC__ ) 00419 #pragma GCC diagnostic pop 00420 #endif 00421 00422 /** @}*/ 00423 } // namespace mbed 00424 00425 #endif
Generated on Tue Jul 12 2022 14:24:27 by
