Skip to content

Commit 1e3e694

Browse files
author
Cruz Monrreal
authored
Merge pull request #7781 from deepikabhavnani/crc_safety
Add thread safety to CRC class
2 parents 7d871bf + 986411c commit 1e3e694

File tree

3 files changed

+107
-24
lines changed

3 files changed

+107
-24
lines changed

TESTS/mbed_drivers/crc/main.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,41 @@ void test_any_polynomial()
125125
}
126126
}
127127

128+
void test_thread(void)
129+
{
130+
char test[] = "123456789";
131+
uint32_t crc;
132+
MbedCRC<POLY_32BIT_ANSI, 32> ct;
133+
TEST_ASSERT_EQUAL(0, ct.compute((void *)test, strlen((const char*)test), &crc));
134+
TEST_ASSERT_EQUAL(0xCBF43926, crc);
135+
}
136+
137+
void test_thread_safety()
138+
{
139+
char test[] = "123456789";
140+
uint32_t crc;
141+
142+
MbedCRC<POLY_16BIT_IBM, 16> ct;
143+
144+
TEST_ASSERT_EQUAL(0, ct.compute_partial_start(&crc));
145+
TEST_ASSERT_EQUAL(0, ct.compute_partial((void *)&test, 4, &crc));
146+
147+
Thread t1(osPriorityNormal1, 320);
148+
t1.start(callback(test_thread));
149+
TEST_ASSERT_EQUAL(0, ct.compute_partial((void *)&test[4], 5, &crc));
150+
TEST_ASSERT_EQUAL(0, ct.compute_partial_stop(&crc));
151+
TEST_ASSERT_EQUAL(0xBB3D, crc);
152+
153+
// Wait for the thread to finish
154+
t1.join();
155+
}
156+
128157
Case cases[] = {
129158
Case("Test supported polynomials", test_supported_polynomials),
130159
Case("Test partial CRC", test_partial_crc),
131160
Case("Test SD CRC polynomials", test_sd_crc),
132-
Case("Test not supported polynomials", test_any_polynomial)
161+
Case("Test not supported polynomials", test_any_polynomial),
162+
Case("Test thread safety", test_thread_safety)
133163
};
134164

135165
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)

