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 MbedCRC(); 00129 virtual ~MbedCRC() 00130 { 00131 // Do nothing 00132 } 00133 00134 /** Compute CRC for the data input 00135 * 00136 * @param buffer Data bytes 00137 * @param size Size of data 00138 * @param crc CRC is the output value 00139 * @return 0 on success, negative error code on failure 00140 */ 00141 int32_t compute(void *buffer, crc_data_size_t size, uint32_t *crc) 00142 { 00143 MBED_ASSERT(crc != NULL); 00144 int32_t status; 00145 if (0 != (status = compute_partial_start(crc))) { 00146 *crc = 0; 00147 return status; 00148 } 00149 if (0 != (status = compute_partial(buffer, size, crc))) { 00150 *crc = 0; 00151 return status; 00152 } 00153 if (0 != (status = compute_partial_stop(crc))) { 00154 *crc = 0; 00155 return status; 00156 } 00157 return 0; 00158 } 00159 00160 /** Compute partial CRC for the data input. 00161 * 00162 * CRC data if not available fully, CRC can be computed in parts with available data. 00163 * Previous CRC output should be passed as argument to the current compute_partial call. 00164 * @pre: Call \ref compute_partial_start to start the partial CRC calculation. 00165 * @post: Call \ref compute_partial_stop to get the final CRC value. 00166 * 00167 * @param buffer Data bytes 00168 * @param size Size of data 00169 * @param crc CRC value is intermediate CRC value filled by API. 00170 * @return 0 on success or a negative error code on failure 00171 * @note: CRC as output in compute_partial is not final CRC value, call @ref compute_partial_stop 00172 * to get final correct CRC value. 00173 */ 00174 int32_t compute_partial(void *buffer, crc_data_size_t size, uint32_t *crc) 00175 { 00176 if (NULL == _crc_table) { 00177 // Compute bitwise CRC 00178 return bitwise_compute_partial(buffer, size, crc); 00179 } else { 00180 // Table CRC 00181 return table_compute_partial(buffer, size, crc); 00182 } 00183 } 00184 00185 /** Compute partial start, indicate start of partial computation 00186 * 00187 * This API should be called before performing any partial computation 00188 * with compute_partial API. 00189 * 00190 * @param crc Initial CRC value set by the API 00191 * @return 0 on success or a negative in case of failure 00192 * @note: CRC is an out parameter and must be reused with compute_partial 00193 * and compute_partial_stop without any modifications in application. 00194 */ 00195 int32_t compute_partial_start(uint32_t *crc) 00196 { 00197 MBED_ASSERT(crc != NULL); 00198 *crc = _initial_value; 00199 return 0; 00200 } 00201 00202 /** Get the final CRC value of partial computation. 00203 * 00204 * CRC value available in partial computation is not correct CRC, as some 00205 * algorithms require remainder to be reflected and final value to be XORed 00206 * This API is used to perform final computation to get correct CRC value. 00207 * 00208 * @param crc CRC result 00209 */ 00210 int32_t compute_partial_stop(uint32_t *crc) 00211 { 00212 MBED_ASSERT(crc != NULL); 00213 uint32_t p_crc = *crc; 00214 if ((width < 8) && (NULL == _crc_table)) { 00215 p_crc = (uint32_t)(p_crc << (8 - width)); 00216 } 00217 *crc = (reflect_remainder(p_crc) ^ _final_xor) & get_crc_mask(); 00218 return 0; 00219 } 00220 00221 /** Get the current CRC polynomial 00222 * 00223 * @return Polynomial value 00224 */ 00225 uint32_t get_polynomial(void) const 00226 { 00227 return polynomial; 00228 } 00229 00230 /** Get the current CRC width 00231 * 00232 * @return CRC width 00233 */ 00234 uint8_t get_width(void) const 00235 { 00236 return width; 00237 } 00238 00239 private: 00240 uint32_t _initial_value; 00241 uint32_t _final_xor; 00242 bool _reflect_data; 00243 bool _reflect_remainder; 00244 uint32_t *_crc_table; 00245 00246 /** Get the current CRC data size 00247 * 00248 * @return CRC data size in bytes 00249 */ 00250 uint8_t get_data_size(void) const 00251 { 00252 return (width <= 8 ? 1 : (width <= 16 ? 2 : 4)); 00253 } 00254 00255 /** Get the top bit of current CRC 00256 * 00257 * @return Top bit is set high for respective data width of current CRC 00258 * Top bit for CRC width less then 8 bits will be set as 8th bit. 00259 */ 00260 uint32_t get_top_bit(void) const 00261 { 00262 return (width < 8 ? (1u << 7) : (uint32_t)(1ul << (width - 1))); 00263 } 00264 00265 /** Get the CRC data mask 00266 * 00267 * @return CRC data mask is generated based on current CRC width 00268 */ 00269 uint32_t get_crc_mask(void) const 00270 { 00271 return (width < 8 ? ((1u << 8) - 1) : (uint32_t)((uint64_t)(1ull << width) - 1)); 00272 } 00273 00274 /** Final value of CRC is reflected 00275 * 00276 * @param data final crc value, which should be reflected 00277 * @return Reflected CRC value 00278 */ 00279 uint32_t reflect_remainder(uint32_t data) const 00280 { 00281 if (_reflect_remainder) { 00282 uint32_t reflection = 0x0; 00283 uint8_t const nBits = (width < 8 ? 8 : width); 00284 00285 for (uint8_t bit = 0; bit < nBits; ++bit) { 00286 if (data & 0x01) { 00287 reflection |= (1 << ((nBits - 1) - bit)); 00288 } 00289 data = (data >> 1); 00290 } 00291 return (reflection); 00292 } else { 00293 return data; 00294 } 00295 } 00296 00297 /** Data bytes are reflected 00298 * 00299 * @param data value to be reflected 00300 * @return Reflected data value 00301 */ 00302 uint32_t reflect_bytes(uint32_t data) const 00303 { 00304 if(_reflect_data) { 00305 uint32_t reflection = 0x0; 00306 00307 for (uint8_t bit = 0; bit < 8; ++bit) { 00308 if (data & 0x01) { 00309 reflection |= (1 << (7 - bit)); 00310 } 00311 data = (data >> 1); 00312 } 00313 return (reflection); 00314 } else { 00315 return data; 00316 } 00317 } 00318 00319 /** Bitwise CRC computation 00320 * 00321 * @param buffer data buffer 00322 * @param size size of the data 00323 * @param crc CRC value is filled in, but the value is not the final 00324 * @return 0 on success or a negative error code on failure 00325 */ 00326 int32_t bitwise_compute_partial(const void *buffer, crc_data_size_t size, uint32_t *crc) const 00327 { 00328 MBED_ASSERT(crc != NULL); 00329 MBED_ASSERT(buffer != NULL); 00330 00331 const uint8_t *data = static_cast<const uint8_t *>(buffer); 00332 uint32_t p_crc = *crc; 00333 00334 if (width < 8) { 00335 uint8_t data_byte; 00336 for (crc_data_size_t byte = 0; byte < size; byte++) { 00337 data_byte = reflect_bytes(data[byte]); 00338 for (uint8_t bit = 8; bit > 0; --bit) { 00339 p_crc <<= 1; 00340 if (( data_byte ^ p_crc) & get_top_bit()) { 00341 p_crc ^= polynomial; 00342 } 00343 data_byte <<= 1; 00344 } 00345 } 00346 } else { 00347 for (crc_data_size_t byte = 0; byte < size; byte++) { 00348 p_crc ^= (reflect_bytes(data[byte]) << (width - 8)); 00349 00350 // Perform modulo-2 division, a bit at a time 00351 for (uint8_t bit = 8; bit > 0; --bit) { 00352 if (p_crc & get_top_bit()) { 00353 p_crc = (p_crc << 1) ^ polynomial; 00354 } else { 00355 p_crc = (p_crc << 1); 00356 } 00357 } 00358 } 00359 } 00360 *crc = p_crc & get_crc_mask(); 00361 return 0; 00362 } 00363 00364 /** CRC computation using ROM tables 00365 * 00366 * @param buffer data buffer 00367 * @param size size of the data 00368 * @param crc CRC value is filled in, but the value is not the final 00369 * @return 0 on success or a negative error code on failure 00370 */ 00371 int32_t table_compute_partial(const void *buffer, crc_data_size_t size, uint32_t *crc) const 00372 { 00373 MBED_ASSERT(crc != NULL); 00374 MBED_ASSERT(buffer != NULL); 00375 00376 const uint8_t *data = static_cast<const uint8_t *>(buffer); 00377 uint32_t p_crc = *crc; 00378 uint8_t data_byte = 0; 00379 00380 if (width <= 8) { 00381 uint8_t *crc_table = (uint8_t *)_crc_table; 00382 for (crc_data_size_t byte = 0; byte < size; byte++) { 00383 data_byte = reflect_bytes(data[byte]) ^ p_crc; 00384 p_crc = crc_table[data_byte]; 00385 } 00386 } else if (width <= 16) { 00387 uint16_t *crc_table = (uint16_t *)_crc_table; 00388 for (crc_data_size_t byte = 0; byte < size; byte++) { 00389 data_byte = reflect_bytes(data[byte]) ^ (p_crc >> (width - 8)); 00390 p_crc = crc_table[data_byte] ^ (p_crc << 8); 00391 } 00392 } else { 00393 uint32_t *crc_table = (uint32_t *)_crc_table; 00394 for (crc_data_size_t byte = 0; byte < size; byte++) { 00395 data_byte = reflect_bytes(data[byte]) ^ (p_crc >> (width - 8)); 00396 p_crc = crc_table[data_byte] ^ (p_crc << 8); 00397 } 00398 } 00399 *crc = p_crc & get_crc_mask(); 00400 return 0; 00401 } 00402 00403 /** Constructor init called from all specialized cases of constructor 00404 * Note: All construtor common code should be in this function. 00405 */ 00406 void mbed_crc_ctor(void) const 00407 { 00408 MBED_STATIC_ASSERT(width <= 32, "Max 32-bit CRC supported"); 00409 } 00410 }; 00411 00412 #if defined ( __CC_ARM ) 00413 #elif defined ( __GNUC__ ) 00414 #pragma GCC diagnostic pop 00415 #endif 00416 00417 /** @}*/ 00418 } // namespace mbed 00419 00420 #endif
Generated on Tue Jul 12 2022 13:30:54 by
