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.
Fork of mbed-dev by
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 #endif 00036 00037 namespace mbed { 00038 /** \addtogroup drivers */ 00039 /** @{*/ 00040 00041 /** CRC object provides CRC generation through hardware/software 00042 * 00043 * ROM polynomial tables for supported polynomials (:: crc_polynomial_t) will be used for 00044 * software CRC computation, if ROM tables are not available then CRC is computed runtime 00045 * bit by bit for all data input. 00046 * 00047 * @tparam polynomial CRC polynomial value in hex 00048 * @tparam width CRC polynomial width 00049 * 00050 * Example: Compute CRC data 00051 * @code 00052 * 00053 * #include "mbed.h" 00054 * 00055 * int main() { 00056 * MbedCRC<POLY_32BIT_ANSI, 32> ct; 00057 * 00058 * char test[] = "123456789"; 00059 * uint32_t crc = 0; 00060 * 00061 * printf("\nPolynomial = 0x%lx Width = %d \n", ct.get_polynomial(), ct.get_width()); 00062 * 00063 * ct.compute((void *)test, strlen((const char*)test), &crc); 00064 * 00065 * printf("The CRC of data \"123456789\" is : 0x%lx\n", crc); 00066 * return 0; 00067 * } 00068 * @endcode 00069 * Example: Compute CRC with data available in parts 00070 * @code 00071 * 00072 * #include "mbed.h" 00073 * int main() { 00074 * MbedCRC<POLY_32BIT_ANSI, 32> ct; 00075 * 00076 * char test[] = "123456789"; 00077 * uint32_t crc = 0; 00078 * 00079 * printf("\nPolynomial = 0x%lx Width = %d \n", ct.get_polynomial(), ct.get_width()); 00080 * 00081 * ct.compute_partial_start(&crc); 00082 * ct.compute_partial((void *)&test, 4, &crc); 00083 * ct.compute_partial((void *)&test[4], 5, &crc); 00084 * ct.compute_partial_stop(&crc); 00085 * 00086 * printf("The CRC of data \"123456789\" is : 0x%lx\n", crc); 00087 * return 0; 00088 * } 00089 * @endcode 00090 * @ingroup drivers 00091 */ 00092 00093 template <uint32_t polynomial=POLY_32BIT_ANSI, uint8_t width=32> 00094 class MbedCRC 00095 { 00096 public: 00097 enum CrcMode { HARDWARE = 0, TABLE, BITWISE }; 00098 00099 public: 00100 typedef uint64_t crc_data_size_t; 00101 00102 /** Lifetime of CRC object 00103 * 00104 * @param initial_xor Inital value/seed to Xor 00105 * @param final_xor Final Xor value 00106 * @param reflect_data 00107 * @param reflect_remainder 00108 * @note Default constructor without any arguments is valid only for supported CRC polynomials. :: crc_polynomial_t 00109 * MbedCRC <POLY_7BIT_SD, 7> ct; --- Valid POLY_7BIT_SD 00110 * MbedCRC <0x1021, 16> ct; --- Valid POLY_16BIT_CCITT 00111 * MbedCRC <POLY_16BIT_CCITT, 32> ct; --- Invalid, compilation error 00112 * MbedCRC <POLY_16BIT_CCITT, 32> ct (i,f,rd,rr) Consturctor can be used for not supported polynomials 00113 * MbedCRC<POLY_16BIT_CCITT, 16> sd(0, 0, false, false); Constructor can also be used for supported 00114 * polynomials with different intial/final/reflect values 00115 * 00116 */ 00117 MbedCRC(uint32_t initial_xor, uint32_t final_xor, bool reflect_data, bool reflect_remainder) : 00118 _initial_value(initial_xor), _final_xor(final_xor), _reflect_data(reflect_data), 00119 _reflect_remainder(reflect_remainder), _crc_table(NULL) 00120 { 00121 mbed_crc_ctor(); 00122 } 00123 MbedCRC(); 00124 virtual ~MbedCRC() 00125 { 00126 // Do nothing 00127 } 00128 00129 /** Compute CRC for the data input 00130 * 00131 * @param buffer Data bytes 00132 * @param size Size of data 00133 * @param crc CRC is the output value 00134 * @return 0 on success, negative error code on failure 00135 */ 00136 int32_t compute(void *buffer, crc_data_size_t size, uint32_t *crc) 00137 { 00138 MBED_ASSERT(crc != NULL); 00139 int32_t status; 00140 if (0 != (status = compute_partial_start(crc))) { 00141 *crc = 0; 00142 return status; 00143 } 00144 if (0 != (status = compute_partial(buffer, size, crc))) { 00145 *crc = 0; 00146 return status; 00147 } 00148 if (0 != (status = compute_partial_stop(crc))) { 00149 *crc = 0; 00150 return status; 00151 } 00152 return 0; 00153 } 00154 00155 /** Compute partial CRC for the data input. 00156 * 00157 * CRC data if not available fully, CRC can be computed in parts with available data. 00158 * Previous CRC output should be passed as argument to the current compute_partial call. 00159 * @pre: Call \ref compute_partial_start to start the partial CRC calculation. 00160 * @post: Call \ref compute_partial_stop to get the final CRC value. 00161 * 00162 * @param buffer Data bytes 00163 * @param size Size of data 00164 * @param crc CRC value is intermediate CRC value filled by API. 00165 * @return 0 on success or a negative error code on failure 00166 * @note: CRC as output in compute_partial is not final CRC value, call @ref compute_partial_stop 00167 * to get final correct CRC value. 00168 */ 00169 int32_t compute_partial(void *buffer, crc_data_size_t size, uint32_t *crc) 00170 { 00171 switch (_mode) 00172 { 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 #endif 00461 00462 /** @}*/ 00463 } // namespace mbed 00464 00465 #endif
Generated on Tue Jul 12 2022 20:37:46 by
