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 "drivers/TableCRC.h" 00020 #include "hal/crc_api.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 #elif defined (__ICCARM__) 00036 #pragma diag_suppress=Pe062 // Shift count is negative 00037 #endif 00038 00039 namespace mbed { 00040 /** \addtogroup drivers */ 00041 /** @{*/ 00042 00043 /** CRC object provides CRC generation through hardware/software 00044 * 00045 * ROM polynomial tables for supported polynomials (:: crc_polynomial_t) will be used for 00046 * software CRC computation, if ROM tables are not available then CRC is computed runtime 00047 * bit by bit for all data input. 00048 * 00049 * @tparam polynomial CRC polynomial value in hex 00050 * @tparam width CRC polynomial width 00051 * 00052 * Example: Compute CRC data 00053 * @code 00054 * 00055 * #include "mbed.h" 00056 * 00057 * int main() { 00058 * MbedCRC<POLY_32BIT_ANSI, 32> ct; 00059 * 00060 * char test[] = "123456789"; 00061 * uint32_t crc = 0; 00062 * 00063 * printf("\nPolynomial = 0x%lx Width = %d \n", ct.get_polynomial(), ct.get_width()); 00064 * 00065 * ct.compute((void *)test, strlen((const char*)test), &crc); 00066 * 00067 * printf("The CRC of data \"123456789\" is : 0x%lx\n", crc); 00068 * return 0; 00069 * } 00070 * @endcode 00071 * Example: Compute CRC with data available in parts 00072 * @code 00073 * 00074 * #include "mbed.h" 00075 * int main() { 00076 * MbedCRC<POLY_32BIT_ANSI, 32> ct; 00077 * 00078 * char test[] = "123456789"; 00079 * uint32_t crc = 0; 00080 * 00081 * printf("\nPolynomial = 0x%lx Width = %d \n", ct.get_polynomial(), ct.get_width()); 00082 * 00083 * ct.compute_partial_start(&crc); 00084 * ct.compute_partial((void *)&test, 4, &crc); 00085 * ct.compute_partial((void *)&test[4], 5, &crc); 00086 * ct.compute_partial_stop(&crc); 00087 * 00088 * printf("The CRC of data \"123456789\" is : 0x%lx\n", crc); 00089 * return 0; 00090 * } 00091 * @endcode 00092 * @ingroup drivers 00093 */ 00094 00095 template <uint32_t polynomial = POLY_32BIT_ANSI, uint8_t width = 32> 00096 class MbedCRC { 00097 public: 00098 enum CrcMode { HARDWARE = 0, TABLE, BITWISE }; 00099 00100 public: 00101 typedef uint64_t crc_data_size_t; 00102 00103 /** Lifetime of CRC object 00104 * 00105 * @param initial_xor Inital value/seed to Xor 00106 * @param final_xor Final Xor value 00107 * @param reflect_data 00108 * @param reflect_remainder 00109 * @note Default constructor without any arguments is valid only for supported CRC polynomials. :: crc_polynomial_t 00110 * MbedCRC <POLY_7BIT_SD, 7> ct; --- Valid POLY_7BIT_SD 00111 * MbedCRC <0x1021, 16> ct; --- Valid POLY_16BIT_CCITT 00112 * MbedCRC <POLY_16BIT_CCITT, 32> ct; --- Invalid, compilation error 00113 * MbedCRC <POLY_16BIT_CCITT, 32> ct (i,f,rd,rr) Consturctor can be used for not supported polynomials 00114 * MbedCRC<POLY_16BIT_CCITT, 16> sd(0, 0, false, false); Constructor can also be used for supported 00115 * polynomials with different intial/final/reflect values 00116 * 00117 */ 00118 MbedCRC(uint32_t initial_xor, uint32_t final_xor, bool reflect_data, bool reflect_remainder) : 00119 _initial_value(initial_xor), _final_xor(final_xor), _reflect_data(reflect_data), 00120 _reflect_remainder(reflect_remainder), _crc_table(NULL) 00121 { 00122 mbed_crc_ctor(); 00123 } 00124 MbedCRC(); 00125 virtual ~MbedCRC() 00126 { 00127 // Do nothing 00128 } 00129 00130 /** Compute CRC for the data input 00131 * 00132 * @param buffer Data bytes 00133 * @param size Size of data 00134 * @param crc CRC is the output value 00135 * @return 0 on success, negative error code on failure 00136 */ 00137 int32_t compute(void *buffer, crc_data_size_t size, uint32_t *crc) 00138 { 00139 MBED_ASSERT(crc != NULL); 00140 int32_t status; 00141 if (0 != (status = compute_partial_start(crc))) { 00142 *crc = 0; 00143 return status; 00144 } 00145 if (0 != (status = compute_partial(buffer, size, crc))) { 00146 *crc = 0; 00147 return status; 00148 } 00149 if (0 != (status = compute_partial_stop(crc))) { 00150 *crc = 0; 00151 return status; 00152 } 00153 return 0; 00154 } 00155 00156 /** Compute partial CRC for the data input. 00157 * 00158 * CRC data if not available fully, CRC can be computed in parts with available data. 00159 * Previous CRC output should be passed as argument to the current compute_partial call. 00160 * @pre: Call \ref compute_partial_start to start the partial CRC calculation. 00161 * @post: Call \ref compute_partial_stop to get the final CRC value. 00162 * 00163 * @param buffer Data bytes 00164 * @param size Size of data 00165 * @param crc CRC value is intermediate CRC value filled by API. 00166 * @return 0 on success or a negative error code on failure 00167 * @note: CRC as output in compute_partial is not final CRC value, call @ref compute_partial_stop 00168 * to get final correct CRC value. 00169 */ 00170 int32_t compute_partial(void *buffer, crc_data_size_t size, uint32_t *crc) 00171 { 00172 switch (_mode) { 00173 case HARDWARE: 00174 #ifdef DEVICE_CRC 00175 hal_crc_compute_partial((uint8_t *)buffer, size); 00176 #endif // DEVICE_CRC 00177 *crc = 0; 00178 return 0; 00179 case TABLE: 00180 return table_compute_partial(buffer, size, crc); 00181 case BITWISE: 00182 return bitwise_compute_partial(buffer, size, crc); 00183 } 00184 00185 return -1; 00186 } 00187 00188 /** Compute partial start, indicate start of partial computation 00189 * 00190 * This API should be called before performing any partial computation 00191 * with compute_partial API. 00192 * 00193 * @param crc Initial CRC value set by the API 00194 * @return 0 on success or a negative in case of failure 00195 * @note: CRC is an out parameter and must be reused with compute_partial 00196 * and compute_partial_stop without any modifications in application. 00197 */ 00198 int32_t compute_partial_start(uint32_t *crc) 00199 { 00200 MBED_ASSERT(crc != NULL); 00201 00202 #ifdef DEVICE_CRC 00203 if (_mode == HARDWARE) { 00204 crc_mbed_config_t config; 00205 config.polynomial = polynomial; 00206 config.width = width; 00207 config.initial_xor = _initial_value; 00208 config.final_xor = _final_xor; 00209 config.reflect_in = _reflect_data; 00210 config.reflect_out = _reflect_remainder; 00211 00212 hal_crc_compute_partial_start(&config); 00213 } 00214 #endif // DEVICE_CRC 00215 00216 *crc = _initial_value; 00217 return 0; 00218 } 00219 00220 /** Get the final CRC value of partial computation. 00221 * 00222 * CRC value available in partial computation is not correct CRC, as some 00223 * algorithms require remainder to be reflected and final value to be XORed 00224 * This API is used to perform final computation to get correct CRC value. 00225 * 00226 * @param crc CRC result 00227 */ 00228 int32_t compute_partial_stop(uint32_t *crc) 00229 { 00230 MBED_ASSERT(crc != NULL); 00231 00232 if (_mode == HARDWARE) { 00233 #ifdef DEVICE_CRC 00234 *crc = hal_crc_get_result(); 00235 return 0; 00236 #else 00237 return -1; 00238 #endif 00239 } 00240 00241 uint32_t p_crc = *crc; 00242 if ((width < 8) && (NULL == _crc_table)) { 00243 p_crc = (uint32_t)(p_crc << (8 - width)); 00244 } 00245 *crc = (reflect_remainder(p_crc) ^ _final_xor) & get_crc_mask(); 00246 return 0; 00247 } 00248 00249 /** Get the current CRC polynomial 00250 * 00251 * @return Polynomial value 00252 */ 00253 uint32_t get_polynomial(void) const 00254 { 00255 return polynomial; 00256 } 00257 00258 /** Get the current CRC width 00259 * 00260 * @return CRC width 00261 */ 00262 uint8_t get_width(void) const 00263 { 00264 return width; 00265 } 00266 00267 private: 00268 uint32_t _initial_value; 00269 uint32_t _final_xor; 00270 bool _reflect_data; 00271 bool _reflect_remainder; 00272 uint32_t *_crc_table; 00273 CrcMode _mode; 00274 00275 /** Get the current CRC data size 00276 * 00277 * @return CRC data size in bytes 00278 */ 00279 uint8_t get_data_size(void) const 00280 { 00281 return (width <= 8 ? 1 : (width <= 16 ? 2 : 4)); 00282 } 00283 00284 /** Get the top bit of current CRC 00285 * 00286 * @return Top bit is set high for respective data width of current CRC 00287 * Top bit for CRC width less then 8 bits will be set as 8th bit. 00288 */ 00289 uint32_t get_top_bit(void) const 00290 { 00291 return (width < 8 ? (1u << 7) : (uint32_t)(1ul << (width - 1))); 00292 } 00293 00294 /** Get the CRC data mask 00295 * 00296 * @return CRC data mask is generated based on current CRC width 00297 */ 00298 uint32_t get_crc_mask(void) const 00299 { 00300 return (width < 8 ? ((1u << 8) - 1) : (uint32_t)((uint64_t)(1ull << width) - 1)); 00301 } 00302 00303 /** Final value of CRC is reflected 00304 * 00305 * @param data final crc value, which should be reflected 00306 * @return Reflected CRC value 00307 */ 00308 uint32_t reflect_remainder(uint32_t data) const 00309 { 00310 if (_reflect_remainder) { 00311 uint32_t reflection = 0x0; 00312 uint8_t const nBits = (width < 8 ? 8 : width); 00313 00314 for (uint8_t bit = 0; bit < nBits; ++bit) { 00315 if (data & 0x01) { 00316 reflection |= (1 << ((nBits - 1) - bit)); 00317 } 00318 data = (data >> 1); 00319 } 00320 return (reflection); 00321 } else { 00322 return data; 00323 } 00324 } 00325 00326 /** Data bytes are reflected 00327 * 00328 * @param data value to be reflected 00329 * @return Reflected data value 00330 */ 00331 uint32_t reflect_bytes(uint32_t data) const 00332 { 00333 if (_reflect_data) { 00334 uint32_t reflection = 0x0; 00335 00336 for (uint8_t bit = 0; bit < 8; ++bit) { 00337 if (data & 0x01) { 00338 reflection |= (1 << (7 - bit)); 00339 } 00340 data = (data >> 1); 00341 } 00342 return (reflection); 00343 } else { 00344 return data; 00345 } 00346 } 00347 00348 /** Bitwise CRC computation 00349 * 00350 * @param buffer data buffer 00351 * @param size size of the data 00352 * @param crc CRC value is filled in, but the value is not the final 00353 * @return 0 on success or a negative error code on failure 00354 */ 00355 int32_t bitwise_compute_partial(const void *buffer, crc_data_size_t size, uint32_t *crc) const 00356 { 00357 MBED_ASSERT(crc != NULL); 00358 MBED_ASSERT(buffer != NULL); 00359 00360 const uint8_t *data = static_cast<const uint8_t *>(buffer); 00361 uint32_t p_crc = *crc; 00362 00363 if (width < 8) { 00364 uint8_t data_byte; 00365 for (crc_data_size_t byte = 0; byte < size; byte++) { 00366 data_byte = reflect_bytes(data[byte]); 00367 for (uint8_t bit = 8; bit > 0; --bit) { 00368 p_crc <<= 1; 00369 if ((data_byte ^ p_crc) & get_top_bit()) { 00370 p_crc ^= polynomial; 00371 } 00372 data_byte <<= 1; 00373 } 00374 } 00375 } else { 00376 for (crc_data_size_t byte = 0; byte < size; byte++) { 00377 p_crc ^= (reflect_bytes(data[byte]) << (width - 8)); 00378 00379 // Perform modulo-2 division, a bit at a time 00380 for (uint8_t bit = 8; bit > 0; --bit) { 00381 if (p_crc & get_top_bit()) { 00382 p_crc = (p_crc << 1) ^ polynomial; 00383 } else { 00384 p_crc = (p_crc << 1); 00385 } 00386 } 00387 } 00388 } 00389 *crc = p_crc & get_crc_mask(); 00390 return 0; 00391 } 00392 00393 /** CRC computation using ROM tables 00394 * 00395 * @param buffer data buffer 00396 * @param size size of the data 00397 * @param crc CRC value is filled in, but the value is not the final 00398 * @return 0 on success or a negative error code on failure 00399 */ 00400 int32_t table_compute_partial(const void *buffer, crc_data_size_t size, uint32_t *crc) const 00401 { 00402 MBED_ASSERT(crc != NULL); 00403 MBED_ASSERT(buffer != NULL); 00404 00405 const uint8_t *data = static_cast<const uint8_t *>(buffer); 00406 uint32_t p_crc = *crc; 00407 uint8_t data_byte = 0; 00408 00409 if (width <= 8) { 00410 uint8_t *crc_table = (uint8_t *)_crc_table; 00411 for (crc_data_size_t byte = 0; byte < size; byte++) { 00412 data_byte = reflect_bytes(data[byte]) ^ p_crc; 00413 p_crc = crc_table[data_byte]; 00414 } 00415 } else if (width <= 16) { 00416 uint16_t *crc_table = (uint16_t *)_crc_table; 00417 for (crc_data_size_t byte = 0; byte < size; byte++) { 00418 data_byte = reflect_bytes(data[byte]) ^ (p_crc >> (width - 8)); 00419 p_crc = crc_table[data_byte] ^ (p_crc << 8); 00420 } 00421 } else { 00422 uint32_t *crc_table = (uint32_t *)_crc_table; 00423 for (crc_data_size_t byte = 0; byte < size; byte++) { 00424 data_byte = reflect_bytes(data[byte]) ^ (p_crc >> (width - 8)); 00425 p_crc = crc_table[data_byte] ^ (p_crc << 8); 00426 } 00427 } 00428 *crc = p_crc & get_crc_mask(); 00429 return 0; 00430 } 00431 00432 /** Constructor init called from all specialized cases of constructor 00433 * Note: All construtor common code should be in this function. 00434 */ 00435 void mbed_crc_ctor(void) 00436 { 00437 MBED_STATIC_ASSERT(width <= 32, "Max 32-bit CRC supported"); 00438 00439 _mode = (_crc_table != NULL) ? TABLE : BITWISE; 00440 00441 #ifdef DEVICE_CRC 00442 crc_mbed_config_t config; 00443 config.polynomial = polynomial; 00444 config.width = width; 00445 config.initial_xor = _initial_value; 00446 config.final_xor = _final_xor; 00447 config.reflect_in = _reflect_data; 00448 config.reflect_out = _reflect_remainder; 00449 00450 if (hal_crc_is_supported(&config)) { 00451 _mode = HARDWARE; 00452 } 00453 #endif 00454 } 00455 }; 00456 00457 #if defined ( __CC_ARM ) 00458 #elif defined ( __GNUC__ ) 00459 #pragma GCC diagnostic pop 00460 #elif defined (__ICCARM__) 00461 #endif 00462 00463 /** @}*/ 00464 } // namespace mbed 00465 00466 #endif
Generated on Tue Jul 12 2022 13:53:15 by
1.7.2