drivers/MbedCRC.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ namespace mbed {
2222
/** \addtogroup drivers */
2323
/** @{*/
2424

25+
SingletonPtr<PlatformMutex> mbed_crc_mutex;
26+
2527
/* Default values for different types of polynomials
2628
*/
2729
template<>

drivers/MbedCRC.h

Lines changed: 74 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include "drivers/TableCRC.h"
2020
#include "hal/crc_api.h"
2121
#include "platform/mbed_assert.h"
22+
#include "platform/SingletonPtr.h"
23+
#include "platform/PlatformMutex.h"
2224

2325
/* This is invalid warning from the compiler for below section of code
2426
if ((width < 8) && (NULL == _crc_table)) {
@@ -45,6 +47,7 @@ namespace mbed {
4547
* ROM polynomial tables for supported polynomials (:: crc_polynomial_t) will be used for
4648
* software CRC computation, if ROM tables are not available then CRC is computed runtime
4749
* bit by bit for all data input.
50+
* @note Synchronization level: Thread safe
4851
*
4952
* @tparam polynomial CRC polynomial value in hex
5053
* @tparam width CRC polynomial width
@@ -79,21 +82,22 @@ namespace mbed {
7982
* uint32_t crc = 0;
8083
*
8184
* printf("\nPolynomial = 0x%lx Width = %d \n", ct.get_polynomial(), ct.get_width());
82-
*
8385
* ct.compute_partial_start(&crc);
8486
* ct.compute_partial((void *)&test, 4, &crc);
8587
* ct.compute_partial((void *)&test[4], 5, &crc);
8688
* ct.compute_partial_stop(&crc);
87-
*
8889
* printf("The CRC of data \"123456789\" is : 0x%lx\n", crc);
8990
* return 0;
9091
* }
9192
* @endcode
9293
* @ingroup drivers
9394
*/
9495

96+
extern SingletonPtr<PlatformMutex> mbed_crc_mutex;
97+
9598
template <uint32_t polynomial = POLY_32BIT_ANSI, uint8_t width = 32>
9699
class MbedCRC {
100+
97101
public:
98102
enum CrcMode
99103
{
@@ -104,7 +108,6 @@ class MbedCRC {
104108
BITWISE
105109
};
106110

107-
public:
108111
typedef uint64_t crc_data_size_t;
109112

110113
/** Lifetime of CRC object
@@ -113,7 +116,7 @@ class MbedCRC {
113116
* @param final_xor Final Xor value
114117
* @param reflect_data
115118
* @param reflect_remainder
116-
* @note Default constructor without any arguments is valid only for supported CRC polynomials. :: crc_polynomial_t
119+
* @note Default constructor without any arguments is valid only for supported CRC polynomials. :: crc_polynomial_t
117120
* MbedCRC <POLY_7BIT_SD, 7> ct; --- Valid POLY_7BIT_SD
118121
* MbedCRC <0x1021, 16> ct; --- Valid POLY_16BIT_CCITT
119122
* MbedCRC <POLY_16BIT_CCITT, 32> ct; --- Invalid, compilation error
@@ -135,6 +138,8 @@ class MbedCRC {
135138
}
136139

137140
/** Compute CRC for the data input
141+
* Compute CRC performs the initialization, computation and collection of
142+
* final CRC.
138143
*
139144
* @param buffer Data bytes
140145
* @param size Size of data
@@ -144,52 +149,73 @@ class MbedCRC {
144149
int32_t compute(void *buffer, crc_data_size_t size, uint32_t *crc)
145150
{
146151
MBED_ASSERT(crc != NULL);
147-
int32_t status;
148-
if (0 != (status = compute_partial_start(crc))) {
149-
*crc = 0;
152+
int32_t status = 0;
153+
154+
status = compute_partial_start(crc);
155+
if (0 != status) {
156+
unlock();
150157
return status;
151158
}
152-
if (0 != (status = compute_partial(buffer, size, crc))) {
153-
*crc = 0;
159+
160+
status = compute_partial(buffer, size, crc);
161+
if (0 != status) {
162+
unlock();
154163
return status;
155164
}
156-
if (0 != (status = compute_partial_stop(crc))) {
157-
*crc = 0;
158-
return status;
165+
166+
status = compute_partial_stop(crc);
167+
if (0 != status) {
168+
*crc = 0;
159169
}
160-
return 0;
170+
171+
return status;
172+
161173
}
162174

163175
/** Compute partial CRC for the data input.
164176
*
165177
* CRC data if not available fully, CRC can be computed in parts with available data.
166-
* Previous CRC output should be passed as argument to the current compute_partial call.
167-
* @pre: Call \ref compute_partial_start to start the partial CRC calculation.
168-
* @post: Call \ref compute_partial_stop to get the final CRC value.
178+
*
179+
* In case of hardware, intermediate values and states are saved by hardware and mutex
180+
* locking is used to serialize access to hardware CRC.
181+
*
182+
* In case of software CRC, previous CRC output should be passed as argument to the
183+
* current compute_partial call. Please note the intermediate CRC value is maintained by
184+
* application and not the driver.
185+
*
186+
* @pre: Call `compute_partial_start` to start the partial CRC calculation.
187+
* @post: Call `compute_partial_stop` to get the final CRC value.
169188
*
170189
* @param buffer Data bytes
171190
* @param size Size of data
172191
* @param crc CRC value is intermediate CRC value filled by API.
173192
* @return 0 on success or a negative error code on failure
174-
* @note: CRC as output in compute_partial is not final CRC value, call @ref compute_partial_stop
193+
* @note: CRC as output in compute_partial is not final CRC value, call `compute_partial_stop`
175194
* to get final correct CRC value.
176195
*/
177196
int32_t compute_partial(void *buffer, crc_data_size_t size, uint32_t *crc)
178197
{
198+
int32_t status = 0;
199+
179200
switch (_mode) {
180201
#ifdef DEVICE_CRC
181202
case HARDWARE:
182203
hal_crc_compute_partial((uint8_t *)buffer, size);
183204
*crc = 0;
184-
return 0;
205+
break;
185206
#endif
186207
case TABLE:
187-
return table_compute_partial(buffer, size, crc);
208+
status = table_compute_partial(buffer, size, crc);
209+
break;
188210
case BITWISE:
189-
return bitwise_compute_partial(buffer, size, crc);
211+
status = bitwise_compute_partial(buffer, size, crc);
212+
break;
213+
default:
214+
status = -1;
215+
break;
190216
}
191217

192-
return -1;
218+
return status;
193219
}
194220

195221
/** Compute partial start, indicate start of partial computation
@@ -200,14 +226,15 @@ class MbedCRC {
200226
* @param crc Initial CRC value set by the API
201227
* @return 0 on success or a negative in case of failure
202228
* @note: CRC is an out parameter and must be reused with compute_partial
203-
* and compute_partial_stop without any modifications in application.
229+
* and `compute_partial_stop` without any modifications in application.
204230
*/
205231
int32_t compute_partial_start(uint32_t *crc)
206232
{
207233
MBED_ASSERT(crc != NULL);
208234

209235
#ifdef DEVICE_CRC
210236
if (_mode == HARDWARE) {
237+
lock();
211238
crc_mbed_config_t config;
212239
config.polynomial = polynomial;
213240
config.width = width;
@@ -218,7 +245,7 @@ class MbedCRC {
218245

219246
hal_crc_compute_partial_start(&config);
220247
}
221-
#endif // DEVICE_CRC
248+
#endif
222249

223250
*crc = _initial_value;
224251
return 0;
@@ -239,6 +266,7 @@ class MbedCRC {
239266
#ifdef DEVICE_CRC
240267
if (_mode == HARDWARE) {
241268
*crc = hal_crc_get_result();
269+
unlock();
242270
return 0;
243271
}
244272
#endif
@@ -252,6 +280,7 @@ class MbedCRC {
252280
} else {
253281
*crc = (reflect_remainder(p_crc) ^ _final_xor) & get_crc_mask();
254282
}
283+
unlock();
255284
return 0;
256285
}
257286

@@ -281,6 +310,28 @@ class MbedCRC {
281310
uint32_t *_crc_table;
282311
CrcMode _mode;
283312

313+
/** Acquire exclusive access to CRC hardware/software
314+
*/
315+
void lock()
316+
{
317+
#ifdef DEVICE_CRC
318+
if (_mode == HARDWARE) {
319+
mbed_crc_mutex->lock();
320+
}
321+
#endif
322+
}
323+
324+
/** Release exclusive access to CRC hardware/software
325+
*/
326+
virtual void unlock()
327+
{
328+
#ifdef DEVICE_CRC
329+
if (_mode == HARDWARE) {
330+
mbed_crc_mutex->unlock();
331+
}
332+
#endif
333+
}
334+
284335
/** Get the current CRC data size
285336
*
286337
* @return CRC data size in bytes

0 commit comments

Comments
 (0)