mirror of https://github.com/ARMmbed/mbed-os.git
Add thread safety to CRC class
Thread safety is added to serialize the hardware CRC and will not impact the software CRC.pull/7781/head
parent
ec4c33ca80
commit
986411ccb0
|
@ -125,11 +125,41 @@ void test_any_polynomial()
|
|||
}
|
||||
}
|
||||
|
||||
void test_thread(void)
|
||||
{
|
||||
char test[] = "123456789";
|
||||
uint32_t crc;
|
||||
MbedCRC<POLY_32BIT_ANSI, 32> ct;
|
||||
TEST_ASSERT_EQUAL(0, ct.compute((void *)test, strlen((const char*)test), &crc));
|
||||
TEST_ASSERT_EQUAL(0xCBF43926, crc);
|
||||
}
|
||||
|
||||
void test_thread_safety()
|
||||
{
|
||||
char test[] = "123456789";
|
||||
uint32_t crc;
|
||||
|
||||
MbedCRC<POLY_16BIT_IBM, 16> ct;
|
||||
|
||||
TEST_ASSERT_EQUAL(0, ct.compute_partial_start(&crc));
|
||||
TEST_ASSERT_EQUAL(0, ct.compute_partial((void *)&test, 4, &crc));
|
||||
|
||||
Thread t1(osPriorityNormal1, 320);
|
||||
t1.start(callback(test_thread));
|
||||
TEST_ASSERT_EQUAL(0, ct.compute_partial((void *)&test[4], 5, &crc));
|
||||
TEST_ASSERT_EQUAL(0, ct.compute_partial_stop(&crc));
|
||||
TEST_ASSERT_EQUAL(0xBB3D, crc);
|
||||
|
||||
// Wait for the thread to finish
|
||||
t1.join();
|
||||
}
|
||||
|
||||
Case cases[] = {
|
||||
Case("Test supported polynomials", test_supported_polynomials),
|
||||
Case("Test partial CRC", test_partial_crc),
|
||||
Case("Test SD CRC polynomials", test_sd_crc),
|
||||
Case("Test not supported polynomials", test_any_polynomial)
|
||||
Case("Test not supported polynomials", test_any_polynomial),
|
||||
Case("Test thread safety", test_thread_safety)
|
||||
};
|
||||
|
||||
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
||||
|
|
|
@ -22,6 +22,8 @@ namespace mbed {
|
|||
/** \addtogroup drivers */
|
||||
/** @{*/
|
||||
|
||||
SingletonPtr<PlatformMutex> mbed_crc_mutex;
|
||||
|
||||
/* Default values for different types of polynomials
|
||||
*/
|
||||
template<>
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include "drivers/TableCRC.h"
|
||||
#include "hal/crc_api.h"
|
||||
#include "platform/mbed_assert.h"
|
||||
#include "platform/SingletonPtr.h"
|
||||
#include "platform/PlatformMutex.h"
|
||||
|
||||
/* This is invalid warning from the compiler for below section of code
|
||||
if ((width < 8) && (NULL == _crc_table)) {
|
||||
|
@ -45,6 +47,7 @@ namespace mbed {
|
|||
* ROM polynomial tables for supported polynomials (:: crc_polynomial_t) will be used for
|
||||
* software CRC computation, if ROM tables are not available then CRC is computed runtime
|
||||
* bit by bit for all data input.
|
||||
* @note Synchronization level: Thread safe
|
||||
*
|
||||
* @tparam polynomial CRC polynomial value in hex
|
||||
* @tparam width CRC polynomial width
|
||||
|
@ -79,12 +82,10 @@ namespace mbed {
|
|||
* uint32_t crc = 0;
|
||||
*
|
||||
* printf("\nPolynomial = 0x%lx Width = %d \n", ct.get_polynomial(), ct.get_width());
|
||||
*
|
||||
* ct.compute_partial_start(&crc);
|
||||
* ct.compute_partial((void *)&test, 4, &crc);
|
||||
* ct.compute_partial((void *)&test[4], 5, &crc);
|
||||
* ct.compute_partial_stop(&crc);
|
||||
*
|
||||
* printf("The CRC of data \"123456789\" is : 0x%lx\n", crc);
|
||||
* return 0;
|
||||
* }
|
||||
|
@ -92,8 +93,11 @@ namespace mbed {
|
|||
* @ingroup drivers
|
||||
*/
|
||||
|
||||
extern SingletonPtr<PlatformMutex> mbed_crc_mutex;
|
||||
|
||||
template <uint32_t polynomial = POLY_32BIT_ANSI, uint8_t width = 32>
|
||||
class MbedCRC {
|
||||
|
||||
public:
|
||||
enum CrcMode
|
||||
{
|
||||
|
@ -104,7 +108,6 @@ public:
|
|||
BITWISE
|
||||
};
|
||||
|
||||
public:
|
||||
typedef uint64_t crc_data_size_t;
|
||||
|
||||
/** Lifetime of CRC object
|
||||
|
@ -113,7 +116,7 @@ public:
|
|||
* @param final_xor Final Xor value
|
||||
* @param reflect_data
|
||||
* @param reflect_remainder
|
||||
* @note Default constructor without any arguments is valid only for supported CRC polynomials. :: crc_polynomial_t
|
||||
* @note Default constructor without any arguments is valid only for supported CRC polynomials. :: crc_polynomial_t
|
||||
* MbedCRC <POLY_7BIT_SD, 7> ct; --- Valid POLY_7BIT_SD
|
||||
* MbedCRC <0x1021, 16> ct; --- Valid POLY_16BIT_CCITT
|
||||
* MbedCRC <POLY_16BIT_CCITT, 32> ct; --- Invalid, compilation error
|
||||
|
@ -135,6 +138,8 @@ public:
|
|||
}
|
||||
|
||||
/** Compute CRC for the data input
|
||||
* Compute CRC performs the initialization, computation and collection of
|
||||
* final CRC.
|
||||
*
|
||||
* @param buffer Data bytes
|
||||
* @param size Size of data
|
||||
|
@ -144,52 +149,73 @@ public:
|
|||
int32_t compute(void *buffer, crc_data_size_t size, uint32_t *crc)
|
||||
{
|
||||
MBED_ASSERT(crc != NULL);
|
||||
int32_t status;
|
||||
if (0 != (status = compute_partial_start(crc))) {
|
||||
*crc = 0;
|
||||
int32_t status = 0;
|
||||
|
||||
status = compute_partial_start(crc);
|
||||
if (0 != status) {
|
||||
unlock();
|
||||
return status;
|
||||
}
|
||||
if (0 != (status = compute_partial(buffer, size, crc))) {
|
||||
*crc = 0;
|
||||
|
||||
status = compute_partial(buffer, size, crc);
|
||||
if (0 != status) {
|
||||
unlock();
|
||||
return status;
|
||||
}
|
||||
if (0 != (status = compute_partial_stop(crc))) {
|
||||
*crc = 0;
|
||||
return status;
|
||||
|
||||
status = compute_partial_stop(crc);
|
||||
if (0 != status) {
|
||||
*crc = 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
/** Compute partial CRC for the data input.
|
||||
*
|
||||
* CRC data if not available fully, CRC can be computed in parts with available data.
|
||||
* Previous CRC output should be passed as argument to the current compute_partial call.
|
||||
* @pre: Call \ref compute_partial_start to start the partial CRC calculation.
|
||||
* @post: Call \ref compute_partial_stop to get the final CRC value.
|
||||
*
|
||||
* In case of hardware, intermediate values and states are saved by hardware and mutex
|
||||
* locking is used to serialize access to hardware CRC.
|
||||
*
|
||||
* In case of software CRC, previous CRC output should be passed as argument to the
|
||||
* current compute_partial call. Please note the intermediate CRC value is maintained by
|
||||
* application and not the driver.
|
||||
*
|
||||
* @pre: Call `compute_partial_start` to start the partial CRC calculation.
|
||||
* @post: Call `compute_partial_stop` to get the final CRC value.
|
||||
*
|
||||
* @param buffer Data bytes
|
||||
* @param size Size of data
|
||||
* @param crc CRC value is intermediate CRC value filled by API.
|
||||
* @return 0 on success or a negative error code on failure
|
||||
* @note: CRC as output in compute_partial is not final CRC value, call @ref compute_partial_stop
|
||||
* @note: CRC as output in compute_partial is not final CRC value, call `compute_partial_stop`
|
||||
* to get final correct CRC value.
|
||||
*/
|
||||
int32_t compute_partial(void *buffer, crc_data_size_t size, uint32_t *crc)
|
||||
{
|
||||
int32_t status = 0;
|
||||
|
||||
switch (_mode) {
|
||||
#ifdef DEVICE_CRC
|
||||
case HARDWARE:
|
||||
hal_crc_compute_partial((uint8_t *)buffer, size);
|
||||
*crc = 0;
|
||||
return 0;
|
||||
break;
|
||||
#endif
|
||||
case TABLE:
|
||||
return table_compute_partial(buffer, size, crc);
|
||||
status = table_compute_partial(buffer, size, crc);
|
||||
break;
|
||||
case BITWISE:
|
||||
return bitwise_compute_partial(buffer, size, crc);
|
||||
status = bitwise_compute_partial(buffer, size, crc);
|
||||
break;
|
||||
default:
|
||||
status = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Compute partial start, indicate start of partial computation
|
||||
|
@ -200,7 +226,7 @@ public:
|
|||
* @param crc Initial CRC value set by the API
|
||||
* @return 0 on success or a negative in case of failure
|
||||
* @note: CRC is an out parameter and must be reused with compute_partial
|
||||
* and compute_partial_stop without any modifications in application.
|
||||
* and `compute_partial_stop` without any modifications in application.
|
||||
*/
|
||||
int32_t compute_partial_start(uint32_t *crc)
|
||||
{
|
||||
|
@ -208,6 +234,7 @@ public:
|
|||
|
||||
#ifdef DEVICE_CRC
|
||||
if (_mode == HARDWARE) {
|
||||
lock();
|
||||
crc_mbed_config_t config;
|
||||
config.polynomial = polynomial;
|
||||
config.width = width;
|
||||
|
@ -218,7 +245,7 @@ public:
|
|||
|
||||
hal_crc_compute_partial_start(&config);
|
||||
}
|
||||
#endif // DEVICE_CRC
|
||||
#endif
|
||||
|
||||
*crc = _initial_value;
|
||||
return 0;
|
||||
|
@ -239,6 +266,7 @@ public:
|
|||
#ifdef DEVICE_CRC
|
||||
if (_mode == HARDWARE) {
|
||||
*crc = hal_crc_get_result();
|
||||
unlock();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -252,6 +280,7 @@ public:
|
|||
} else {
|
||||
*crc = (reflect_remainder(p_crc) ^ _final_xor) & get_crc_mask();
|
||||
}
|
||||
unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -281,6 +310,28 @@ private:
|
|||
uint32_t *_crc_table;
|
||||
CrcMode _mode;
|
||||
|
||||
/** Acquire exclusive access to CRC hardware/software
|
||||
*/
|
||||
void lock()
|
||||
{
|
||||
#ifdef DEVICE_CRC
|
||||
if (_mode == HARDWARE) {
|
||||
mbed_crc_mutex->lock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Release exclusive access to CRC hardware/software
|
||||
*/
|
||||
virtual void unlock()
|
||||
{
|
||||
#ifdef DEVICE_CRC
|
||||
if (_mode == HARDWARE) {
|
||||
mbed_crc_mutex->unlock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Get the current CRC data size
|
||||
*
|
||||
* @return CRC data size in bytes
|
||||
|
|
Loading…
Reference in New Issue