summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Peplin <chris.peplin@rhubarbtech.com>2014-01-04 10:51:16 -0500
committerChristopher Peplin <chris.peplin@rhubarbtech.com>2014-01-04 10:52:42 -0500
commit08db5c9eb826f7aa0dba36cbef8011d7bc6b55a5 (patch)
treeb2875552387f00191c772bc6da08dcaa7e6d2e87
parent6f3a81ed8287357b54aad16bff27495c6eaca6df (diff)
Add a get_bitfield function for byte arrays.
-rw-r--r--Makefile3
-rw-r--r--README.mkd6
-rw-r--r--src/bitfield/8byte.c10
-rw-r--r--src/bitfield/8byte.h4
-rw-r--r--src/bitfield/bitfield.c18
-rw-r--r--src/bitfield/bitfield.h34
-rw-r--r--src/canutil/read.c18
-rw-r--r--src/canutil/read.h42
-rw-r--r--tests/8byte_tests.c40
-rw-r--r--tests/read_tests.c35
10 files changed, 164 insertions, 46 deletions
diff --git a/Makefile b/Makefile
index c3c3e5a4..89fbf25a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
CC = gcc
INCLUDES = -Isrc
-CFLAGS = $(INCLUDES) -c -w -Wall -Werror -g -ggdb -std=gnu++0x -coverage
+CFLAGS = $(INCLUDES) -c -w -Wall -Werror -g -ggdb -std=gnu99 -coverage
LDFLAGS = -coverage -lm
LDLIBS = -lcheck
@@ -36,6 +36,7 @@ coverage:
@make clean
@make test
@lcov --base-directory . --directory $(TEST_OBJDIR) -c -o $(TEST_OBJDIR)/coverage.info
+ @lcov --remove $(COVERAGE_INFO_PATH) "/usr/*" -o $(COVERAGE_INFO_PATH)
@genhtml -o $(TEST_OBJDIR)/coverage -t "isotp-c test coverage" --num-spaces 4 $(COVERAGE_INFO_PATH)
@$(BROWSER) $(TEST_OBJDIR)/coverage/index.html
@echo "$(GREEN)Coverage information generated in $(TEST_OBJDIR)/coverage/index.html.$(COLOR_RESET)"
diff --git a/README.mkd b/README.mkd
index d16a8931..0cad3d21 100644
--- a/README.mkd
+++ b/README.mkd
@@ -30,11 +30,11 @@ useful.
### 8 Byte Decoding
uint64_t data = 0x8000000000000000;
- uint64_t result = get_bit_field(data, 0, 1, false);
+ uint64_t result = get_bitfield(data, 0, 1, false);
// result == 0x1
data = 0x0402574d555a0401;
- result = get_bit_field(data, 16, 32, false);
+ result = get_bitfield(data, 16, 32, false);
// result = 0x574d555a;
data = 0x00000000F34DFCFF;
@@ -51,7 +51,7 @@ useful.
uint64_t data = 0;
fail_unless(set_bit_field(&data, 1, 0, 1));
- uint64_t result = get_bit_field(data, 0, 1, false);
+ uint64_t result = get_bitfield(data, 0, 1, false);
ck_assert_int_eq(result, 0x1);
### CAN Signal Encoding
diff --git a/src/bitfield/8byte.c b/src/bitfield/8byte.c
index 76dccc75..3c555f08 100644
--- a/src/bitfield/8byte.c
+++ b/src/bitfield/8byte.c
@@ -8,7 +8,7 @@
uint8_t eightbyte_get_nibble(const uint64_t source, const uint8_t nibble_index,
const bool data_is_big_endian) {
- return eightbyte_get_bit_field(source, NIBBLE_SIZE * nibble_index, NIBBLE_SIZE,
+ return eightbyte_get_bitfield(source, NIBBLE_SIZE * nibble_index, NIBBLE_SIZE,
data_is_big_endian);
}
@@ -20,7 +20,10 @@ uint8_t eightbyte_get_byte(uint64_t source, const uint8_t byte_index,
return (source >> (EIGHTBYTE_BIT - ((byte_index + 1) * CHAR_BIT))) & 0xFF;
}
-uint64_t eightbyte_get_bit_field(uint64_t source, const uint16_t offset,
+// TODO is this funciton necessary anymore? is it any faster for uint64_t than
+// get_bitfield(data[], ...)? is the performance better on a 32 bit platform
+// like the PIC32?
+uint64_t eightbyte_get_bitfield(uint64_t source, const uint16_t offset,
const uint16_t bit_count, const bool data_is_big_endian) {
int startByte = offset / CHAR_BIT;
int endByte = (offset + bit_count - 1) / CHAR_BIT;
@@ -33,8 +36,7 @@ uint64_t eightbyte_get_bit_field(uint64_t source, const uint16_t offset,
uint64_t ret = bytes[startByte];
if(startByte != endByte) {
// The lowest byte address contains the most significant bit.
- int i;
- for(i = startByte + 1; i <= endByte; i++) {
+ for(uint8_t i = startByte + 1; i <= endByte; i++) {
ret = ret << 8;
ret = ret | bytes[i];
}
diff --git a/src/bitfield/8byte.h b/src/bitfield/8byte.h
index 194007c8..ab775caa 100644
--- a/src/bitfield/8byte.h
+++ b/src/bitfield/8byte.h
@@ -32,11 +32,11 @@ extern "C" {
*
* Examples
*
- * uint64_t value = get_bit_field(data, 2, 4);
+ * uint64_t value = get_bitfield(data, 2, 4);
*
* Returns the value of the requested bit field, right aligned in a uint64_t.
*/
-uint64_t eightbyte_get_bit_field(uint64_t source, const uint16_t offset,
+uint64_t eightbyte_get_bitfield(uint64_t source, const uint16_t offset,
const uint16_t bit_count, const bool data_is_big_endian);
/* Public: Return a single nibble from the payload, with range checking.
diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c
index 3b0c5fdd..52f368f5 100644
--- a/src/bitfield/bitfield.c
+++ b/src/bitfield/bitfield.c
@@ -2,6 +2,7 @@
#include <limits.h>
#include <string.h>
#include <stddef.h>
+#include <endian.h>
uint64_t bitmask(const uint8_t bit_count) {
return (((uint64_t)0x1) << bit_count) - 1;
@@ -26,8 +27,25 @@ uint8_t get_byte(const uint8_t source[], const uint8_t source_length,
return 0;
}
+uint64_t get_bitfield(const uint8_t source[], const uint8_t source_length,
+ const uint16_t offset, const uint16_t bit_count) {
+ if(bit_count > 64 || bit_count < 1) {
+ // TODO error reporting?
+ return 0;
+ }
+
+ union {
+ uint64_t whole;
+ uint8_t bytes[sizeof(uint64_t)];
+ } combined;
+ copy_bits_right_aligned(source, source_length, offset, bit_count,
+ combined.bytes, sizeof(combined.bytes));
+ return htobe64(combined.whole);
+}
+
bool set_nibble(const uint16_t nibble_index, const uint8_t value,
uint8_t* destination, const uint16_t destination_length) {
return copy_bits(&value, CHAR_BIT, NIBBLE_SIZE, NIBBLE_SIZE, destination,
destination_length, nibble_index * NIBBLE_SIZE);
}
+
diff --git a/src/bitfield/bitfield.h b/src/bitfield/bitfield.h
index 5dd976f0..80f31243 100644
--- a/src/bitfield/bitfield.h
+++ b/src/bitfield/bitfield.h
@@ -10,6 +10,36 @@
extern "C" {
#endif
+/* Public: Reads a subset of bits into a uint64_t, right aligned so they may be
+ * interpreted as a number.
+ *
+ * source - the bytes in question.
+ * source_size - the number of bytes in the source.
+ * offset - the starting index of the bit field (beginning from 0).
+ * bit_count - the width of the bit field to extract. This must be less than or
+ * equal to 64.
+ *
+ * Bit fields are positioned according to big-endian bit layout and the data is
+ * swapped automatically as necessary depending on the compiled architecture.
+ *
+ * For example, the bit layout of the value "42" (i.e. 00101010 set at position
+ * 14 with length 6 is:
+ *
+ * 000000000000001010100000000000000000000000000000000000000000000
+ *
+ * and the same value and position but with length 8 is:
+ *
+ * 000000000000000010101000000000000000000000000000000000000000000
+ *
+ * Examples
+ *
+ * uint64_t value = get_bitfield(data, data_size, 2, 4);
+ *
+ * Returns the value of the requested bit field, right aligned in a uint64_t.
+ */
+uint64_t get_bits(const uint8_t source[], const uint8_t source_length,
+ const uint16_t offset, const uint16_t bit_count);
+
/* Public: Return a single nibble from the byte array, with range checking.
*
* source - the source byte array.
@@ -142,7 +172,9 @@ bool set_nibble(const uint16_t nibble_index, const uint8_t value,
*/
uint16_t bits_to_bytes(uint32_t bits);
-/* Private:
+/* Public: Return a right aligned bitmask for a uint64_t.
+ *
+ * bit_count - the number of bits to mask, right aligned.
*/
uint64_t bitmask(const uint8_t bit_count);
diff --git a/src/canutil/read.c b/src/canutil/read.c
index 4864a60f..3931721a 100644
--- a/src/canutil/read.c
+++ b/src/canutil/read.c
@@ -4,7 +4,7 @@
float eightbyte_parse_float(uint64_t data, uint8_t bit_offset, uint8_t bit_size,
float factor, float offset) {
- uint64_t raw = eightbyte_get_bit_field(data, bit_offset, bit_size, true);
+ uint64_t raw = eightbyte_get_bitfield(data, bit_offset, bit_size, true);
return raw * factor + offset;
}
@@ -14,9 +14,19 @@ bool eightbyte_parse_bool(uint64_t data, uint8_t bit_offset, uint8_t bit_size,
return value == 0.0 ? false : true;
}
-float bitfield_parse_float(const uint8_t data[], const uint16_t size,
+float bitfield_parse_float(const uint8_t source[], const uint16_t source_length,
const uint8_t bit_offset, const uint8_t bit_size, const float factor,
const float offset) {
- //TODO
- return 0;
+ uint64_t raw = get_bitfield(source, source_length, bit_offset, bit_size);
+ // TODO seems dumb that this is repeated from eightbyte_parse_float - is it
+ // really worth keeping around these two implementations?
+ return raw * factor + offset;
+}
+
+float bitfield_parse_bool(const uint8_t source[], const uint16_t source_length,
+ const uint8_t bit_offset, const uint8_t bit_size, const float factor,
+ const float offset) {
+ float value = bitfield_parse_float(source, source_length, bit_offset,
+ bit_size, factor, offset);
+ return value == 0.0 ? false : true;
}
diff --git a/src/canutil/read.h b/src/canutil/read.h
index bf6c0ade..733e3509 100644
--- a/src/canutil/read.h
+++ b/src/canutil/read.h
@@ -10,7 +10,7 @@ extern "C" {
/* Public: Parse a CAN signal from a message and apply required transformation.
*
- * data - the payload containing the signal.
+ * source - the payload containing the signal.
* bit_offset - the starting bit for the signal.
* bit_size - the width of the signal.
* factor - the transformation factor for the signal value, applied after
@@ -20,16 +20,30 @@ extern "C" {
*
* Returns the decoded and transformed value of the signal.
*/
-float eightbyte_parse_float(const uint64_t data, const uint8_t bit_offset,
+float eightbyte_parse_float(const uint64_t source, const uint8_t bit_offset,
const uint8_t bit_size, const float factor, const float offset);
-float bitfield_parse_float(const uint8_t data[], const uint16_t size,
+/* Public: Parse a CAN signal from a message storage as a byte array and apply
+ * required transformation.
+ *
+ * source - the payload containing the signal.
+ * source_size - the size of the payload in bytes.
+ * bit_offset - the starting bit for the signal.
+ * bit_size - the width of the signal.
+ * factor - the transformation factor for the signal value, applied after
+ * pulling out the bit field. Use 1.0 for no factor.
+ * offset - the transformation offset for the signal value, applied after
+ * pulling out the bit field. Use 0 for no offset.
+ *
+ * Returns the decoded and transformed value of the signal.
+ */
+float bitfield_parse_float(const uint8_t source[], const uint16_t source_size,
const uint8_t bit_offset, const uint8_t bit_size, const float factor,
const float offset);
/* Public: Parse a CAN signal from a message and interpret it as a boolean.
*
- * data - the payload containing the signal.
+ * source - the payload containing the signal.
* bit_offset - the starting bit for the signal.
* bit_size - the width of the signal.
* factor - the transformation factor for the signal value, applied after
@@ -39,9 +53,27 @@ float bitfield_parse_float(const uint8_t data[], const uint16_t size,
*
* Returns false if the value was 0, otherwise true.
*/
-bool eightbyte_parse_bool(uint64_t data, uint8_t bit_offset, uint8_t bit_size,
+bool eightbyte_parse_bool(uint64_t source, uint8_t bit_offset, uint8_t bit_size,
float factor, float offset);
+/* Public: Parse a CAN signal from a message storage as a byte array and
+ * interpret it as a boolean.
+ *
+ * source - the payload containing the signal.
+ * source_size - the size of the payload in bytes.
+ * bit_offset - the starting bit for the signal.
+ * bit_size - the width of the signal.
+ * factor - the transformation factor for the signal value, applied after
+ * pulling out the bit field. Use 1.0 for no factor.
+ * offset - the transformation offset for the signal value, applied after
+ * pulling out the bit field. Use 0 for no offset.
+ *
+ * Returns false if the value was 0, otherwise true.
+ */
+float bitfield_parse_float(const uint8_t source[], const uint16_t source_size,
+ const uint8_t bit_offset, const uint8_t bit_size, const float factor,
+ const float offset);
+
#ifdef __cplusplus
}
#endif
diff --git a/tests/8byte_tests.c b/tests/8byte_tests.c
index 5ebb0db0..12ff417d 100644
--- a/tests/8byte_tests.c
+++ b/tests/8byte_tests.c
@@ -12,7 +12,7 @@ END_TEST
START_TEST (test_one_bit_not_swapped)
{
uint64_t data = 0x80;
- uint64_t result = eightbyte_get_bit_field(data, 0, 1, false);
+ uint64_t result = eightbyte_get_bitfield(data, 0, 1, false);
fail_if(result == 1);
}
END_TEST
@@ -20,7 +20,7 @@ END_TEST
START_TEST (test_one_bit)
{
uint64_t data = 0x8000000000000000;
- uint64_t result = eightbyte_get_bit_field(data, 0, 1, false);
+ uint64_t result = eightbyte_get_bitfield(data, 0, 1, false);
fail_unless(result == 0x1,
"First bit in 0x%llx was 0x%llx instead of 0x1", data, result);
}
@@ -29,7 +29,7 @@ END_TEST
START_TEST (test_32_bit_parse)
{
uint64_t data = 0x0402574d555a0401;
- uint64_t result = eightbyte_get_bit_field(data, 16, 32, false);
+ uint64_t result = eightbyte_get_bitfield(data, 16, 32, false);
uint64_t expectedValue = 0x574d555a;
fail_unless(result == expectedValue,
"Field retrieved in 0x%llx was 0x%llx instead of 0x%llx", data,
@@ -40,7 +40,7 @@ END_TEST
START_TEST (test_16_bit_parse)
{
uint64_t data = 0xF34DFCFF00000000;
- uint64_t result = eightbyte_get_bit_field(data, 16, 16, false);
+ uint64_t result = eightbyte_get_bitfield(data, 16, 16, false);
uint64_t expectedValue = 0xFCFF;
fail_unless(result == expectedValue,
"Field retrieved in 0x%llx was 0x%llx instead of 0x%llx", data,
@@ -51,13 +51,13 @@ END_TEST
START_TEST (test_one_byte)
{
uint64_t data = 0xFA00000000000000;
- uint64_t result = eightbyte_get_bit_field(data, 0, 4, false);
+ uint64_t result = eightbyte_get_bitfield(data, 0, 4, false);
fail_unless(result == 0xF,
"First nibble in 0x%llx was 0x%llx instead of 0xF", data, result);
- result = eightbyte_get_bit_field(data, 4, 4, false);
+ result = eightbyte_get_bitfield(data, 4, 4, false);
fail_unless(result == 0xA,
"Second nibble in 0x%llx was 0x%llx instead of 0xA", data, result);
- result = eightbyte_get_bit_field(data, 0, 8, false);
+ result = eightbyte_get_bitfield(data, 0, 8, false);
fail_unless(result == 0xFA,
"All bits in 0x%llx were 0x%llx instead of 0x%llx", data, result, data);
}
@@ -66,19 +66,19 @@ END_TEST
START_TEST (test_multi_byte)
{
uint64_t data = 0x12FA000000000000;
- uint64_t result = eightbyte_get_bit_field(data, 0, 4, false);
+ uint64_t result = eightbyte_get_bitfield(data, 0, 4, false);
fail_unless(result == 0x1,
"First 4 bits in 0x%llx was 0x%llx instead of 0xF", (data >> 60) & 0xF,
result);
- result = eightbyte_get_bit_field(data, 4, 4, false);
+ result = eightbyte_get_bitfield(data, 4, 4, false);
fail_unless(result == 0x2,
"Second 4 bits in 0x%llx was 0x%llx instead of 0xA", (data >> 56) & 0xF,
result);
- result = eightbyte_get_bit_field(data, 8, 4, false);
+ result = eightbyte_get_bitfield(data, 8, 4, false);
fail_unless(result == 0xF,
"First 4 bits in 0x%llx was 0x%llx instead of 0x1", (data >> 52) & 0xF,
result);
- result = eightbyte_get_bit_field(data, 12, 4, false);
+ result = eightbyte_get_bitfield(data, 12, 4, false);
fail_unless(result == 0xA,
"Second 4 bits in 0x%llx was 0x%llx instead of 0x2", (data >> 48) % 0xF,
result);
@@ -88,7 +88,7 @@ END_TEST
START_TEST (test_get_multi_byte)
{
uint64_t data = 0x12FA000000000000;
- uint64_t result = eightbyte_get_bit_field(data, 0, 9, false);
+ uint64_t result = eightbyte_get_bitfield(data, 0, 9, false);
ck_assert_int_eq(result, 0x25);
}
END_TEST
@@ -96,7 +96,7 @@ END_TEST
START_TEST (test_get_off_byte_boundary)
{
uint64_t data = 0x000012FA00000000;
- uint64_t result = eightbyte_get_bit_field(data, 12, 8, false);
+ uint64_t result = eightbyte_get_bitfield(data, 12, 8, false);
ck_assert_int_eq(result, 0x01);
} END_TEST
@@ -111,16 +111,16 @@ START_TEST (test_set_field)
{
uint64_t data = 0;
fail_unless(set_bit_field(&data, 1, 0, 1));
- uint64_t result = eightbyte_get_bit_field(data, 0, 1, false);
+ uint64_t result = eightbyte_get_bitfield(data, 0, 1, false);
ck_assert_int_eq(result, 0x1);
data = 0;
fail_unless(set_bit_field(&data, 1, 1, 1));
- result = eightbyte_get_bit_field(data, 1, 1, false);
+ result = eightbyte_get_bitfield(data, 1, 1, false);
ck_assert_int_eq(result, 0x1);
data = 0;
fail_unless(set_bit_field(&data, 0xf, 3, 4));
- result = eightbyte_get_bit_field(data, 3, 4, false);
+ result = eightbyte_get_bitfield(data, 3, 4, false);
ck_assert_int_eq(result, 0xf);
}
END_TEST
@@ -129,7 +129,7 @@ START_TEST (test_set_doesnt_clobber_existing_data)
{
uint64_t data = 0xFFFC4DF300000000;
fail_unless(set_bit_field(&data, 0x4fc8, 16, 16));
- uint64_t result = eightbyte_get_bit_field(data, 16, 16, false);
+ uint64_t result = eightbyte_get_bitfield(data, 16, 16, false);
fail_unless(result == 0x4fc8,
"Field retrieved in 0x%llx was 0x%llx instead of 0x%x", data, result,
0xc84f);
@@ -146,7 +146,7 @@ START_TEST (test_set_off_byte_boundary)
{
uint64_t data = 0xFFFC4DF300000000;
fail_unless(set_bit_field(&data, 0x12, 12, 8));
- uint64_t result = eightbyte_get_bit_field(data, 12, 12, false);
+ uint64_t result = eightbyte_get_bitfield(data, 12, 12, false);
ck_assert_int_eq(result,0x12d);
}
END_TEST
@@ -155,14 +155,14 @@ START_TEST (test_set_odd_number_of_bits)
{
uint64_t data = 0xFFFC4DF300000000LLU;
fail_unless(set_bit_field(&data, 0x12, 11, 5));
- uint64_t result = eightbyte_get_bit_field(data, 11, 5, false);
+ uint64_t result = eightbyte_get_bitfield(data, 11, 5, false);
fail_unless(result == 0x12,
"Field set in 0x%llx%llx%llx%llx was 0x%llx instead of 0x%llx", data, result,
0x12);
data = 0xFFFC4DF300000000LLU;
fail_unless(set_bit_field(&data, 0x2, 11, 5));
- result = eightbyte_get_bit_field(data, 11, 5, false);
+ result = eightbyte_get_bitfield(data, 11, 5, false);
fail_unless(result == 0x2,
"Field set in 0x%llx%llx%llx%llx was 0x%llx instead of 0x%llx", data, result,
0x2);
diff --git a/tests/read_tests.c b/tests/read_tests.c
index 1cde4612..512d87e8 100644
--- a/tests/read_tests.c
+++ b/tests/read_tests.c
@@ -3,8 +3,9 @@
#include <canutil/read.h>
const uint64_t BIG_ENDIAN_TEST_DATA = __builtin_bswap64(0xEB00000000000000);
+const uint8_t ARRAY_TEST_DATA[] = {0xEB, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
-START_TEST (test_parse_float)
+START_TEST (test_eightbyte_parse_float)
{
float result = eightbyte_parse_float(BIG_ENDIAN_TEST_DATA, 2, 4, 1001.0,
-30000.0);
@@ -14,10 +15,30 @@ START_TEST (test_parse_float)
}
END_TEST
-START_TEST (test_parse_bool)
+START_TEST (test_eightbyte_parse_bool)
{
- float result = eightbyte_parse_bool(BIG_ENDIAN_TEST_DATA, 0, 1, 1.0, 0);
- float correctResult = true;
+ bool result = eightbyte_parse_bool(BIG_ENDIAN_TEST_DATA, 0, 1, 1.0, 0);
+ bool correctResult = true;
+ fail_unless(result == correctResult,
+ "parse is incorrect: %d but should be %d", result, correctResult);
+}
+END_TEST
+
+START_TEST (test_bitfield_parse_float)
+{
+ float result = bitfield_parse_float(ARRAY_TEST_DATA,
+ sizeof(ARRAY_TEST_DATA), 2, 4, 1001.0, -30000.0);
+ float correctResult = 0xA * 1001.0 - 30000.0;
+ fail_unless(result == correctResult,
+ "parse is incorrect: %f but should be %f", result, correctResult);
+}
+END_TEST
+
+START_TEST (test_bitfield_parse_bool)
+{
+ bool result = bitfield_parse_bool(ARRAY_TEST_DATA, sizeof(ARRAY_TEST_DATA),
+ 0, 1, 1.0, 0);
+ bool correctResult = true;
fail_unless(result == correctResult,
"parse is incorrect: %d but should be %d", result, correctResult);
}
@@ -27,8 +48,10 @@ Suite* canreadSuite(void) {
Suite* s = suite_create("read");
TCase *tc_core = tcase_create("core");
tcase_add_checked_fixture(tc_core, NULL, NULL);
- tcase_add_test(tc_core, test_parse_float);
- tcase_add_test(tc_core, test_parse_bool);
+ tcase_add_test(tc_core, test_eightbyte_parse_float);
+ tcase_add_test(tc_core, test_eightbyte_parse_bool);
+ tcase_add_test(tc_core, test_bitfield_parse_float);
+ tcase_add_test(tc_core, test_bitfield_parse_bool);
suite_add_tcase(s, tc_core);
return s;