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