From bc1baf25a0844861713829c0e9e69e4a2d447cc6 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Tue, 24 Dec 2013 10:56:35 -0500 Subject: Initial commit, pulled from openxc/vi-firmware. --- CHANGELOG.mkd | 5 ++ LICENSE | 24 ++++++ Makefile | 35 ++++++++ README.mkd | 18 ++++ runtests.sh | 17 ++++ src/bitfield/bitfield.c | 60 +++++++++++++ src/bitfield/bitfield.h | 58 +++++++++++++ src/canutil/read.c | 14 +++ src/canutil/read.h | 13 +++ src/canutil/write.c | 18 ++++ src/canutil/write.h | 13 +++ tests/bitfield_tests.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/tests.bin | Bin 0 -> 24728 bytes 13 files changed, 500 insertions(+) create mode 100644 CHANGELOG.mkd create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.mkd create mode 100644 runtests.sh create mode 100644 src/bitfield/bitfield.c create mode 100644 src/bitfield/bitfield.h create mode 100644 src/canutil/read.c create mode 100644 src/canutil/read.h create mode 100644 src/canutil/write.c create mode 100644 src/canutil/write.h create mode 100644 tests/bitfield_tests.c create mode 100755 tests/tests.bin diff --git a/CHANGELOG.mkd b/CHANGELOG.mkd new file mode 100644 index 00000000..e710764f --- /dev/null +++ b/CHANGELOG.mkd @@ -0,0 +1,5 @@ +# CAN Message Utilities for C + +## v0.1 + +* Initial release diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..330d61f4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2013 Ford Motor Company +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..8385c3ac --- /dev/null +++ b/Makefile @@ -0,0 +1,35 @@ +CC = gcc +INCLUDES = -Isrc +CFLAGS = $(INCLUDES) -c -w -Wall -Werror -g -ggdb +LDFLAGS = +LDLIBS = -lcheck + +TEST_DIR = tests + +# Guard against \r\n line endings only in Cygwin +OSTYPE := $(shell uname) +ifneq ($(OSTYPE),Darwin) + OSTYPE := $(shell uname -o) + ifeq ($(OSTYPE),Cygwin) + TEST_SET_OPTS = igncr + endif +endif + +SRC = $(wildcard src/**/*.c) +OBJS = $(SRC:.c=.o) +TEST_SRC = $(wildcard $(TEST_DIR)/*.c) +TEST_OBJS = $(TEST_SRC:.c=.o) + +all: $(OBJS) + +test: $(TEST_DIR)/tests.bin + @set -o $(TEST_SET_OPTS) >/dev/null 2>&1 + @export SHELLOPTS + @sh runtests.sh $(TEST_DIR) + +$(TEST_DIR)/tests.bin: $(TEST_OBJS) $(OBJS) + @mkdir -p $(dir $@) + $(CC) $(LDFLAGS) $(CC_SYMBOLS) $(INCLUDES) -o $@ $^ $(LDLIBS) + +clean: + rm -rf **/*.o $(TEST_DIR)/*.bin diff --git a/README.mkd b/README.mkd new file mode 100644 index 00000000..0d8efb74 --- /dev/null +++ b/README.mkd @@ -0,0 +1,18 @@ +CAN Message Utilities for C +============ + +## Testing + +The library includes a test suite that uses the `check` C unit test library. + + $ make test + +## Authors + +Chris Peplin cpeplin@ford.com + +## License + +Copyright (c) 2013 Ford Motor Company + +Licensed under the BSD license. diff --git a/runtests.sh b/runtests.sh new file mode 100644 index 00000000..4781636b --- /dev/null +++ b/runtests.sh @@ -0,0 +1,17 @@ +echo "Running unit tests:" + +for i in $1/*.bin +do + if test -f $i + then + if ./$i + then + echo $i PASS + else + echo "ERROR in test $i:" + exit 1 + fi + fi +done + +echo "${txtbld}$(tput setaf 2)All unit tests passed.$(tput sgr0)" diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c new file mode 100644 index 00000000..d383db04 --- /dev/null +++ b/src/bitfield/bitfield.c @@ -0,0 +1,60 @@ +#include + +/** + * Find the ending bit of a bitfield within the final byte. + * + * Returns: a bit position from 0 to 7. + */ +int findEndBit(int startBit, int numBits) { + int endBit = (startBit + numBits) % 8; + return endBit == 0 ? 8 : endBit; +} + +uint64_t bitmask(int numBits) { + return (((uint64_t)0x1) << numBits) - 1; +} + +int startingByte(int startBit) { + return startBit / 8; +} + +int endingByte(int startBit, int numBits) { + return (startBit + numBits - 1) / 8; +} + +uint64_t getBitField(uint64_t data, int startBit, int numBits, bool bigEndian) { + int startByte = startingByte(startBit); + int endByte = endingByte(startBit, numBits); + + if(!bigEndian) { + data = __builtin_bswap64(data); + } + uint8_t* bytes = (uint8_t*)&data; + 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++) { + ret = ret << 8; + ret = ret | bytes[i]; + } + } + + ret >>= 8 - findEndBit(startBit, numBits); + return ret & bitmask(numBits); +} + +/** + * TODO it would be nice to have a warning if you call with this a value that + * won't fit in the number of bits you've specified it should use. + */ +void setBitField(uint64_t* data, uint64_t value, int startBit, int numBits) { + int shiftDistance = 64 - startBit - numBits; + value <<= shiftDistance; + *data &= ~(bitmask(numBits) << shiftDistance); + *data |= value; +} + +uint8_t nthByte(uint64_t source, int byteNum) { + return (source >> (64 - ((byteNum + 1) * 8))) & 0xFF; +} diff --git a/src/bitfield/bitfield.h b/src/bitfield/bitfield.h new file mode 100644 index 00000000..27766733 --- /dev/null +++ b/src/bitfield/bitfield.h @@ -0,0 +1,58 @@ +#ifndef __BITFIELD_H__ +#define __BITFIELD_H__ + +#include +#include + +/* Public: Reads a subset of bits from a byte array. + * + * data - the bytes in question. + * startPos - the starting index of the bit field (beginning from 0). + * numBits - the width of the bit field to extract. + * bigEndian - if the data passed in is little endian, set this to false and it + * will be flipped before grabbing the bit field. + * + * Bit fields are positioned according to big-endian bit layout, but inside the + * bit field, values are represented as little-endian. Therefore, to get the bit + * field, we swap the overall byte order if bigEndian == false and + * use the value we find in the field (assuming the embedded platform is little + * endian). + * + * 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 + * + * If the architecture where is code is running is little-endian, the input data + * will be swapped before grabbing the bit field. + * + * Examples + * + * uint64_t value = getBitField(data, 2, 4); + * + * Returns the value of the requested bit field. + */ +uint64_t getBitField(uint64_t data, int startPos, int numBits, bool bigEndian); + +/* Public: Set the bit field in the given data array to the new value. + * + * data - a byte array with size at least startPos + numBits. + * value - the value to set in the bit field. + * startPos - the starting index of the bit field (beginning from 0). + */ +void setBitField(uint64_t* data, uint64_t value, int startPos, int numBits); + +/* Public: Retreive the nth byte out of 8 bytes in a uint64_t. + * + * source - the source data to retreive the byte from. + * byteNum - the index of the byte, starting at 0 and assuming big-endian order. + * + * Returns the requested byte from the source bytes. + */ +uint8_t nthByte(uint64_t source, int byteNum); + +#endif // __BITFIELD_H__ diff --git a/src/canutil/read.c b/src/canutil/read.c new file mode 100644 index 00000000..6b4e40aa --- /dev/null +++ b/src/canutil/read.c @@ -0,0 +1,14 @@ +#include + +float parseFloat(uint64_t data, uint8_t bitPosition, uint8_t bitSize, + float factor, float offset) { + uint64_t rawValue = getBitField(data, bitPosition, + bitSize, true); + return rawValue * factor + offset; +} + +bool parseBoolean(uint64_t data, uint8_t bitPosition, uint8_t bitSize, + float factor, float offset) { + float value = parseFloat(data, bitPosition, bitSize, factor, offset); + return value == 0.0 ? false : true; +} diff --git a/src/canutil/read.h b/src/canutil/read.h new file mode 100644 index 00000000..815f26b0 --- /dev/null +++ b/src/canutil/read.h @@ -0,0 +1,13 @@ +#ifndef __READ_H__ +#define __READ_H__ + +#include +#include + +float parseFloat(uint64_t data, uint8_t bitPosition, uint8_t bitSize, + float factor, float offset); + +bool parseBoolean(uint64_t data, uint8_t bitPosition, uint8_t bitSize, + float factor, float offset); + +#endif // __READ_H__ diff --git a/src/canutil/write.c b/src/canutil/write.c new file mode 100644 index 00000000..fdcba1f5 --- /dev/null +++ b/src/canutil/write.c @@ -0,0 +1,18 @@ +#include "write.h" + +uint64_t encodeFloat(float value, float offset, float factor, uint8_t bitPosition, + uint8_t bitSize) { + float rawValue = (value - offset) / factor; + if(rawValue > 0) { + // round up to avoid losing precision when we cast to an int + rawValue += 0.5; + } + uint64_t result = 0; + setBitField(&result, rawValue, bitPosition, bitSize); + return result; +} + +uint64_t encodeBoolean(bool value, float offset, float factor, + uint8_t bitPosition, uint8_t bitSize) { + return encodeFloat(value, offset, factor, bitPosition, bitSize); +} diff --git a/src/canutil/write.h b/src/canutil/write.h new file mode 100644 index 00000000..85a5c1a0 --- /dev/null +++ b/src/canutil/write.h @@ -0,0 +1,13 @@ +#ifndef __WRITE_H__ +#define __WRITE_H__ + +#include +#include + +uint64_t encodeFloat(float value, float offset, float factor, uint8_t bitPosition, + uint8_t bitSize); + +uint64_t encodeBoolean(bool value, float offset, float factor, + uint8_t bitPosition, uint8_t bitSize); + +#endif // __WRITE_H__ diff --git a/tests/bitfield_tests.c b/tests/bitfield_tests.c new file mode 100644 index 00000000..d248989b --- /dev/null +++ b/tests/bitfield_tests.c @@ -0,0 +1,225 @@ +#include +#include +#include + +START_TEST (test_large_bitmask) +{ + // yeah, this isn't a public method but I wanted to unit test it to track + // down a bug + extern uint64_t bitmask(int numBits); + uint64_t result = bitmask(32); + fail_if(result != 0xffffffff); +} +END_TEST + +START_TEST (test_one_bit_not_swapped) +{ + uint64_t data = 0x80; + uint64_t result = getBitField(data, 0, 1, false); + fail_if(result == 1); +} +END_TEST + +START_TEST (test_one_bit) +{ + uint64_t data = 0x8000000000000000; + uint64_t result = getBitField(data, 0, 1, false); + fail_unless(result == 0x1, + "First bits in 0x%X was 0x%X instead of 0x1", data, result); +} +END_TEST + +START_TEST (test_32_bit_parse) +{ + uint64_t data = 0x0402574d555a0401; + uint64_t result = getBitField(data, 16, 32, false); + uint64_t expectedValue = 0x574d555a; + fail_unless(result == expectedValue, + "Field retrieved in 0x%X was 0x%X instead of %d", data, + result, expectedValue); +} +END_TEST + +START_TEST (test_16_bit_parse) +{ + uint64_t data = 0xF34DFCFF00000000; + uint64_t result = getBitField(data, 16, 16, false); + uint64_t expectedValue = 0xFCFF; + fail_unless(result == expectedValue, + "Field retrieved in 0x%X was 0x%X instead of %d", data, + result, expectedValue); +} +END_TEST + +START_TEST (test_one_byte) +{ + uint64_t data = 0xFA00000000000000; + uint64_t result = getBitField(data, 0, 4, false); + fail_unless(result == 0xF, + "First 4 bits in 0x%X was 0x%X instead of 0xF", data, result); + result = getBitField(data, 4, 4, false); + fail_unless(result == 0xA, + "First 4 bits in 0x%X was 0x%X instead of 0xA", data, result); + result = getBitField(data, 0, 8, false); + fail_unless(result == 0xFA, + "All bits in 0x%X were 0x%X instead of 0x%X", data, result, data); +} +END_TEST + +START_TEST (test_multi_byte) +{ + uint64_t data = 0x12FA000000000000; + uint64_t result = getBitField(data, 0, 4, false); + fail_unless(result == 0x1, + "First 4 bits in 0x%X was 0x%X instead of 0xF", (data >> 60) & 0xF, + result); + result = getBitField(data, 4, 4, false); + fail_unless(result == 0x2, + "Second 4 bits in 0x%X was %d instead of 0xA", (data >> 56) & 0xF, + result); + result = getBitField(data, 8, 4, false); + fail_unless(result == 0xF, + "First 4 bits in 0x%X was %d instead of 0x1", (data >> 52) & 0xF, + result); + result = getBitField(data, 12, 4, false); + fail_unless(result == 0xA, + "Second 4 bits in 0x%X was %d instead of 0x2", (data >> 48) % 0xF, + result); +} +END_TEST + +START_TEST (test_get_multi_byte) +{ + uint64_t data = 0x12FA000000000000; + uint64_t result = getBitField(data, 0, 9, false); + ck_assert_int_eq(result, 0x25); +} +END_TEST + +START_TEST (test_get_off_byte_boundary) +{ + uint64_t data = 0x000012FA00000000; + uint64_t result = getBitField(data, 12, 8, false); + ck_assert_int_eq(result, 0x01); +} END_TEST + +START_TEST (test_set_field) +{ + uint64_t data = 0; + setBitField(&data, 1, 0, 1); + uint64_t result = getBitField(data, 0, 1, false); + ck_assert_int_eq(result, 0x1); + data = 0; + setBitField(&data, 1, 1, 1); + result = getBitField(data, 1, 1, false); + ck_assert_int_eq(result, 0x1); + + data = 0; + setBitField(&data, 0xf, 3, 4); + result = getBitField(data, 3, 4, false); + ck_assert_int_eq(result, 0xf); +} +END_TEST + +START_TEST (test_set_doesnt_clobber_existing_data) +{ + uint64_t data = 0xFFFC4DF300000000; + setBitField(&data, 0x4fc8, 16, 16); + uint64_t result = getBitField(data, 16, 16, false); + fail_unless(result == 0x4fc8, + "Field retrieved in 0x%X was 0x%X instead of 0x%X", data, result, + 0xc84f); + + data = 0x8000000000000000; + setBitField(&data, 1, 21, 1); + fail_unless(data == 0x8000040000000000LLU, + "Expected combined value 0x8000040000000000 but got 0x%X%X", + data >> 32, data); +} +END_TEST + +START_TEST (test_set_off_byte_boundary) +{ + uint64_t data = 0xFFFC4DF300000000; + setBitField(&data, 0x12, 12, 8); + uint64_t result = getBitField(data, 12, 12, false); + ck_assert_int_eq(result,0x12d); +} +END_TEST + +START_TEST (test_set_odd_number_of_bits) +{ + uint64_t data = 0xFFFC4DF300000000LLU; + setBitField(&data, 0x12, 11, 5); + uint64_t result = getBitField(data, 11, 5, false); + fail_unless(result == 0x12, + "Field set in 0x%X%X%X%X was %d instead of %d", data, result, + 0x12); + + data = 0xFFFC4DF300000000LLU; + setBitField(&data, 0x2, 11, 5); + result = getBitField(data, 11, 5, false); + fail_unless(result == 0x2, + "Field set in 0x%X%X%X%X was %d instead of %d", data, result, + 0x2); +} +END_TEST + +START_TEST(test_nth_byte) +{ + uint64_t data = 0x00000000F34DFCFF; + uint8_t result = nthByte(data, 0); + uint8_t expected = 0x0; + ck_assert_int_eq(result, expected); + + result = nthByte(data, 4); + expected = 0xF3; + ck_assert_int_eq(result, expected); + + result = nthByte(data, 5); + expected = 0x4D; + ck_assert_int_eq(result, expected); + + result = nthByte(data, 6); + expected = 0xFC; + ck_assert_int_eq(result, expected); + + result = nthByte(data, 7); + expected = 0xFF; + ck_assert_int_eq(result, expected); +} +END_TEST + +Suite* bitfieldSuite(void) { + Suite* s = suite_create("bitfield"); + TCase *tc_core = tcase_create("core"); + tcase_add_test(tc_core, test_large_bitmask); + tcase_add_test(tc_core, test_one_bit); + tcase_add_test(tc_core, test_one_bit_not_swapped); + tcase_add_test(tc_core, test_one_byte); + tcase_add_test(tc_core, test_16_bit_parse); + tcase_add_test(tc_core, test_32_bit_parse); + tcase_add_test(tc_core, test_multi_byte); + tcase_add_test(tc_core, test_get_multi_byte); + tcase_add_test(tc_core, test_get_off_byte_boundary); + tcase_add_test(tc_core, test_set_field); + tcase_add_test(tc_core, test_set_doesnt_clobber_existing_data); + tcase_add_test(tc_core, test_set_off_byte_boundary); + tcase_add_test(tc_core, test_set_odd_number_of_bits); + tcase_add_test(tc_core, test_nth_byte); + suite_add_tcase(s, tc_core); + + return s; +} + +int main(void) { + int numberFailed; + Suite* s = bitfieldSuite(); + SRunner *sr = srunner_create(s); + // Don't fork so we can actually use gdb + srunner_set_fork_status(sr, CK_NOFORK); + srunner_run_all(sr, CK_NORMAL); + numberFailed = srunner_ntests_failed(sr); + srunner_free(sr); + return (numberFailed == 0) ? 0 : 1; +} diff --git a/tests/tests.bin b/tests/tests.bin new file mode 100755 index 00000000..5fd0916e Binary files /dev/null and b/tests/tests.bin differ -- cgit 1.2.3-korg From 39a420f13e8000e2dfa53777b9e51594ba03e5d4 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Tue, 24 Dec 2013 12:00:20 -0500 Subject: Add test cases from vi-firmware. --- .gitignore | 4 ++++ Makefile | 5 +++-- src/bitfield/bitfield.h | 8 ++++++++ src/canutil/read.h | 16 ++++++++++++++++ src/canutil/write.c | 12 ++++++------ src/canutil/write.h | 16 ++++++++++++---- tests/read_tests.c | 36 ++++++++++++++++++++++++++++++++++++ tests/tests.bin | Bin 24728 -> 0 bytes tests/write_tests.c | 40 ++++++++++++++++++++++++++++++++++++++++ 9 files changed, 125 insertions(+), 12 deletions(-) create mode 100644 .gitignore create mode 100644 tests/read_tests.c delete mode 100755 tests/tests.bin create mode 100644 tests/write_tests.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..b4225c09 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +.DS_Store +*~ +*.bin diff --git a/Makefile b/Makefile index 8385c3ac..49e22f2c 100644 --- a/Makefile +++ b/Makefile @@ -19,15 +19,16 @@ SRC = $(wildcard src/**/*.c) OBJS = $(SRC:.c=.o) TEST_SRC = $(wildcard $(TEST_DIR)/*.c) TEST_OBJS = $(TEST_SRC:.c=.o) +TESTS=$(patsubst %.c,%.bin,$(TEST_SRC)) all: $(OBJS) -test: $(TEST_DIR)/tests.bin +test: $(TESTS) @set -o $(TEST_SET_OPTS) >/dev/null 2>&1 @export SHELLOPTS @sh runtests.sh $(TEST_DIR) -$(TEST_DIR)/tests.bin: $(TEST_OBJS) $(OBJS) +$(TEST_DIR)/%.bin: $(TEST_DIR)/%.o $(OBJS) @mkdir -p $(dir $@) $(CC) $(LDFLAGS) $(CC_SYMBOLS) $(INCLUDES) -o $@ $^ $(LDLIBS) diff --git a/src/bitfield/bitfield.h b/src/bitfield/bitfield.h index 27766733..7d9f3995 100644 --- a/src/bitfield/bitfield.h +++ b/src/bitfield/bitfield.h @@ -4,6 +4,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /* Public: Reads a subset of bits from a byte array. * * data - the bytes in question. @@ -55,4 +59,8 @@ void setBitField(uint64_t* data, uint64_t value, int startPos, int numBits); */ uint8_t nthByte(uint64_t source, int byteNum); +#ifdef __cplusplus +} +#endif + #endif // __BITFIELD_H__ diff --git a/src/canutil/read.h b/src/canutil/read.h index 815f26b0..6ac4eebe 100644 --- a/src/canutil/read.h +++ b/src/canutil/read.h @@ -4,10 +4,26 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + +/* Public: Parse a CAN signal from a message and apply required transformation. + * + * signal - The details of the signal to decode and forward. + * data - The raw bytes of the CAN message that contains the signal, assumed + * to be in big-endian byte order from CAN. + * + * Returns the final, transformed value of the signal. + */ float parseFloat(uint64_t data, uint8_t bitPosition, uint8_t bitSize, float factor, float offset); bool parseBoolean(uint64_t data, uint8_t bitPosition, uint8_t bitSize, float factor, float offset); +#ifdef __cplusplus +} +#endif + #endif // __READ_H__ diff --git a/src/canutil/write.c b/src/canutil/write.c index fdcba1f5..741778c7 100644 --- a/src/canutil/write.c +++ b/src/canutil/write.c @@ -1,18 +1,18 @@ #include "write.h" -uint64_t encodeFloat(float value, float offset, float factor, uint8_t bitPosition, - uint8_t bitSize) { +uint64_t encodeFloat(float value, uint8_t bitPosition, uint8_t bitSize, + float factor, float offset) { float rawValue = (value - offset) / factor; if(rawValue > 0) { // round up to avoid losing precision when we cast to an int rawValue += 0.5; } uint64_t result = 0; - setBitField(&result, rawValue, bitPosition, bitSize); + setBitField(&result, (uint64_t)rawValue, bitPosition, bitSize); return result; } -uint64_t encodeBoolean(bool value, float offset, float factor, - uint8_t bitPosition, uint8_t bitSize) { - return encodeFloat(value, offset, factor, bitPosition, bitSize); +uint64_t encodeBoolean(bool value, uint8_t bitPosition, uint8_t bitSize, + float factor, float offset) { + return encodeFloat(value, offset, factor, bitPosition, bitSize); } diff --git a/src/canutil/write.h b/src/canutil/write.h index 85a5c1a0..1b086dbe 100644 --- a/src/canutil/write.h +++ b/src/canutil/write.h @@ -4,10 +4,18 @@ #include #include -uint64_t encodeFloat(float value, float offset, float factor, uint8_t bitPosition, - uint8_t bitSize); +#ifdef __cplusplus +extern "C" { +#endif -uint64_t encodeBoolean(bool value, float offset, float factor, - uint8_t bitPosition, uint8_t bitSize); +uint64_t encodeFloat(float value, uint8_t bitPosition, uint8_t bitSize, + float factor, float offset); + +uint64_t encodeBoolean(bool value, uint8_t bitPosition, uint8_t bitSize, + float factor, float offset); + +#ifdef __cplusplus +} +#endif #endif // __WRITE_H__ diff --git a/tests/read_tests.c b/tests/read_tests.c new file mode 100644 index 00000000..f5f0f0c3 --- /dev/null +++ b/tests/read_tests.c @@ -0,0 +1,36 @@ +#include +#include +#include + +const uint64_t BIG_ENDIAN_TEST_DATA = __builtin_bswap64(0xEB00000000000000); + +START_TEST (test_parse_float) +{ + float result = parseFloat(BIG_ENDIAN_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 + +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); + suite_add_tcase(s, tc_core); + + return s; +} + +int main(void) { + int numberFailed; + Suite* s = canreadSuite(); + SRunner *sr = srunner_create(s); + // Don't fork so we can actually use gdb + srunner_set_fork_status(sr, CK_NOFORK); + srunner_run_all(sr, CK_NORMAL); + numberFailed = srunner_ntests_failed(sr); + srunner_free(sr); + return (numberFailed == 0) ? 0 : 1; +} diff --git a/tests/tests.bin b/tests/tests.bin deleted file mode 100755 index 5fd0916e..00000000 Binary files a/tests/tests.bin and /dev/null differ diff --git a/tests/write_tests.c b/tests/write_tests.c new file mode 100644 index 00000000..da5ee89c --- /dev/null +++ b/tests/write_tests.c @@ -0,0 +1,40 @@ +#include +#include +#include + +START_TEST (test_encode_can_signal) +{ + uint64_t value = encodeFloat(0, 1, 3, 1, 0); + ck_assert_int_eq(value, 0); +} +END_TEST + +START_TEST (test_encode_can_signal_rounding_precision) +{ + uint64_t value = encodeFloat(50, 2, 19, 0.001, 0); + ck_assert_int_eq(value, 0x061a800000000000LLU); +} +END_TEST + +Suite* canwriteSuite(void) { + Suite* s = suite_create("write"); + TCase *tc_core = tcase_create("core"); + tcase_add_checked_fixture(tc_core, NULL, NULL); + tcase_add_test(tc_core, test_encode_can_signal); + tcase_add_test(tc_core, test_encode_can_signal_rounding_precision); + suite_add_tcase(s, tc_core); + + return s; +} + +int main(void) { + int numberFailed; + Suite* s = canwriteSuite(); + SRunner *sr = srunner_create(s); + // Don't fork so we can actually use gdb + srunner_set_fork_status(sr, CK_NOFORK); + srunner_run_all(sr, CK_NORMAL); + numberFailed = srunner_ntests_failed(sr); + srunner_free(sr); + return (numberFailed == 0) ? 0 : 1; +} -- cgit 1.2.3-korg From 04a4db7d336ae2cae94ac3234086b22fbf1339f0 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Fri, 27 Dec 2013 11:09:25 -0500 Subject: Add missing include for explicit import. --- src/canutil/write.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/canutil/write.c b/src/canutil/write.c index 741778c7..64b57297 100644 --- a/src/canutil/write.c +++ b/src/canutil/write.c @@ -1,4 +1,5 @@ #include "write.h" +#include uint64_t encodeFloat(float value, uint8_t bitPosition, uint8_t bitSize, float factor, float offset) { -- cgit 1.2.3-korg From 0b00bb6c3c5df70317775efd12b6fff418ff4540 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sat, 28 Dec 2013 15:42:10 -0500 Subject: Draft work making the bitfield functions more generic. --- src/bitfield/bitfield.c | 185 ++++++++++++++++++++++++++++++++++++++++-------- src/bitfield/bitfield.h | 17 ++++- tests/bitfield_tests.c | 46 ++++++++++++ 3 files changed, 219 insertions(+), 29 deletions(-) diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c index d383db04..b3aef4b2 100644 --- a/src/bitfield/bitfield.c +++ b/src/bitfield/bitfield.c @@ -1,47 +1,147 @@ #include +#include +#include +#include + +#define NIBBLE_SIZE (CHAR_BIT / 2) + +#define PREPARE_FIRST_COPY() \ + do { \ + if (source_length >= (CHAR_BIT - destination_offset_modulo)) { \ + *destination &= reverse_mask[destination_offset_modulo]; \ + source_length -= CHAR_BIT - destination_offset_modulo; \ + } else { \ + *destination &= reverse_mask[destination_offset_modulo] \ + | reverse_mask_xor[destination_offset_modulo + source_length + 1];\ + c &= reverse_mask[destination_offset_modulo + source_length ];\ + source_length = 0; \ + } } while (0) /** * Find the ending bit of a bitfield within the final byte. * * Returns: a bit position from 0 to 7. */ -int findEndBit(int startBit, int numBits) { - int endBit = (startBit + numBits) % 8; - return endBit == 0 ? 8 : endBit; -} - -uint64_t bitmask(int numBits) { - return (((uint64_t)0x1) << numBits) - 1; +static uint8_t findEndBit(const uint16_t startBit, const uint16_t numBits) { + int endBit = (startBit + numBits) % CHAR_BIT; + return endBit == 0 ? CHAR_BIT : endBit; } -int startingByte(int startBit) { - return startBit / 8; -} -int endingByte(int startBit, int numBits) { - return (startBit + numBits - 1) / 8; +// TODO can probably remove this +static int byteForBit(const uint16_t startBit) { + return startBit / CHAR_BIT; } -uint64_t getBitField(uint64_t data, int startBit, int numBits, bool bigEndian) { - int startByte = startingByte(startBit); - int endByte = endingByte(startBit, numBits); +/* Thanks to + * http://stackoverflow.com/questions/3534535/whats-a-time-efficient-algorithm-to-copy-unaligned-bit-arrays + */ +static void bitarray_copy(const uint8_t* source_origin, int source_offset, + int source_length, uint8_t* destination_origin, int destination_offset) { + static const uint8_t mask[] = + { 0x55, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; + static const uint8_t reverse_mask[] = + { 0x55, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; + static const uint8_t reverse_mask_xor[] = + { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00 }; - if(!bigEndian) { - data = __builtin_bswap64(data); + if(source_length < 1) { + return; } - uint8_t* bytes = (uint8_t*)&data; - 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++) { - ret = ret << 8; - ret = ret | bytes[i]; + + int source_offset_modulo; + int destination_offset_modulo; + + const uint8_t* source = source_origin + byteForBit(source_offset); + uint8_t* destination = destination_origin + byteForBit(destination_offset); + + source_offset_modulo = source_offset % CHAR_BIT; + destination_offset_modulo = destination_offset % CHAR_BIT; + + if(source_offset_modulo == destination_offset_modulo) { + if(source_offset_modulo) { + uint8_t c; + + c = reverse_mask_xor[destination_offset_modulo] & *source++; + + PREPARE_FIRST_COPY(); + *destination++ |= c; + } + + int byte_len = source_length / CHAR_BIT; + int source_length_modulo = source_length % CHAR_BIT; + + if(byte_len) { + memcpy(destination, source, byte_len); + source += byte_len; + destination += byte_len; + } + if(source_length_modulo) { + *destination &= reverse_mask_xor[source_length_modulo]; + *destination |= reverse_mask[source_length_modulo] & *source; + } + } else { + int bit_diff_ls; + int bit_diff_rs; + uint8_t c; + /* + * Begin: Line things up on destination. + */ + if (source_offset_modulo > destination_offset_modulo) { + bit_diff_ls = source_offset_modulo - destination_offset_modulo; + bit_diff_rs = CHAR_BIT - bit_diff_ls; + + c = *source++ << bit_diff_ls; + c |= *source >> bit_diff_rs; + c &= reverse_mask_xor[destination_offset_modulo]; + } else { + bit_diff_rs = destination_offset_modulo - source_offset_modulo; + bit_diff_ls = CHAR_BIT - bit_diff_rs; + + c = *source >> bit_diff_rs & + reverse_mask_xor[destination_offset_modulo]; + } + PREPARE_FIRST_COPY(); + *destination++ |= c; + + /* + * Middle: copy with only shifting the source. + */ + int byte_len = source_length / CHAR_BIT; + + while(--byte_len >= 0) { + c = *source++ << bit_diff_ls; + c |= *source >> bit_diff_rs; + *destination++ = c; + } + + /* + * End: copy the remaing bits; + */ + int source_length_modulo = source_length % CHAR_BIT; + if(source_length_modulo) { + c = *source++ << bit_diff_ls; + c |= *source >> bit_diff_rs; + c &= reverse_mask[source_length_modulo]; + + *destination &= reverse_mask_xor[source_length_modulo]; + *destination |= c; } } +} + +uint64_t bitmask(const uint8_t numBits) { + return (((uint64_t)0x1) << numBits) - 1; +} - ret >>= 8 - findEndBit(startBit, numBits); - return ret & bitmask(numBits); +uint64_t getBitField(uint64_t data, const uint16_t startBit, + const uint16_t numBits, bool bigEndian) { + uint64_t result; + getBits(startBit, numBits, (const uint8_t*)&data, + CHAR_BIT * sizeof(uint64_t), + bigEndian ? ENDIANNESS_BIG_ENDIAN : ENDIANNESS_LITTLE_ENDIAN, + &result); + return result; } /** @@ -56,5 +156,34 @@ void setBitField(uint64_t* data, uint64_t value, int startBit, int numBits) { } uint8_t nthByte(uint64_t source, int byteNum) { - return (source >> (64 - ((byteNum + 1) * 8))) & 0xFF; + return (source >> (64 - ((byteNum + 1) * CHAR_BIT))) & 0xFF; +} + +uint8_t getNibble(const uint8_t nibble_index, const uint8_t data[], + const uint8_t length, Endianness endianness) { + uint8_t byte_index = nibble_index / 2; + uint8_t result; + if(byte_index < length) { + result = data[byte_index]; + if(nibble_index % 2 == 0) { + result >>= NIBBLE_SIZE; + } + } + result &= bitmask(NIBBLE_SIZE); + return result; +} + +// TODO getBytes, return status and store in output parameter +uint8_t getByte(const uint8_t byte_index, const uint8_t data[], + const uint8_t length, Endianness endianness) { + if(byte_index < length) { + return data[byte_index]; + } + return 0; +} + +void getBits(const uint16_t start_index, const uint16_t field_size, + const uint8_t data[], const uint8_t length, Endianness endianness, + uint8_t* result) { + bitarray_copy(data, start_index, field_size, result, 0); } diff --git a/src/bitfield/bitfield.h b/src/bitfield/bitfield.h index 7d9f3995..ce68b949 100644 --- a/src/bitfield/bitfield.h +++ b/src/bitfield/bitfield.h @@ -8,6 +8,21 @@ extern "C" { #endif +typedef enum { + ENDIANNESS_LITTLE_ENDIAN, + ENDIANNESS_BIG_ENDIAN +} Endianness; + +uint8_t getNibble(const uint8_t nibble_index, const uint8_t data[], + const uint8_t length, Endianness endianness); + +uint8_t getByte(const uint8_t byte_index, const uint8_t data[], + const uint8_t length, Endianness endianness); + +void getBits(const uint16_t start_index, const uint16_t field_size, + const uint8_t data[], const uint8_t length, Endianness endianness, + uint8_t* result); + /* Public: Reads a subset of bits from a byte array. * * data - the bytes in question. @@ -40,7 +55,7 @@ extern "C" { * * Returns the value of the requested bit field. */ -uint64_t getBitField(uint64_t data, int startPos, int numBits, bool bigEndian); +uint64_t getBitField(uint64_t data, const uint16_t startPos, const uint16_t numBits, bool bigEndian); /* Public: Set the bit field in the given data array to the new value. * diff --git a/tests/bitfield_tests.c b/tests/bitfield_tests.c index d248989b..f321e5f2 100644 --- a/tests/bitfield_tests.c +++ b/tests/bitfield_tests.c @@ -190,6 +190,48 @@ START_TEST(test_nth_byte) } END_TEST +START_TEST (test_get_byte) +{ + uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; + uint8_t result = getByte(0, data, sizeof(data), ENDIANNESS_BIG_ENDIAN); + ck_assert_int_eq(result, 0x12); + result = getByte(3, data, sizeof(data), ENDIANNESS_BIG_ENDIAN); + ck_assert_int_eq(result, 0x78); +} +END_TEST + +START_TEST (test_get_nibble) +{ + uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; + uint8_t result = getNibble(0, data, sizeof(data), ENDIANNESS_BIG_ENDIAN); + ck_assert_int_eq(result, 0x1); + result = getNibble(1, data, sizeof(data), ENDIANNESS_BIG_ENDIAN); + ck_assert_int_eq(result, 0x2); + result = getNibble(2, data, sizeof(data), ENDIANNESS_BIG_ENDIAN); + ck_assert_int_eq(result, 0x3); +} +END_TEST + +START_TEST (test_get_bits) +{ + uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; + uint8_t result[4]; + getBits(0, 16, data, 36, ENDIANNESS_BIG_ENDIAN, result); + ck_assert_int_eq(result[0], 0x12); + ck_assert_int_eq(result[1], 0x34); +} +END_TEST + +START_TEST (test_get_uneven_bits) +{ + uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; + uint8_t result[4] = {0}; + getBits(4, 12, data, 36, ENDIANNESS_BIG_ENDIAN, result); + ck_assert_int_eq(result[0], 0x2); + ck_assert_int_eq(result[1], 0x34); +} +END_TEST + Suite* bitfieldSuite(void) { Suite* s = suite_create("bitfield"); TCase *tc_core = tcase_create("core"); @@ -207,6 +249,10 @@ Suite* bitfieldSuite(void) { tcase_add_test(tc_core, test_set_off_byte_boundary); tcase_add_test(tc_core, test_set_odd_number_of_bits); tcase_add_test(tc_core, test_nth_byte); + tcase_add_test(tc_core, test_get_byte); + tcase_add_test(tc_core, test_get_nibble); + tcase_add_test(tc_core, test_get_bits); + tcase_add_test(tc_core, test_get_uneven_bits); suite_add_tcase(s, tc_core); return s; -- cgit 1.2.3-korg From 20bb0f507694482d7e0c6a381e3025544aa9cb5a Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sat, 28 Dec 2013 23:43:53 -0500 Subject: Hack together a legacy getBitField backed by new bit copying function. --- Makefile | 2 +- src/bitfield/bitfield.c | 90 +++++++++++++++++++++++++++---------------------- tests/bitfield_tests.c | 28 +++++++-------- 3 files changed, 65 insertions(+), 55 deletions(-) diff --git a/Makefile b/Makefile index 49e22f2c..d841c208 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc INCLUDES = -Isrc -CFLAGS = $(INCLUDES) -c -w -Wall -Werror -g -ggdb +CFLAGS = $(INCLUDES) -c -w -Wall -Werror -g -ggdb -std=gnu99 LDFLAGS = LDLIBS = -lcheck diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c index b3aef4b2..834e443e 100644 --- a/src/bitfield/bitfield.c +++ b/src/bitfield/bitfield.c @@ -23,7 +23,7 @@ * Returns: a bit position from 0 to 7. */ static uint8_t findEndBit(const uint16_t startBit, const uint16_t numBits) { - int endBit = (startBit + numBits) % CHAR_BIT; + int endBit = numBits % CHAR_BIT; return endBit == 0 ? CHAR_BIT : endBit; } @@ -38,8 +38,6 @@ static int byteForBit(const uint16_t startBit) { */ static void bitarray_copy(const uint8_t* source_origin, int source_offset, int source_length, uint8_t* destination_origin, int destination_offset) { - static const uint8_t mask[] = - { 0x55, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; static const uint8_t reverse_mask[] = { 0x55, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; static const uint8_t reverse_mask_xor[] = @@ -49,21 +47,14 @@ static void bitarray_copy(const uint8_t* source_origin, int source_offset, return; } - int source_offset_modulo; - int destination_offset_modulo; - const uint8_t* source = source_origin + byteForBit(source_offset); uint8_t* destination = destination_origin + byteForBit(destination_offset); - - source_offset_modulo = source_offset % CHAR_BIT; - destination_offset_modulo = destination_offset % CHAR_BIT; + int source_offset_modulo = source_offset % CHAR_BIT; + int destination_offset_modulo = destination_offset % CHAR_BIT; if(source_offset_modulo == destination_offset_modulo) { - if(source_offset_modulo) { - uint8_t c; - - c = reverse_mask_xor[destination_offset_modulo] & *source++; - + if(source_offset_modulo > 0) { + uint8_t c = reverse_mask_xor[destination_offset_modulo] & *source++; PREPARE_FIRST_COPY(); *destination++ |= c; } @@ -71,35 +62,36 @@ static void bitarray_copy(const uint8_t* source_origin, int source_offset, int byte_len = source_length / CHAR_BIT; int source_length_modulo = source_length % CHAR_BIT; - if(byte_len) { + if(byte_len > 0) { memcpy(destination, source, byte_len); source += byte_len; destination += byte_len; } - if(source_length_modulo) { - *destination &= reverse_mask_xor[source_length_modulo]; - *destination |= reverse_mask[source_length_modulo] & *source; + + if(source_length_modulo > 0) { + *destination &= reverse_mask_xor[source_length_modulo]; + *destination |= reverse_mask[source_length_modulo] & *source; } } else { - int bit_diff_ls; - int bit_diff_rs; + int bit_diff_left_shift; + int bit_diff_right_shift; uint8_t c; /* * Begin: Line things up on destination. */ - if (source_offset_modulo > destination_offset_modulo) { - bit_diff_ls = source_offset_modulo - destination_offset_modulo; - bit_diff_rs = CHAR_BIT - bit_diff_ls; + if(source_offset_modulo > destination_offset_modulo) { + bit_diff_left_shift = source_offset_modulo - destination_offset_modulo; + bit_diff_right_shift = CHAR_BIT - bit_diff_left_shift; - c = *source++ << bit_diff_ls; - c |= *source >> bit_diff_rs; - c &= reverse_mask_xor[destination_offset_modulo]; + c = *source++ << bit_diff_left_shift; + c |= *source >> bit_diff_right_shift; + c &= reverse_mask_xor[destination_offset_modulo]; } else { - bit_diff_rs = destination_offset_modulo - source_offset_modulo; - bit_diff_ls = CHAR_BIT - bit_diff_rs; + bit_diff_right_shift = destination_offset_modulo - source_offset_modulo; + bit_diff_left_shift = CHAR_BIT - bit_diff_right_shift; - c = *source >> bit_diff_rs & - reverse_mask_xor[destination_offset_modulo]; + c = *source >> bit_diff_right_shift & + reverse_mask_xor[destination_offset_modulo]; } PREPARE_FIRST_COPY(); *destination++ |= c; @@ -108,10 +100,9 @@ static void bitarray_copy(const uint8_t* source_origin, int source_offset, * Middle: copy with only shifting the source. */ int byte_len = source_length / CHAR_BIT; - while(--byte_len >= 0) { - c = *source++ << bit_diff_ls; - c |= *source >> bit_diff_rs; + c = *source++ << bit_diff_left_shift; + c |= *source >> bit_diff_right_shift; *destination++ = c; } @@ -119,9 +110,9 @@ static void bitarray_copy(const uint8_t* source_origin, int source_offset, * End: copy the remaing bits; */ int source_length_modulo = source_length % CHAR_BIT; - if(source_length_modulo) { - c = *source++ << bit_diff_ls; - c |= *source >> bit_diff_rs; + if(source_length_modulo > 0) { + c = *source++ << bit_diff_left_shift; + c |= *source >> bit_diff_right_shift; c &= reverse_mask[source_length_modulo]; *destination &= reverse_mask_xor[source_length_modulo]; @@ -136,12 +127,30 @@ uint64_t bitmask(const uint8_t numBits) { uint64_t getBitField(uint64_t data, const uint16_t startBit, const uint16_t numBits, bool bigEndian) { - uint64_t result; + uint8_t result[8] = {0}; + if(!bigEndian) { + data = __builtin_bswap64(data); + } getBits(startBit, numBits, (const uint8_t*)&data, CHAR_BIT * sizeof(uint64_t), bigEndian ? ENDIANNESS_BIG_ENDIAN : ENDIANNESS_LITTLE_ENDIAN, - &result); - return result; + result); + // TODO the result has already been shifted to be aligned right, so if we + // try and bswap here it's going to be screwed up unless it was byte aligned + uint64_t int_result = 0; + // TODO should the API return the byte length of data in the result array? + // i think yes. + uint8_t byte_count = numBits / CHAR_BIT; + if(numBits % CHAR_BIT != 0) { + ++byte_count; + } + + // TODO wow, can't believe this works, but something is clearly wrong with + // the API! + for(int i = 0; i < byte_count; i++) { + int_result |= result[byte_count - i - 1] << (CHAR_BIT * i); + } + return int_result; } /** @@ -185,5 +194,6 @@ uint8_t getByte(const uint8_t byte_index, const uint8_t data[], void getBits(const uint16_t start_index, const uint16_t field_size, const uint8_t data[], const uint8_t length, Endianness endianness, uint8_t* result) { - bitarray_copy(data, start_index, field_size, result, 0); + bitarray_copy(data, start_index, field_size, result, + CHAR_BIT - findEndBit(start_index, field_size)); } diff --git a/tests/bitfield_tests.c b/tests/bitfield_tests.c index f321e5f2..056f8c13 100644 --- a/tests/bitfield_tests.c +++ b/tests/bitfield_tests.c @@ -25,7 +25,7 @@ START_TEST (test_one_bit) uint64_t data = 0x8000000000000000; uint64_t result = getBitField(data, 0, 1, false); fail_unless(result == 0x1, - "First bits in 0x%X was 0x%X instead of 0x1", data, result); + "First bit in 0x%llx was 0x%llx instead of 0x1", data, result); } END_TEST @@ -35,7 +35,7 @@ START_TEST (test_32_bit_parse) uint64_t result = getBitField(data, 16, 32, false); uint64_t expectedValue = 0x574d555a; fail_unless(result == expectedValue, - "Field retrieved in 0x%X was 0x%X instead of %d", data, + "Field retrieved in 0x%llx was 0x%llx instead of 0x%llx", data, result, expectedValue); } END_TEST @@ -46,7 +46,7 @@ START_TEST (test_16_bit_parse) uint64_t result = getBitField(data, 16, 16, false); uint64_t expectedValue = 0xFCFF; fail_unless(result == expectedValue, - "Field retrieved in 0x%X was 0x%X instead of %d", data, + "Field retrieved in 0x%llx was 0x%llx instead of 0x%llx", data, result, expectedValue); } END_TEST @@ -56,13 +56,13 @@ START_TEST (test_one_byte) uint64_t data = 0xFA00000000000000; uint64_t result = getBitField(data, 0, 4, false); fail_unless(result == 0xF, - "First 4 bits in 0x%X was 0x%X instead of 0xF", data, result); + "First 4 bits in 0x%llx was 0x%llx instead of 0xF", data, result); result = getBitField(data, 4, 4, false); fail_unless(result == 0xA, - "First 4 bits in 0x%X was 0x%X instead of 0xA", data, result); + "First 4 bits in 0x%llx was 0x%llx instead of 0xA", data, result); result = getBitField(data, 0, 8, false); fail_unless(result == 0xFA, - "All bits in 0x%X were 0x%X instead of 0x%X", data, result, data); + "All bits in 0x%llx were 0x%llx instead of 0x%llx", data, result, data); } END_TEST @@ -71,19 +71,19 @@ START_TEST (test_multi_byte) uint64_t data = 0x12FA000000000000; uint64_t result = getBitField(data, 0, 4, false); fail_unless(result == 0x1, - "First 4 bits in 0x%X was 0x%X instead of 0xF", (data >> 60) & 0xF, + "First 4 bits in 0x%llx was 0x%llx instead of 0xF", (data >> 60) & 0xF, result); result = getBitField(data, 4, 4, false); fail_unless(result == 0x2, - "Second 4 bits in 0x%X was %d instead of 0xA", (data >> 56) & 0xF, + "Second 4 bits in 0x%llx was 0x%llx instead of 0xA", (data >> 56) & 0xF, result); result = getBitField(data, 8, 4, false); fail_unless(result == 0xF, - "First 4 bits in 0x%X was %d instead of 0x1", (data >> 52) & 0xF, + "First 4 bits in 0x%llx was 0x%llx instead of 0x1", (data >> 52) & 0xF, result); result = getBitField(data, 12, 4, false); fail_unless(result == 0xA, - "Second 4 bits in 0x%X was %d instead of 0x2", (data >> 48) % 0xF, + "Second 4 bits in 0x%llx was 0x%llx instead of 0x2", (data >> 48) % 0xF, result); } END_TEST @@ -127,13 +127,13 @@ START_TEST (test_set_doesnt_clobber_existing_data) setBitField(&data, 0x4fc8, 16, 16); uint64_t result = getBitField(data, 16, 16, false); fail_unless(result == 0x4fc8, - "Field retrieved in 0x%X was 0x%X instead of 0x%X", data, result, + "Field retrieved in 0x%llx was 0x%llx instead of 0x%x", data, result, 0xc84f); data = 0x8000000000000000; setBitField(&data, 1, 21, 1); fail_unless(data == 0x8000040000000000LLU, - "Expected combined value 0x8000040000000000 but got 0x%X%X", + "Expected combined value 0x8000040000000000 but got 0x%llx%llx", data >> 32, data); } END_TEST @@ -153,14 +153,14 @@ START_TEST (test_set_odd_number_of_bits) setBitField(&data, 0x12, 11, 5); uint64_t result = getBitField(data, 11, 5, false); fail_unless(result == 0x12, - "Field set in 0x%X%X%X%X was %d instead of %d", data, result, + "Field set in 0x%llx%llx%llx%llx was 0x%llx instead of 0x%llx", data, result, 0x12); data = 0xFFFC4DF300000000LLU; setBitField(&data, 0x2, 11, 5); result = getBitField(data, 11, 5, false); fail_unless(result == 0x2, - "Field set in 0x%X%X%X%X was %d instead of %d", data, result, + "Field set in 0x%llx%llx%llx%llx was 0x%llx instead of 0x%llx", data, result, 0x2); } END_TEST -- cgit 1.2.3-korg From 6830d35b449141305f137f78f09c2b879bfb9b33 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sun, 29 Dec 2013 11:34:10 -0500 Subject: Clean up bitfield API a bit. --- src/bitfield/bitarray.c | 129 +++++++++++++++++++++++++++++++++++++ src/bitfield/bitfield.c | 167 +++++++----------------------------------------- src/bitfield/bitfield.h | 65 +++++++++++++++---- tests/bitfield_tests.c | 25 +++++--- 4 files changed, 221 insertions(+), 165 deletions(-) create mode 100644 src/bitfield/bitarray.c diff --git a/src/bitfield/bitarray.c b/src/bitfield/bitarray.c new file mode 100644 index 00000000..8fbc941d --- /dev/null +++ b/src/bitfield/bitarray.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include + +#define PREPARE_FIRST_COPY() \ + do { \ + if (bit_count >= (CHAR_BIT - destination_offset_modulo)) { \ + *destination &= reverse_mask[destination_offset_modulo]; \ + bit_count -= CHAR_BIT - destination_offset_modulo; \ + } else { \ + *destination &= reverse_mask[destination_offset_modulo] \ + | reverse_mask_xor[destination_offset_modulo + bit_count + 1];\ + c &= reverse_mask[destination_offset_modulo + bit_count ];\ + bit_count = 0; \ + } } while (0) + +static const uint8_t reverse_mask[] = + { 0x55, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; +static const uint8_t reverse_mask_xor[] = + { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00 }; + +bool copyBits(const uint8_t* source_origin, const uint16_t source_length, + const uint16_t source_offset, uint16_t bit_count, + uint8_t* destination_origin, const uint16_t destination_length, + const uint16_t destination_offset) { + if(bit_count < 1) { + return false; + } + + if(source_offset + bit_count > source_length * CHAR_BIT || + destination_offset + bit_count > destination_length * CHAR_BIT ) { + return false; + } + + const uint8_t* source = source_origin + (source_offset / CHAR_BIT); + uint8_t* destination = destination_origin + (destination_offset / CHAR_BIT); + int source_offset_modulo = source_offset % CHAR_BIT; + int destination_offset_modulo = destination_offset % CHAR_BIT; + + if(source_offset_modulo == destination_offset_modulo) { + if(source_offset_modulo > 0) { + uint8_t c = reverse_mask_xor[destination_offset_modulo] & *source++; + PREPARE_FIRST_COPY(); + *destination++ |= c; + } + + int byte_len = bit_count / CHAR_BIT; + int bit_count_modulo = bit_count % CHAR_BIT; + + if(byte_len > 0) { + memcpy(destination, source, byte_len); + source += byte_len; + destination += byte_len; + } + + if(bit_count_modulo > 0) { + *destination &= reverse_mask_xor[bit_count_modulo]; + *destination |= reverse_mask[bit_count_modulo] & *source; + } + } else { + int bit_diff_left_shift; + int bit_diff_right_shift; + uint8_t c; + /* + * Begin: Line things up on destination. + */ + if(source_offset_modulo > destination_offset_modulo) { + bit_diff_left_shift = source_offset_modulo - destination_offset_modulo; + bit_diff_right_shift = CHAR_BIT - bit_diff_left_shift; + + c = *source++ << bit_diff_left_shift; + c |= *source >> bit_diff_right_shift; + c &= reverse_mask_xor[destination_offset_modulo]; + } else { + bit_diff_right_shift = destination_offset_modulo - source_offset_modulo; + bit_diff_left_shift = CHAR_BIT - bit_diff_right_shift; + + c = *source >> bit_diff_right_shift & + reverse_mask_xor[destination_offset_modulo]; + } + PREPARE_FIRST_COPY(); + *destination++ |= c; + + /* + * Middle: copy with only shifting the source. + */ + int byte_len = bit_count / CHAR_BIT; + while(--byte_len >= 0) { + c = *source++ << bit_diff_left_shift; + c |= *source >> bit_diff_right_shift; + *destination++ = c; + } + + /* + * End: copy the remaing bits; + */ + int bit_count_modulo = bit_count % CHAR_BIT; + if(bit_count_modulo > 0) { + c = *source++ << bit_diff_left_shift; + c |= *source >> bit_diff_right_shift; + c &= reverse_mask[bit_count_modulo]; + + *destination &= reverse_mask_xor[bit_count_modulo]; + *destination |= c; + } + } + return true; +} + +/** + * Find the ending bit of a bitfield within the final byte. + * + * Returns: a bit position from 0 to 7. + */ +static uint8_t findEndBit(const uint16_t startBit, const uint16_t numBits) { + int endBit = numBits % CHAR_BIT; + return endBit == 0 ? CHAR_BIT : endBit; +} + +bool copyBitsRightAligned(const uint8_t source[], const uint16_t source_length, + const uint16_t offset, const uint16_t bit_count, + uint8_t* destination, const uint16_t destination_length) { + return copyBits(source, source_length, offset, bit_count, destination, + destination_length, + // provide a proper destination offset so the result is right + // aligned + CHAR_BIT - findEndBit(offset, bit_count)); +} diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c index 834e443e..b0396413 100644 --- a/src/bitfield/bitfield.c +++ b/src/bitfield/bitfield.c @@ -5,124 +5,16 @@ #define NIBBLE_SIZE (CHAR_BIT / 2) -#define PREPARE_FIRST_COPY() \ - do { \ - if (source_length >= (CHAR_BIT - destination_offset_modulo)) { \ - *destination &= reverse_mask[destination_offset_modulo]; \ - source_length -= CHAR_BIT - destination_offset_modulo; \ - } else { \ - *destination &= reverse_mask[destination_offset_modulo] \ - | reverse_mask_xor[destination_offset_modulo + source_length + 1];\ - c &= reverse_mask[destination_offset_modulo + source_length ];\ - source_length = 0; \ - } } while (0) - -/** - * Find the ending bit of a bitfield within the final byte. - * - * Returns: a bit position from 0 to 7. - */ -static uint8_t findEndBit(const uint16_t startBit, const uint16_t numBits) { - int endBit = numBits % CHAR_BIT; - return endBit == 0 ? CHAR_BIT : endBit; -} - - -// TODO can probably remove this -static int byteForBit(const uint16_t startBit) { - return startBit / CHAR_BIT; +uint64_t bitmask(const uint8_t numBits) { + return (((uint64_t)0x1) << numBits) - 1; } -/* Thanks to - * http://stackoverflow.com/questions/3534535/whats-a-time-efficient-algorithm-to-copy-unaligned-bit-arrays - */ -static void bitarray_copy(const uint8_t* source_origin, int source_offset, - int source_length, uint8_t* destination_origin, int destination_offset) { - static const uint8_t reverse_mask[] = - { 0x55, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; - static const uint8_t reverse_mask_xor[] = - { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00 }; - - if(source_length < 1) { - return; - } - - const uint8_t* source = source_origin + byteForBit(source_offset); - uint8_t* destination = destination_origin + byteForBit(destination_offset); - int source_offset_modulo = source_offset % CHAR_BIT; - int destination_offset_modulo = destination_offset % CHAR_BIT; - - if(source_offset_modulo == destination_offset_modulo) { - if(source_offset_modulo > 0) { - uint8_t c = reverse_mask_xor[destination_offset_modulo] & *source++; - PREPARE_FIRST_COPY(); - *destination++ |= c; - } - - int byte_len = source_length / CHAR_BIT; - int source_length_modulo = source_length % CHAR_BIT; - - if(byte_len > 0) { - memcpy(destination, source, byte_len); - source += byte_len; - destination += byte_len; - } - - if(source_length_modulo > 0) { - *destination &= reverse_mask_xor[source_length_modulo]; - *destination |= reverse_mask[source_length_modulo] & *source; - } - } else { - int bit_diff_left_shift; - int bit_diff_right_shift; - uint8_t c; - /* - * Begin: Line things up on destination. - */ - if(source_offset_modulo > destination_offset_modulo) { - bit_diff_left_shift = source_offset_modulo - destination_offset_modulo; - bit_diff_right_shift = CHAR_BIT - bit_diff_left_shift; - - c = *source++ << bit_diff_left_shift; - c |= *source >> bit_diff_right_shift; - c &= reverse_mask_xor[destination_offset_modulo]; - } else { - bit_diff_right_shift = destination_offset_modulo - source_offset_modulo; - bit_diff_left_shift = CHAR_BIT - bit_diff_right_shift; - - c = *source >> bit_diff_right_shift & - reverse_mask_xor[destination_offset_modulo]; - } - PREPARE_FIRST_COPY(); - *destination++ |= c; - - /* - * Middle: copy with only shifting the source. - */ - int byte_len = source_length / CHAR_BIT; - while(--byte_len >= 0) { - c = *source++ << bit_diff_left_shift; - c |= *source >> bit_diff_right_shift; - *destination++ = c; - } - - /* - * End: copy the remaing bits; - */ - int source_length_modulo = source_length % CHAR_BIT; - if(source_length_modulo > 0) { - c = *source++ << bit_diff_left_shift; - c |= *source >> bit_diff_right_shift; - c &= reverse_mask[source_length_modulo]; - - *destination &= reverse_mask_xor[source_length_modulo]; - *destination |= c; - } +static uint16_t bitsToBytes(uint32_t bits) { + uint8_t byte_count = bits / CHAR_BIT; + if(bits % CHAR_BIT != 0) { + ++byte_count; } -} - -uint64_t bitmask(const uint8_t numBits) { - return (((uint64_t)0x1) << numBits) - 1; + return byte_count; } uint64_t getBitField(uint64_t data, const uint16_t startBit, @@ -131,24 +23,18 @@ uint64_t getBitField(uint64_t data, const uint16_t startBit, if(!bigEndian) { data = __builtin_bswap64(data); } - getBits(startBit, numBits, (const uint8_t*)&data, - CHAR_BIT * sizeof(uint64_t), - bigEndian ? ENDIANNESS_BIG_ENDIAN : ENDIANNESS_LITTLE_ENDIAN, - result); - // TODO the result has already been shifted to be aligned right, so if we - // try and bswap here it's going to be screwed up unless it was byte aligned + copyBitsRightAligned((const uint8_t*)&data, sizeof(data), startBit, numBits, + result, sizeof(result)); uint64_t int_result = 0; - // TODO should the API return the byte length of data in the result array? - // i think yes. - uint8_t byte_count = numBits / CHAR_BIT; - if(numBits % CHAR_BIT != 0) { - ++byte_count; - } - // TODO wow, can't believe this works, but something is clearly wrong with - // the API! - for(int i = 0; i < byte_count; i++) { - int_result |= result[byte_count - i - 1] << (CHAR_BIT * i); + if(!bigEndian) { + // we need to swap the byte order of the array to get it into a + // uint64_t, but it's been right aligned so we have to be more careful + for(int i = 0; i < bitsToBytes(numBits); i++) { + int_result |= result[bitsToBytes(numBits) - i - 1] << (CHAR_BIT * i); + } + } else { + int_result = *(uint64_t*)result; } return int_result; } @@ -157,19 +43,20 @@ uint64_t getBitField(uint64_t data, const uint16_t startBit, * TODO it would be nice to have a warning if you call with this a value that * won't fit in the number of bits you've specified it should use. */ -void setBitField(uint64_t* data, uint64_t value, int startBit, int numBits) { - int shiftDistance = 64 - startBit - numBits; +void setBitField(uint64_t* data, uint64_t value, const uint16_t startPos, + const uint16_t numBits) { + int shiftDistance = 64 - startPos - numBits; value <<= shiftDistance; *data &= ~(bitmask(numBits) << shiftDistance); *data |= value; } -uint8_t nthByte(uint64_t source, int byteNum) { +uint8_t nthByte(const uint64_t source, const uint16_t byteNum) { return (source >> (64 - ((byteNum + 1) * CHAR_BIT))) & 0xFF; } uint8_t getNibble(const uint8_t nibble_index, const uint8_t data[], - const uint8_t length, Endianness endianness) { + const uint8_t length) { uint8_t byte_index = nibble_index / 2; uint8_t result; if(byte_index < length) { @@ -182,18 +69,10 @@ uint8_t getNibble(const uint8_t nibble_index, const uint8_t data[], return result; } -// TODO getBytes, return status and store in output parameter uint8_t getByte(const uint8_t byte_index, const uint8_t data[], - const uint8_t length, Endianness endianness) { + const uint8_t length) { if(byte_index < length) { return data[byte_index]; } return 0; } - -void getBits(const uint16_t start_index, const uint16_t field_size, - const uint8_t data[], const uint8_t length, Endianness endianness, - uint8_t* result) { - bitarray_copy(data, start_index, field_size, result, - CHAR_BIT - findEndBit(start_index, field_size)); -} diff --git a/src/bitfield/bitfield.h b/src/bitfield/bitfield.h index ce68b949..bf5c9b7d 100644 --- a/src/bitfield/bitfield.h +++ b/src/bitfield/bitfield.h @@ -8,20 +8,57 @@ extern "C" { #endif -typedef enum { - ENDIANNESS_LITTLE_ENDIAN, - ENDIANNESS_BIG_ENDIAN -} Endianness; - uint8_t getNibble(const uint8_t nibble_index, const uint8_t data[], - const uint8_t length, Endianness endianness); + const uint8_t length); uint8_t getByte(const uint8_t byte_index, const uint8_t data[], - const uint8_t length, Endianness endianness); + const uint8_t length); + +/* Public: Copy a range of bits from one bit array to another. + * + * The range does not need to be byte aligned, and the source and destination do + * not have to be the same size (as long as the desitnation has enough room to + * fit the range). + * + * A bit array with regards to this function always has the leftmost bit in byte + * 0, i.e. bit index is the leftmost bit of byte 0. Endianness does not matter. + * + * Thanks to + * http://stackoverflow.com/questions/3534535/whats-a-time-efficient-algorithm-to-copy-unaligned-bit-arrays + * for the implementation of the algorithm. + * + * source_origin - the source array. + * source_length - the total length of the source array in bytes, + * for range checking. + * source_offset - an offset in bits to start the copy from the source array. + * Specify 0 to start from source_origin. + * bit_count - the number of bits to copy. + * destination_origin - the destination array. + * desitnation_length - the total length of the destination array in bytes, + * for range checking. + * destination_offset - an offset in bits to start placing the copied range into + * the destination array. Specify 0 to start from the beginning of the + * destination. If you are copying a range not aligned on a byte, you + * probably want to set this to a positive offset to right the resulting + * bits in the destination. + * + * Returns true if the copy was successful and false if the range exceeded the + * size of the source or destination, or if the range size negative or 0. + */ +bool copyBits(const uint8_t* source_origin, const uint16_t source_length, + const uint16_t source_offset, uint16_t bit_count, + uint8_t* destination_origin, const uint16_t destination_length, + const uint16_t destination_offset); + +bool copyBitsRightAligned(const uint8_t source[], const uint16_t source_length, + const uint16_t offset, const uint16_t bit_count, + uint8_t* destination, const uint16_t destination_length); -void getBits(const uint16_t start_index, const uint16_t field_size, - const uint8_t data[], const uint8_t length, Endianness endianness, - uint8_t* result); +// TODO using uint64_t everywhere for CAN message payload is kind of cute, but +// in actuality a CAN message may have a smaller payload, and it makes all of +// these functions not applicable to other data sizes. It's also fairly +// inefficient on 32-bit platforms. how much work is it to switch vi-firmware +// to using uint8_t*? /* Public: Reads a subset of bits from a byte array. * @@ -55,7 +92,8 @@ void getBits(const uint16_t start_index, const uint16_t field_size, * * Returns the value of the requested bit field. */ -uint64_t getBitField(uint64_t data, const uint16_t startPos, const uint16_t numBits, bool bigEndian); +uint64_t getBitField(uint64_t data, const uint16_t startPos, + const uint16_t numBits, bool bigEndian); /* Public: Set the bit field in the given data array to the new value. * @@ -63,7 +101,8 @@ uint64_t getBitField(uint64_t data, const uint16_t startPos, const uint16_t numB * value - the value to set in the bit field. * startPos - the starting index of the bit field (beginning from 0). */ -void setBitField(uint64_t* data, uint64_t value, int startPos, int numBits); +void setBitField(uint64_t* data, uint64_t value, const uint16_t startPos, + const uint16_t numBits); /* Public: Retreive the nth byte out of 8 bytes in a uint64_t. * @@ -72,7 +111,7 @@ void setBitField(uint64_t* data, uint64_t value, int startPos, int numBits); * * Returns the requested byte from the source bytes. */ -uint8_t nthByte(uint64_t source, int byteNum); +uint8_t nthByte(const uint64_t source, const uint16_t byteNum); #ifdef __cplusplus } diff --git a/tests/bitfield_tests.c b/tests/bitfield_tests.c index 056f8c13..e2304ea0 100644 --- a/tests/bitfield_tests.c +++ b/tests/bitfield_tests.c @@ -193,9 +193,9 @@ END_TEST START_TEST (test_get_byte) { uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; - uint8_t result = getByte(0, data, sizeof(data), ENDIANNESS_BIG_ENDIAN); + uint8_t result = getByte(0, data, sizeof(data)); ck_assert_int_eq(result, 0x12); - result = getByte(3, data, sizeof(data), ENDIANNESS_BIG_ENDIAN); + result = getByte(3, data, sizeof(data)); ck_assert_int_eq(result, 0x78); } END_TEST @@ -203,20 +203,28 @@ END_TEST START_TEST (test_get_nibble) { uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; - uint8_t result = getNibble(0, data, sizeof(data), ENDIANNESS_BIG_ENDIAN); + uint8_t result = getNibble(0, data, sizeof(data)); ck_assert_int_eq(result, 0x1); - result = getNibble(1, data, sizeof(data), ENDIANNESS_BIG_ENDIAN); + result = getNibble(1, data, sizeof(data)); ck_assert_int_eq(result, 0x2); - result = getNibble(2, data, sizeof(data), ENDIANNESS_BIG_ENDIAN); + result = getNibble(2, data, sizeof(data)); ck_assert_int_eq(result, 0x3); } END_TEST -START_TEST (test_get_bits) +START_TEST (test_get_bits_out_of_range) { uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; uint8_t result[4]; - getBits(0, 16, data, 36, ENDIANNESS_BIG_ENDIAN, result); + fail_if(copyBitsRightAligned(data, 4, 25, 16, result, 4)); +} +END_TEST + +START_TEST (test_get_bits) +{ + uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; + uint8_t result[4] = {0}; + fail_unless(copyBitsRightAligned(data, 4, 0, 16, result, 4)); ck_assert_int_eq(result[0], 0x12); ck_assert_int_eq(result[1], 0x34); } @@ -226,7 +234,7 @@ START_TEST (test_get_uneven_bits) { uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; uint8_t result[4] = {0}; - getBits(4, 12, data, 36, ENDIANNESS_BIG_ENDIAN, result); + fail_unless(copyBitsRightAligned(data, 4, 4, 12, result, 4)); ck_assert_int_eq(result[0], 0x2); ck_assert_int_eq(result[1], 0x34); } @@ -252,6 +260,7 @@ Suite* bitfieldSuite(void) { tcase_add_test(tc_core, test_get_byte); tcase_add_test(tc_core, test_get_nibble); tcase_add_test(tc_core, test_get_bits); + tcase_add_test(tc_core, test_get_bits_out_of_range); tcase_add_test(tc_core, test_get_uneven_bits); suite_add_tcase(s, tc_core); -- cgit 1.2.3-korg From a855335e3ad18a9d0094357eb39622448f8649a9 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sun, 29 Dec 2013 11:44:03 -0500 Subject: Standardize argument ordering for bitfield functions. --- src/bitfield/bitfield.c | 21 +++++++---------- src/bitfield/bitfield.h | 62 +++++++++++++++++++++++++++++++++++++++++++++---- tests/bitfield_tests.c | 10 ++++---- 3 files changed, 72 insertions(+), 21 deletions(-) diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c index b0396413..934d5a6a 100644 --- a/src/bitfield/bitfield.c +++ b/src/bitfield/bitfield.c @@ -55,24 +55,21 @@ uint8_t nthByte(const uint64_t source, const uint16_t byteNum) { return (source >> (64 - ((byteNum + 1) * CHAR_BIT))) & 0xFF; } -uint8_t getNibble(const uint8_t nibble_index, const uint8_t data[], - const uint8_t length) { +uint8_t getNibble(const uint8_t source[], const uint8_t source_length, + const uint8_t nibble_index) { uint8_t byte_index = nibble_index / 2; - uint8_t result; - if(byte_index < length) { - result = data[byte_index]; - if(nibble_index % 2 == 0) { - result >>= NIBBLE_SIZE; - } + uint8_t result = getByte(source, source_length, byte_index); + if(nibble_index % 2 == 0) { + result >>= NIBBLE_SIZE; } result &= bitmask(NIBBLE_SIZE); return result; } -uint8_t getByte(const uint8_t byte_index, const uint8_t data[], - const uint8_t length) { - if(byte_index < length) { - return data[byte_index]; +uint8_t getByte(const uint8_t source[], const uint8_t source_length, + const uint8_t byte_index) { + if(byte_index < source_length) { + return source[byte_index]; } return 0; } diff --git a/src/bitfield/bitfield.h b/src/bitfield/bitfield.h index bf5c9b7d..45e3ba26 100644 --- a/src/bitfield/bitfield.h +++ b/src/bitfield/bitfield.h @@ -8,11 +8,28 @@ extern "C" { #endif -uint8_t getNibble(const uint8_t nibble_index, const uint8_t data[], - const uint8_t length); +/* Public: Return a single nibble from the byte array, with range checking. + * + * source - the source byte array. + * source_length - the total length of the source array. + * nibble_index - the index of the nibble to retreive. The leftmost nibble is + * index 0. + * + * Returns the retreived nibble, right aligned in a uint8_t. + */ +uint8_t getNibble(const uint8_t source[], const uint8_t source_length, + const uint8_t nibble_index); -uint8_t getByte(const uint8_t byte_index, const uint8_t data[], - const uint8_t length); +/* Public: Return a single byte from the byte array, with range checking. + * + * source - the source byte array. + * source_length - the total length of the source array. + * byte_index - the index of the byte to retreive. The leftmost byte is index 0. + * + * Returns the retreived byte. + */ +uint8_t getByte(const uint8_t source[], const uint8_t source_length, + const uint8_t byte_index); /* Public: Copy a range of bits from one bit array to another. * @@ -23,6 +40,17 @@ uint8_t getByte(const uint8_t byte_index, const uint8_t data[], * A bit array with regards to this function always has the leftmost bit in byte * 0, i.e. bit index is the leftmost bit of byte 0. Endianness does not matter. * + * For example: + * + * uint8_t source[4] = {0x11, 0x22, 0x33, 0x44}; + * uint8_t destination[4] = {0}; + * copyBits(source, sizeof(source), 8, 8, destination, + * sizeof(destination), 0); + * // destination[0] == 0x22 + * // destination[1] == 0x0 + * // destination[2] == 0x0 + * // destination[3] == 0x0 + * * Thanks to * http://stackoverflow.com/questions/3534535/whats-a-time-efficient-algorithm-to-copy-unaligned-bit-arrays * for the implementation of the algorithm. @@ -50,6 +78,32 @@ bool copyBits(const uint8_t* source_origin, const uint16_t source_length, uint8_t* destination_origin, const uint16_t destination_length, const uint16_t destination_offset); +/* Public: Copy a range of bits from one array to another, right aligning the + * result. + * + * This is mostly useful if you want to cast the result to an integer type + * instead of a byte array. + * + * For example: + * + * uint8_t source[4] = {0x11, 0x22, 0x33, 0x44}; + * uint8_t destination[4] = {0}; + * copyBitsRightAligned(source, sizeof(source), 8, 8, destination, + * sizeof(destination)); + * // destination[0] == 0x0 + * // destination[1] == 0x0 + * // destination[2] == 0x0 + * // destination[3] == 0x22 + * + * int value = (int)destination; + * // value == 0x22 == 32 + * + * The arguments are the same as copyBits, but without the destination_offset + * option - that's set automatically to right align the result. + * + * Returns true if the copy was successful and false if the range exceeded the + * size of the source or destination, or if the range size negative or 0. + */ bool copyBitsRightAligned(const uint8_t source[], const uint16_t source_length, const uint16_t offset, const uint16_t bit_count, uint8_t* destination, const uint16_t destination_length); diff --git a/tests/bitfield_tests.c b/tests/bitfield_tests.c index e2304ea0..00a28a36 100644 --- a/tests/bitfield_tests.c +++ b/tests/bitfield_tests.c @@ -193,9 +193,9 @@ END_TEST START_TEST (test_get_byte) { uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; - uint8_t result = getByte(0, data, sizeof(data)); + uint8_t result = getByte(data, sizeof(data), 0); ck_assert_int_eq(result, 0x12); - result = getByte(3, data, sizeof(data)); + result = getByte(data, sizeof(data), 3); ck_assert_int_eq(result, 0x78); } END_TEST @@ -203,11 +203,11 @@ END_TEST START_TEST (test_get_nibble) { uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; - uint8_t result = getNibble(0, data, sizeof(data)); + uint8_t result = getNibble(data, sizeof(data), 0); ck_assert_int_eq(result, 0x1); - result = getNibble(1, data, sizeof(data)); + result = getNibble(data, sizeof(data), 1); ck_assert_int_eq(result, 0x2); - result = getNibble(2, data, sizeof(data)); + result = getNibble(data, sizeof(data), 2); ck_assert_int_eq(result, 0x3); } END_TEST -- cgit 1.2.3-korg From 6ce03a4f1b229e605da08b073fad6f7c0fe8bf10 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sun, 29 Dec 2013 11:48:24 -0500 Subject: Split up 8 byte wrappers from generic bit array functions. --- src/bitfield/8byte.c | 56 ++++++++++++ src/bitfield/8byte.h | 74 ++++++++++++++++ src/bitfield/bitfield.c | 50 ----------- src/bitfield/bitfield.h | 59 ------------- tests/8byte_tests.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/bitfield_tests.c | 202 ------------------------------------------- 6 files changed, 355 insertions(+), 311 deletions(-) create mode 100644 src/bitfield/8byte.c create mode 100644 src/bitfield/8byte.h create mode 100644 tests/8byte_tests.c diff --git a/src/bitfield/8byte.c b/src/bitfield/8byte.c new file mode 100644 index 00000000..0f249d93 --- /dev/null +++ b/src/bitfield/8byte.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include + +uint64_t bitmask(const uint8_t numBits) { + return (((uint64_t)0x1) << numBits) - 1; +} + +static uint16_t bitsToBytes(uint32_t bits) { + uint8_t byte_count = bits / CHAR_BIT; + if(bits % CHAR_BIT != 0) { + ++byte_count; + } + return byte_count; +} + +uint64_t getBitField(uint64_t data, const uint16_t startBit, + const uint16_t numBits, bool bigEndian) { + uint8_t result[8] = {0}; + if(!bigEndian) { + data = __builtin_bswap64(data); + } + copyBitsRightAligned((const uint8_t*)&data, sizeof(data), startBit, numBits, + result, sizeof(result)); + uint64_t int_result = 0; + + if(!bigEndian) { + // we need to swap the byte order of the array to get it into a + // uint64_t, but it's been right aligned so we have to be more careful + for(int i = 0; i < bitsToBytes(numBits); i++) { + int_result |= result[bitsToBytes(numBits) - i - 1] << (CHAR_BIT * i); + } + } else { + int_result = *(uint64_t*)result; + } + return int_result; +} + +/** + * TODO it would be nice to have a warning if you call with this a value that + * won't fit in the number of bits you've specified it should use. + */ +void setBitField(uint64_t* data, uint64_t value, const uint16_t startPos, + const uint16_t numBits) { + int shiftDistance = 64 - startPos - numBits; + value <<= shiftDistance; + *data &= ~(bitmask(numBits) << shiftDistance); + *data |= value; +} + +uint8_t nthByte(const uint64_t source, const uint16_t byteNum) { + return (source >> (64 - ((byteNum + 1) * CHAR_BIT))) & 0xFF; +} + diff --git a/src/bitfield/8byte.h b/src/bitfield/8byte.h new file mode 100644 index 00000000..13b6aff3 --- /dev/null +++ b/src/bitfield/8byte.h @@ -0,0 +1,74 @@ +#ifndef __8BYTE_H__ +#define __8BYTE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// TODO using uint64_t everywhere for CAN message payload is kind of cute, but +// in actuality a CAN message may have a smaller payload, and it makes all of +// these functions not applicable to other data sizes. It's also fairly +// inefficient on 32-bit platforms. how much work is it to switch vi-firmware +// to using uint8_t*? + +/* Public: Reads a subset of bits from a byte array. + * + * data - the bytes in question. + * startPos - the starting index of the bit field (beginning from 0). + * numBits - the width of the bit field to extract. + * bigEndian - if the data passed in is little endian, set this to false and it + * will be flipped before grabbing the bit field. + * + * Bit fields are positioned according to big-endian bit layout, but inside the + * bit field, values are represented as little-endian. Therefore, to get the bit + * field, we swap the overall byte order if bigEndian == false and + * use the value we find in the field (assuming the embedded platform is little + * endian). + * + * 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 + * + * If the architecture where is code is running is little-endian, the input data + * will be swapped before grabbing the bit field. + * + * Examples + * + * uint64_t value = getBitField(data, 2, 4); + * + * Returns the value of the requested bit field. + */ +uint64_t getBitField(uint64_t data, const uint16_t startPos, + const uint16_t numBits, bool bigEndian); + +/* Public: Set the bit field in the given data array to the new value. + * + * data - a byte array with size at least startPos + numBits. + * value - the value to set in the bit field. + * startPos - the starting index of the bit field (beginning from 0). + */ +void setBitField(uint64_t* data, uint64_t value, const uint16_t startPos, + const uint16_t numBits); + +/* Public: Retreive the nth byte out of 8 bytes in a uint64_t. + * + * source - the source data to retreive the byte from. + * byteNum - the index of the byte, starting at 0 and assuming big-endian order. + * + * Returns the requested byte from the source bytes. + */ +uint8_t nthByte(const uint64_t source, const uint16_t byteNum); + +#ifdef __cplusplus +} +#endif + +#endif // __8BYTE_H__ diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c index 934d5a6a..3bf00ac0 100644 --- a/src/bitfield/bitfield.c +++ b/src/bitfield/bitfield.c @@ -5,56 +5,6 @@ #define NIBBLE_SIZE (CHAR_BIT / 2) -uint64_t bitmask(const uint8_t numBits) { - return (((uint64_t)0x1) << numBits) - 1; -} - -static uint16_t bitsToBytes(uint32_t bits) { - uint8_t byte_count = bits / CHAR_BIT; - if(bits % CHAR_BIT != 0) { - ++byte_count; - } - return byte_count; -} - -uint64_t getBitField(uint64_t data, const uint16_t startBit, - const uint16_t numBits, bool bigEndian) { - uint8_t result[8] = {0}; - if(!bigEndian) { - data = __builtin_bswap64(data); - } - copyBitsRightAligned((const uint8_t*)&data, sizeof(data), startBit, numBits, - result, sizeof(result)); - uint64_t int_result = 0; - - if(!bigEndian) { - // we need to swap the byte order of the array to get it into a - // uint64_t, but it's been right aligned so we have to be more careful - for(int i = 0; i < bitsToBytes(numBits); i++) { - int_result |= result[bitsToBytes(numBits) - i - 1] << (CHAR_BIT * i); - } - } else { - int_result = *(uint64_t*)result; - } - return int_result; -} - -/** - * TODO it would be nice to have a warning if you call with this a value that - * won't fit in the number of bits you've specified it should use. - */ -void setBitField(uint64_t* data, uint64_t value, const uint16_t startPos, - const uint16_t numBits) { - int shiftDistance = 64 - startPos - numBits; - value <<= shiftDistance; - *data &= ~(bitmask(numBits) << shiftDistance); - *data |= value; -} - -uint8_t nthByte(const uint64_t source, const uint16_t byteNum) { - return (source >> (64 - ((byteNum + 1) * CHAR_BIT))) & 0xFF; -} - uint8_t getNibble(const uint8_t source[], const uint8_t source_length, const uint8_t nibble_index) { uint8_t byte_index = nibble_index / 2; diff --git a/src/bitfield/bitfield.h b/src/bitfield/bitfield.h index 45e3ba26..6f5f1c18 100644 --- a/src/bitfield/bitfield.h +++ b/src/bitfield/bitfield.h @@ -108,65 +108,6 @@ bool copyBitsRightAligned(const uint8_t source[], const uint16_t source_length, const uint16_t offset, const uint16_t bit_count, uint8_t* destination, const uint16_t destination_length); -// TODO using uint64_t everywhere for CAN message payload is kind of cute, but -// in actuality a CAN message may have a smaller payload, and it makes all of -// these functions not applicable to other data sizes. It's also fairly -// inefficient on 32-bit platforms. how much work is it to switch vi-firmware -// to using uint8_t*? - -/* Public: Reads a subset of bits from a byte array. - * - * data - the bytes in question. - * startPos - the starting index of the bit field (beginning from 0). - * numBits - the width of the bit field to extract. - * bigEndian - if the data passed in is little endian, set this to false and it - * will be flipped before grabbing the bit field. - * - * Bit fields are positioned according to big-endian bit layout, but inside the - * bit field, values are represented as little-endian. Therefore, to get the bit - * field, we swap the overall byte order if bigEndian == false and - * use the value we find in the field (assuming the embedded platform is little - * endian). - * - * 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 - * - * If the architecture where is code is running is little-endian, the input data - * will be swapped before grabbing the bit field. - * - * Examples - * - * uint64_t value = getBitField(data, 2, 4); - * - * Returns the value of the requested bit field. - */ -uint64_t getBitField(uint64_t data, const uint16_t startPos, - const uint16_t numBits, bool bigEndian); - -/* Public: Set the bit field in the given data array to the new value. - * - * data - a byte array with size at least startPos + numBits. - * value - the value to set in the bit field. - * startPos - the starting index of the bit field (beginning from 0). - */ -void setBitField(uint64_t* data, uint64_t value, const uint16_t startPos, - const uint16_t numBits); - -/* Public: Retreive the nth byte out of 8 bytes in a uint64_t. - * - * source - the source data to retreive the byte from. - * byteNum - the index of the byte, starting at 0 and assuming big-endian order. - * - * Returns the requested byte from the source bytes. - */ -uint8_t nthByte(const uint64_t source, const uint16_t byteNum); - #ifdef __cplusplus } #endif diff --git a/tests/8byte_tests.c b/tests/8byte_tests.c new file mode 100644 index 00000000..140c4efb --- /dev/null +++ b/tests/8byte_tests.c @@ -0,0 +1,225 @@ +#include +#include +#include + +START_TEST (test_large_bitmask) +{ + // yeah, this isn't a public method but I wanted to unit test it to track + // down a bug + extern uint64_t bitmask(int numBits); + uint64_t result = bitmask(32); + fail_if(result != 0xffffffff); +} +END_TEST + +START_TEST (test_one_bit_not_swapped) +{ + uint64_t data = 0x80; + uint64_t result = getBitField(data, 0, 1, false); + fail_if(result == 1); +} +END_TEST + +START_TEST (test_one_bit) +{ + uint64_t data = 0x8000000000000000; + uint64_t result = getBitField(data, 0, 1, false); + fail_unless(result == 0x1, + "First bit in 0x%llx was 0x%llx instead of 0x1", data, result); +} +END_TEST + +START_TEST (test_32_bit_parse) +{ + uint64_t data = 0x0402574d555a0401; + uint64_t result = getBitField(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, + result, expectedValue); +} +END_TEST + +START_TEST (test_16_bit_parse) +{ + uint64_t data = 0xF34DFCFF00000000; + uint64_t result = getBitField(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, + result, expectedValue); +} +END_TEST + +START_TEST (test_one_byte) +{ + uint64_t data = 0xFA00000000000000; + uint64_t result = getBitField(data, 0, 4, false); + fail_unless(result == 0xF, + "First 4 bits in 0x%llx was 0x%llx instead of 0xF", data, result); + result = getBitField(data, 4, 4, false); + fail_unless(result == 0xA, + "First 4 bits in 0x%llx was 0x%llx instead of 0xA", data, result); + result = getBitField(data, 0, 8, false); + fail_unless(result == 0xFA, + "All bits in 0x%llx were 0x%llx instead of 0x%llx", data, result, data); +} +END_TEST + +START_TEST (test_multi_byte) +{ + uint64_t data = 0x12FA000000000000; + uint64_t result = getBitField(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 = getBitField(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 = getBitField(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 = getBitField(data, 12, 4, false); + fail_unless(result == 0xA, + "Second 4 bits in 0x%llx was 0x%llx instead of 0x2", (data >> 48) % 0xF, + result); +} +END_TEST + +START_TEST (test_get_multi_byte) +{ + uint64_t data = 0x12FA000000000000; + uint64_t result = getBitField(data, 0, 9, false); + ck_assert_int_eq(result, 0x25); +} +END_TEST + +START_TEST (test_get_off_byte_boundary) +{ + uint64_t data = 0x000012FA00000000; + uint64_t result = getBitField(data, 12, 8, false); + ck_assert_int_eq(result, 0x01); +} END_TEST + +START_TEST (test_set_field) +{ + uint64_t data = 0; + setBitField(&data, 1, 0, 1); + uint64_t result = getBitField(data, 0, 1, false); + ck_assert_int_eq(result, 0x1); + data = 0; + setBitField(&data, 1, 1, 1); + result = getBitField(data, 1, 1, false); + ck_assert_int_eq(result, 0x1); + + data = 0; + setBitField(&data, 0xf, 3, 4); + result = getBitField(data, 3, 4, false); + ck_assert_int_eq(result, 0xf); +} +END_TEST + +START_TEST (test_set_doesnt_clobber_existing_data) +{ + uint64_t data = 0xFFFC4DF300000000; + setBitField(&data, 0x4fc8, 16, 16); + uint64_t result = getBitField(data, 16, 16, false); + fail_unless(result == 0x4fc8, + "Field retrieved in 0x%llx was 0x%llx instead of 0x%x", data, result, + 0xc84f); + + data = 0x8000000000000000; + setBitField(&data, 1, 21, 1); + fail_unless(data == 0x8000040000000000LLU, + "Expected combined value 0x8000040000000000 but got 0x%llx%llx", + data >> 32, data); +} +END_TEST + +START_TEST (test_set_off_byte_boundary) +{ + uint64_t data = 0xFFFC4DF300000000; + setBitField(&data, 0x12, 12, 8); + uint64_t result = getBitField(data, 12, 12, false); + ck_assert_int_eq(result,0x12d); +} +END_TEST + +START_TEST (test_set_odd_number_of_bits) +{ + uint64_t data = 0xFFFC4DF300000000LLU; + setBitField(&data, 0x12, 11, 5); + uint64_t result = getBitField(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; + setBitField(&data, 0x2, 11, 5); + result = getBitField(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); +} +END_TEST + +START_TEST(test_nth_byte) +{ + uint64_t data = 0x00000000F34DFCFF; + uint8_t result = nthByte(data, 0); + uint8_t expected = 0x0; + ck_assert_int_eq(result, expected); + + result = nthByte(data, 4); + expected = 0xF3; + ck_assert_int_eq(result, expected); + + result = nthByte(data, 5); + expected = 0x4D; + ck_assert_int_eq(result, expected); + + result = nthByte(data, 6); + expected = 0xFC; + ck_assert_int_eq(result, expected); + + result = nthByte(data, 7); + expected = 0xFF; + ck_assert_int_eq(result, expected); +} +END_TEST + +Suite* bitfieldSuite(void) { + Suite* s = suite_create("bitfield"); + TCase *tc_core = tcase_create("core"); + tcase_add_test(tc_core, test_large_bitmask); + tcase_add_test(tc_core, test_one_bit); + tcase_add_test(tc_core, test_one_bit_not_swapped); + tcase_add_test(tc_core, test_one_byte); + tcase_add_test(tc_core, test_16_bit_parse); + tcase_add_test(tc_core, test_32_bit_parse); + tcase_add_test(tc_core, test_multi_byte); + tcase_add_test(tc_core, test_get_multi_byte); + tcase_add_test(tc_core, test_get_off_byte_boundary); + tcase_add_test(tc_core, test_set_field); + tcase_add_test(tc_core, test_set_doesnt_clobber_existing_data); + tcase_add_test(tc_core, test_set_off_byte_boundary); + tcase_add_test(tc_core, test_set_odd_number_of_bits); + tcase_add_test(tc_core, test_nth_byte); + suite_add_tcase(s, tc_core); + + return s; +} + +int main(void) { + int numberFailed; + Suite* s = bitfieldSuite(); + SRunner *sr = srunner_create(s); + // Don't fork so we can actually use gdb + srunner_set_fork_status(sr, CK_NOFORK); + srunner_run_all(sr, CK_NORMAL); + numberFailed = srunner_ntests_failed(sr); + srunner_free(sr); + return (numberFailed == 0) ? 0 : 1; +} diff --git a/tests/bitfield_tests.c b/tests/bitfield_tests.c index 00a28a36..f6287c19 100644 --- a/tests/bitfield_tests.c +++ b/tests/bitfield_tests.c @@ -2,194 +2,6 @@ #include #include -START_TEST (test_large_bitmask) -{ - // yeah, this isn't a public method but I wanted to unit test it to track - // down a bug - extern uint64_t bitmask(int numBits); - uint64_t result = bitmask(32); - fail_if(result != 0xffffffff); -} -END_TEST - -START_TEST (test_one_bit_not_swapped) -{ - uint64_t data = 0x80; - uint64_t result = getBitField(data, 0, 1, false); - fail_if(result == 1); -} -END_TEST - -START_TEST (test_one_bit) -{ - uint64_t data = 0x8000000000000000; - uint64_t result = getBitField(data, 0, 1, false); - fail_unless(result == 0x1, - "First bit in 0x%llx was 0x%llx instead of 0x1", data, result); -} -END_TEST - -START_TEST (test_32_bit_parse) -{ - uint64_t data = 0x0402574d555a0401; - uint64_t result = getBitField(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, - result, expectedValue); -} -END_TEST - -START_TEST (test_16_bit_parse) -{ - uint64_t data = 0xF34DFCFF00000000; - uint64_t result = getBitField(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, - result, expectedValue); -} -END_TEST - -START_TEST (test_one_byte) -{ - uint64_t data = 0xFA00000000000000; - uint64_t result = getBitField(data, 0, 4, false); - fail_unless(result == 0xF, - "First 4 bits in 0x%llx was 0x%llx instead of 0xF", data, result); - result = getBitField(data, 4, 4, false); - fail_unless(result == 0xA, - "First 4 bits in 0x%llx was 0x%llx instead of 0xA", data, result); - result = getBitField(data, 0, 8, false); - fail_unless(result == 0xFA, - "All bits in 0x%llx were 0x%llx instead of 0x%llx", data, result, data); -} -END_TEST - -START_TEST (test_multi_byte) -{ - uint64_t data = 0x12FA000000000000; - uint64_t result = getBitField(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 = getBitField(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 = getBitField(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 = getBitField(data, 12, 4, false); - fail_unless(result == 0xA, - "Second 4 bits in 0x%llx was 0x%llx instead of 0x2", (data >> 48) % 0xF, - result); -} -END_TEST - -START_TEST (test_get_multi_byte) -{ - uint64_t data = 0x12FA000000000000; - uint64_t result = getBitField(data, 0, 9, false); - ck_assert_int_eq(result, 0x25); -} -END_TEST - -START_TEST (test_get_off_byte_boundary) -{ - uint64_t data = 0x000012FA00000000; - uint64_t result = getBitField(data, 12, 8, false); - ck_assert_int_eq(result, 0x01); -} END_TEST - -START_TEST (test_set_field) -{ - uint64_t data = 0; - setBitField(&data, 1, 0, 1); - uint64_t result = getBitField(data, 0, 1, false); - ck_assert_int_eq(result, 0x1); - data = 0; - setBitField(&data, 1, 1, 1); - result = getBitField(data, 1, 1, false); - ck_assert_int_eq(result, 0x1); - - data = 0; - setBitField(&data, 0xf, 3, 4); - result = getBitField(data, 3, 4, false); - ck_assert_int_eq(result, 0xf); -} -END_TEST - -START_TEST (test_set_doesnt_clobber_existing_data) -{ - uint64_t data = 0xFFFC4DF300000000; - setBitField(&data, 0x4fc8, 16, 16); - uint64_t result = getBitField(data, 16, 16, false); - fail_unless(result == 0x4fc8, - "Field retrieved in 0x%llx was 0x%llx instead of 0x%x", data, result, - 0xc84f); - - data = 0x8000000000000000; - setBitField(&data, 1, 21, 1); - fail_unless(data == 0x8000040000000000LLU, - "Expected combined value 0x8000040000000000 but got 0x%llx%llx", - data >> 32, data); -} -END_TEST - -START_TEST (test_set_off_byte_boundary) -{ - uint64_t data = 0xFFFC4DF300000000; - setBitField(&data, 0x12, 12, 8); - uint64_t result = getBitField(data, 12, 12, false); - ck_assert_int_eq(result,0x12d); -} -END_TEST - -START_TEST (test_set_odd_number_of_bits) -{ - uint64_t data = 0xFFFC4DF300000000LLU; - setBitField(&data, 0x12, 11, 5); - uint64_t result = getBitField(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; - setBitField(&data, 0x2, 11, 5); - result = getBitField(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); -} -END_TEST - -START_TEST(test_nth_byte) -{ - uint64_t data = 0x00000000F34DFCFF; - uint8_t result = nthByte(data, 0); - uint8_t expected = 0x0; - ck_assert_int_eq(result, expected); - - result = nthByte(data, 4); - expected = 0xF3; - ck_assert_int_eq(result, expected); - - result = nthByte(data, 5); - expected = 0x4D; - ck_assert_int_eq(result, expected); - - result = nthByte(data, 6); - expected = 0xFC; - ck_assert_int_eq(result, expected); - - result = nthByte(data, 7); - expected = 0xFF; - ck_assert_int_eq(result, expected); -} -END_TEST - START_TEST (test_get_byte) { uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; @@ -243,20 +55,6 @@ END_TEST Suite* bitfieldSuite(void) { Suite* s = suite_create("bitfield"); TCase *tc_core = tcase_create("core"); - tcase_add_test(tc_core, test_large_bitmask); - tcase_add_test(tc_core, test_one_bit); - tcase_add_test(tc_core, test_one_bit_not_swapped); - tcase_add_test(tc_core, test_one_byte); - tcase_add_test(tc_core, test_16_bit_parse); - tcase_add_test(tc_core, test_32_bit_parse); - tcase_add_test(tc_core, test_multi_byte); - tcase_add_test(tc_core, test_get_multi_byte); - tcase_add_test(tc_core, test_get_off_byte_boundary); - tcase_add_test(tc_core, test_set_field); - tcase_add_test(tc_core, test_set_doesnt_clobber_existing_data); - tcase_add_test(tc_core, test_set_off_byte_boundary); - tcase_add_test(tc_core, test_set_odd_number_of_bits); - tcase_add_test(tc_core, test_nth_byte); tcase_add_test(tc_core, test_get_byte); tcase_add_test(tc_core, test_get_nibble); tcase_add_test(tc_core, test_get_bits); -- cgit 1.2.3-korg From c2c7ef1dfe4cae6b5831ffab0ce5780b27e0c25e Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sun, 29 Dec 2013 11:55:35 -0500 Subject: Standardize on snake_case naming as this is a C library. --- src/bitfield/8byte.c | 40 ++++++++++++++++--------------- src/bitfield/8byte.h | 29 ++++++++++++----------- src/canutil/read.c | 12 +++++----- src/canutil/read.h | 4 ++-- src/canutil/write.c | 14 +++++------ src/canutil/write.h | 4 ++-- tests/8byte_tests.c | 66 ++++++++++++++++++++++++++-------------------------- tests/read_tests.c | 2 +- tests/write_tests.c | 4 ++-- 9 files changed, 89 insertions(+), 86 deletions(-) diff --git a/src/bitfield/8byte.c b/src/bitfield/8byte.c index 0f249d93..77251996 100644 --- a/src/bitfield/8byte.c +++ b/src/bitfield/8byte.c @@ -4,11 +4,13 @@ #include #include -uint64_t bitmask(const uint8_t numBits) { - return (((uint64_t)0x1) << numBits) - 1; +#define EIGHTBYTE_BIT (8 * sizeof(uint64_t)) + +uint64_t bitmask(const uint8_t bit_count) { + return (((uint64_t)0x1) << bit_count) - 1; } -static uint16_t bitsToBytes(uint32_t bits) { +static uint16_t bits_to_bytes(uint32_t bits) { uint8_t byte_count = bits / CHAR_BIT; if(bits % CHAR_BIT != 0) { ++byte_count; @@ -16,21 +18,21 @@ static uint16_t bitsToBytes(uint32_t bits) { return byte_count; } -uint64_t getBitField(uint64_t data, const uint16_t startBit, - const uint16_t numBits, bool bigEndian) { +uint64_t get_bit_field(uint64_t source, const uint16_t startBit, + const uint16_t bit_count, bool big_endian) { uint8_t result[8] = {0}; - if(!bigEndian) { - data = __builtin_bswap64(data); + if(!big_endian) { + source = __builtin_bswap64(source); } - copyBitsRightAligned((const uint8_t*)&data, sizeof(data), startBit, numBits, - result, sizeof(result)); + copyBitsRightAligned((const uint8_t*)&source, sizeof(source), startBit, + bit_count, result, sizeof(result)); uint64_t int_result = 0; - if(!bigEndian) { + if(!big_endian) { // we need to swap the byte order of the array to get it into a // uint64_t, but it's been right aligned so we have to be more careful - for(int i = 0; i < bitsToBytes(numBits); i++) { - int_result |= result[bitsToBytes(numBits) - i - 1] << (CHAR_BIT * i); + for(int i = 0; i < bits_to_bytes(bit_count); i++) { + int_result |= result[bits_to_bytes(bit_count) - i - 1] << (CHAR_BIT * i); } } else { int_result = *(uint64_t*)result; @@ -42,15 +44,15 @@ uint64_t getBitField(uint64_t data, const uint16_t startBit, * TODO it would be nice to have a warning if you call with this a value that * won't fit in the number of bits you've specified it should use. */ -void setBitField(uint64_t* data, uint64_t value, const uint16_t startPos, - const uint16_t numBits) { - int shiftDistance = 64 - startPos - numBits; +void set_bit_field(uint64_t* destination, uint64_t value, const uint16_t offset, + const uint16_t bit_count) { + int shiftDistance = EIGHTBYTE_BIT - offset - bit_count; value <<= shiftDistance; - *data &= ~(bitmask(numBits) << shiftDistance); - *data |= value; + *destination &= ~(bitmask(bit_count) << shiftDistance); + *destination |= value; } -uint8_t nthByte(const uint64_t source, const uint16_t byteNum) { - return (source >> (64 - ((byteNum + 1) * CHAR_BIT))) & 0xFF; +uint8_t nth_byte(const uint64_t source, const uint16_t byte_index) { + return (source >> (EIGHTBYTE_BIT - ((byte_index + 1) * CHAR_BIT))) & 0xFF; } diff --git a/src/bitfield/8byte.h b/src/bitfield/8byte.h index 13b6aff3..9cbf61a9 100644 --- a/src/bitfield/8byte.h +++ b/src/bitfield/8byte.h @@ -14,17 +14,17 @@ extern "C" { // inefficient on 32-bit platforms. how much work is it to switch vi-firmware // to using uint8_t*? -/* Public: Reads a subset of bits from a byte array. +/* Public: Reads a subset of bits into a uint64_t. * - * data - the bytes in question. - * startPos - the starting index of the bit field (beginning from 0). + * source - the bytes in question. + * offset - the starting index of the bit field (beginning from 0). * numBits - the width of the bit field to extract. - * bigEndian - if the data passed in is little endian, set this to false and it + * big_endian - if the data passed in is little endian, set this to false and it * will be flipped before grabbing the bit field. * * Bit fields are positioned according to big-endian bit layout, but inside the * bit field, values are represented as little-endian. Therefore, to get the bit - * field, we swap the overall byte order if bigEndian == false and + * field, we swap the overall byte order if big_endian == false and * use the value we find in the field (assuming the embedded platform is little * endian). * @@ -42,30 +42,31 @@ extern "C" { * * Examples * - * uint64_t value = getBitField(data, 2, 4); + * uint64_t value = get_bit_field(data, 2, 4); * * Returns the value of the requested bit field. */ -uint64_t getBitField(uint64_t data, const uint16_t startPos, - const uint16_t numBits, bool bigEndian); +uint64_t get_bit_field(uint64_t source, const uint16_t offset, + const uint16_t bit_count, bool big_endian); /* Public: Set the bit field in the given data array to the new value. * - * data - a byte array with size at least startPos + numBits. + * destination - a byte array with size at least offset + bit_count. * value - the value to set in the bit field. - * startPos - the starting index of the bit field (beginning from 0). + * offset - the starting index of the bit field (beginning from 0). + * bit_count - the number of bits to set in the data. */ -void setBitField(uint64_t* data, uint64_t value, const uint16_t startPos, - const uint16_t numBits); +void set_bit_field(uint64_t* destination, uint64_t value, const uint16_t offset, + const uint16_t bit_count); /* Public: Retreive the nth byte out of 8 bytes in a uint64_t. * * source - the source data to retreive the byte from. - * byteNum - the index of the byte, starting at 0 and assuming big-endian order. + * byte_index - the index of the byte, starting at 0 and assuming big-endian order. * * Returns the requested byte from the source bytes. */ -uint8_t nthByte(const uint64_t source, const uint16_t byteNum); +uint8_t nth_byte(const uint64_t source, const uint16_t byte_index); #ifdef __cplusplus } diff --git a/src/canutil/read.c b/src/canutil/read.c index 6b4e40aa..5e882c3d 100644 --- a/src/canutil/read.c +++ b/src/canutil/read.c @@ -1,14 +1,14 @@ #include -float parseFloat(uint64_t data, uint8_t bitPosition, uint8_t bitSize, +float bitfield_parse_float(uint64_t data, uint8_t bit_offset, uint8_t bit_size, float factor, float offset) { - uint64_t rawValue = getBitField(data, bitPosition, - bitSize, true); - return rawValue * factor + offset; + uint64_t raw = get_bit_field(data, bit_offset, + bit_size, true); + return raw * factor + offset; } -bool parseBoolean(uint64_t data, uint8_t bitPosition, uint8_t bitSize, +bool bitfield_parse_bool(uint64_t data, uint8_t bit_offset, uint8_t bit_size, float factor, float offset) { - float value = parseFloat(data, bitPosition, bitSize, factor, offset); + float value = bitfield_parse_float(data, 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 6ac4eebe..3742d6d1 100644 --- a/src/canutil/read.h +++ b/src/canutil/read.h @@ -16,10 +16,10 @@ extern "C" { * * Returns the final, transformed value of the signal. */ -float parseFloat(uint64_t data, uint8_t bitPosition, uint8_t bitSize, +float bitfield_parse_float(uint64_t data, uint8_t bit_offset, uint8_t bit_size, float factor, float offset); -bool parseBoolean(uint64_t data, uint8_t bitPosition, uint8_t bitSize, +bool bitfield_parse_bool(uint64_t data, uint8_t bit_offset, uint8_t bit_size, float factor, float offset); #ifdef __cplusplus diff --git a/src/canutil/write.c b/src/canutil/write.c index 64b57297..14d2a449 100644 --- a/src/canutil/write.c +++ b/src/canutil/write.c @@ -1,19 +1,19 @@ #include "write.h" #include -uint64_t encodeFloat(float value, uint8_t bitPosition, uint8_t bitSize, +uint64_t bitfield_encode_float(float value, uint8_t bit_offset, uint8_t bit_size, float factor, float offset) { - float rawValue = (value - offset) / factor; - if(rawValue > 0) { + float raw = (value - offset) / factor; + if(raw > 0) { // round up to avoid losing precision when we cast to an int - rawValue += 0.5; + raw += 0.5; } uint64_t result = 0; - setBitField(&result, (uint64_t)rawValue, bitPosition, bitSize); + set_bit_field(&result, (uint64_t)raw, bit_offset, bit_size); return result; } -uint64_t encodeBoolean(bool value, uint8_t bitPosition, uint8_t bitSize, +uint64_t bitfield_encode_bool(bool value, uint8_t bit_offset, uint8_t bit_size, float factor, float offset) { - return encodeFloat(value, offset, factor, bitPosition, bitSize); + return bitfield_encode_float(value, offset, factor, bit_offset, bit_size); } diff --git a/src/canutil/write.h b/src/canutil/write.h index 1b086dbe..3d13b1df 100644 --- a/src/canutil/write.h +++ b/src/canutil/write.h @@ -8,10 +8,10 @@ extern "C" { #endif -uint64_t encodeFloat(float value, uint8_t bitPosition, uint8_t bitSize, +uint64_t bitfield_encode_float(float value, uint8_t bit_offset, uint8_t bit_size, float factor, float offset); -uint64_t encodeBoolean(bool value, uint8_t bitPosition, uint8_t bitSize, +uint64_t bitfield_encode_bool(bool value, uint8_t bit_offset, uint8_t bit_size, float factor, float offset); #ifdef __cplusplus diff --git a/tests/8byte_tests.c b/tests/8byte_tests.c index 140c4efb..f4188bfe 100644 --- a/tests/8byte_tests.c +++ b/tests/8byte_tests.c @@ -15,7 +15,7 @@ END_TEST START_TEST (test_one_bit_not_swapped) { uint64_t data = 0x80; - uint64_t result = getBitField(data, 0, 1, false); + uint64_t result = get_bit_field(data, 0, 1, false); fail_if(result == 1); } END_TEST @@ -23,7 +23,7 @@ END_TEST START_TEST (test_one_bit) { uint64_t data = 0x8000000000000000; - uint64_t result = getBitField(data, 0, 1, false); + uint64_t result = get_bit_field(data, 0, 1, false); fail_unless(result == 0x1, "First bit in 0x%llx was 0x%llx instead of 0x1", data, result); } @@ -32,7 +32,7 @@ END_TEST START_TEST (test_32_bit_parse) { uint64_t data = 0x0402574d555a0401; - uint64_t result = getBitField(data, 16, 32, false); + uint64_t result = get_bit_field(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, @@ -43,7 +43,7 @@ END_TEST START_TEST (test_16_bit_parse) { uint64_t data = 0xF34DFCFF00000000; - uint64_t result = getBitField(data, 16, 16, false); + uint64_t result = get_bit_field(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, @@ -54,13 +54,13 @@ END_TEST START_TEST (test_one_byte) { uint64_t data = 0xFA00000000000000; - uint64_t result = getBitField(data, 0, 4, false); + uint64_t result = get_bit_field(data, 0, 4, false); fail_unless(result == 0xF, "First 4 bits in 0x%llx was 0x%llx instead of 0xF", data, result); - result = getBitField(data, 4, 4, false); + result = get_bit_field(data, 4, 4, false); fail_unless(result == 0xA, "First 4 bits in 0x%llx was 0x%llx instead of 0xA", data, result); - result = getBitField(data, 0, 8, false); + result = get_bit_field(data, 0, 8, false); fail_unless(result == 0xFA, "All bits in 0x%llx were 0x%llx instead of 0x%llx", data, result, data); } @@ -69,19 +69,19 @@ END_TEST START_TEST (test_multi_byte) { uint64_t data = 0x12FA000000000000; - uint64_t result = getBitField(data, 0, 4, false); + uint64_t result = get_bit_field(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 = getBitField(data, 4, 4, false); + result = get_bit_field(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 = getBitField(data, 8, 4, false); + result = get_bit_field(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 = getBitField(data, 12, 4, false); + result = get_bit_field(data, 12, 4, false); fail_unless(result == 0xA, "Second 4 bits in 0x%llx was 0x%llx instead of 0x2", (data >> 48) % 0xF, result); @@ -91,7 +91,7 @@ END_TEST START_TEST (test_get_multi_byte) { uint64_t data = 0x12FA000000000000; - uint64_t result = getBitField(data, 0, 9, false); + uint64_t result = get_bit_field(data, 0, 9, false); ck_assert_int_eq(result, 0x25); } END_TEST @@ -99,24 +99,24 @@ END_TEST START_TEST (test_get_off_byte_boundary) { uint64_t data = 0x000012FA00000000; - uint64_t result = getBitField(data, 12, 8, false); + uint64_t result = get_bit_field(data, 12, 8, false); ck_assert_int_eq(result, 0x01); } END_TEST START_TEST (test_set_field) { uint64_t data = 0; - setBitField(&data, 1, 0, 1); - uint64_t result = getBitField(data, 0, 1, false); + set_bit_field(&data, 1, 0, 1); + uint64_t result = get_bit_field(data, 0, 1, false); ck_assert_int_eq(result, 0x1); data = 0; - setBitField(&data, 1, 1, 1); - result = getBitField(data, 1, 1, false); + set_bit_field(&data, 1, 1, 1); + result = get_bit_field(data, 1, 1, false); ck_assert_int_eq(result, 0x1); data = 0; - setBitField(&data, 0xf, 3, 4); - result = getBitField(data, 3, 4, false); + set_bit_field(&data, 0xf, 3, 4); + result = get_bit_field(data, 3, 4, false); ck_assert_int_eq(result, 0xf); } END_TEST @@ -124,14 +124,14 @@ END_TEST START_TEST (test_set_doesnt_clobber_existing_data) { uint64_t data = 0xFFFC4DF300000000; - setBitField(&data, 0x4fc8, 16, 16); - uint64_t result = getBitField(data, 16, 16, false); + set_bit_field(&data, 0x4fc8, 16, 16); + uint64_t result = get_bit_field(data, 16, 16, false); fail_unless(result == 0x4fc8, "Field retrieved in 0x%llx was 0x%llx instead of 0x%x", data, result, 0xc84f); data = 0x8000000000000000; - setBitField(&data, 1, 21, 1); + set_bit_field(&data, 1, 21, 1); fail_unless(data == 0x8000040000000000LLU, "Expected combined value 0x8000040000000000 but got 0x%llx%llx", data >> 32, data); @@ -141,8 +141,8 @@ END_TEST START_TEST (test_set_off_byte_boundary) { uint64_t data = 0xFFFC4DF300000000; - setBitField(&data, 0x12, 12, 8); - uint64_t result = getBitField(data, 12, 12, false); + set_bit_field(&data, 0x12, 12, 8); + uint64_t result = get_bit_field(data, 12, 12, false); ck_assert_int_eq(result,0x12d); } END_TEST @@ -150,15 +150,15 @@ END_TEST START_TEST (test_set_odd_number_of_bits) { uint64_t data = 0xFFFC4DF300000000LLU; - setBitField(&data, 0x12, 11, 5); - uint64_t result = getBitField(data, 11, 5, false); + set_bit_field(&data, 0x12, 11, 5); + uint64_t result = get_bit_field(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; - setBitField(&data, 0x2, 11, 5); - result = getBitField(data, 11, 5, false); + set_bit_field(&data, 0x2, 11, 5); + result = get_bit_field(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); @@ -168,23 +168,23 @@ END_TEST START_TEST(test_nth_byte) { uint64_t data = 0x00000000F34DFCFF; - uint8_t result = nthByte(data, 0); + uint8_t result = nth_byte(data, 0); uint8_t expected = 0x0; ck_assert_int_eq(result, expected); - result = nthByte(data, 4); + result = nth_byte(data, 4); expected = 0xF3; ck_assert_int_eq(result, expected); - result = nthByte(data, 5); + result = nth_byte(data, 5); expected = 0x4D; ck_assert_int_eq(result, expected); - result = nthByte(data, 6); + result = nth_byte(data, 6); expected = 0xFC; ck_assert_int_eq(result, expected); - result = nthByte(data, 7); + result = nth_byte(data, 7); expected = 0xFF; ck_assert_int_eq(result, expected); } diff --git a/tests/read_tests.c b/tests/read_tests.c index f5f0f0c3..62ced1f9 100644 --- a/tests/read_tests.c +++ b/tests/read_tests.c @@ -6,7 +6,7 @@ const uint64_t BIG_ENDIAN_TEST_DATA = __builtin_bswap64(0xEB00000000000000); START_TEST (test_parse_float) { - float result = parseFloat(BIG_ENDIAN_TEST_DATA, 2, 4, 1001.0, -30000.0); + float result = bitfield_parse_float(BIG_ENDIAN_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); diff --git a/tests/write_tests.c b/tests/write_tests.c index da5ee89c..ed555f60 100644 --- a/tests/write_tests.c +++ b/tests/write_tests.c @@ -4,14 +4,14 @@ START_TEST (test_encode_can_signal) { - uint64_t value = encodeFloat(0, 1, 3, 1, 0); + uint64_t value = bitfield_encode_float(0, 1, 3, 1, 0); ck_assert_int_eq(value, 0); } END_TEST START_TEST (test_encode_can_signal_rounding_precision) { - uint64_t value = encodeFloat(50, 2, 19, 0.001, 0); + uint64_t value = bitfield_encode_float(50, 2, 19, 0.001, 0); ck_assert_int_eq(value, 0x061a800000000000LLU); } END_TEST -- cgit 1.2.3-korg From f29f8a4cefbdc798c4a9aba495da7d2c0a81774c Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sun, 29 Dec 2013 12:06:11 -0500 Subject: Check if a value will fit in bitfield before setting. --- src/bitfield/8byte.c | 11 ++++++----- src/bitfield/8byte.h | 5 ++++- tests/8byte_tests.c | 24 ++++++++++++++++-------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/bitfield/8byte.c b/src/bitfield/8byte.c index 77251996..3b6b5466 100644 --- a/src/bitfield/8byte.c +++ b/src/bitfield/8byte.c @@ -40,16 +40,17 @@ uint64_t get_bit_field(uint64_t source, const uint16_t startBit, return int_result; } -/** - * TODO it would be nice to have a warning if you call with this a value that - * won't fit in the number of bits you've specified it should use. - */ -void set_bit_field(uint64_t* destination, uint64_t value, const uint16_t offset, +bool set_bit_field(uint64_t* destination, uint64_t value, const uint16_t offset, const uint16_t bit_count) { + if(value > bitmask(bit_count)) { + return false; + } + int shiftDistance = EIGHTBYTE_BIT - offset - bit_count; value <<= shiftDistance; *destination &= ~(bitmask(bit_count) << shiftDistance); *destination |= value; + return true; } uint8_t nth_byte(const uint64_t source, const uint16_t byte_index) { diff --git a/src/bitfield/8byte.h b/src/bitfield/8byte.h index 9cbf61a9..36b5fe60 100644 --- a/src/bitfield/8byte.h +++ b/src/bitfield/8byte.h @@ -55,8 +55,11 @@ uint64_t get_bit_field(uint64_t source, const uint16_t offset, * value - the value to set in the bit field. * offset - the starting index of the bit field (beginning from 0). * bit_count - the number of bits to set in the data. + * + * Returns true if the bit_count is enough to fully represent the value, and + * false if it will not fit. */ -void set_bit_field(uint64_t* destination, uint64_t value, const uint16_t offset, +bool set_bit_field(uint64_t* destination, uint64_t value, const uint16_t offset, const uint16_t bit_count); /* Public: Retreive the nth byte out of 8 bytes in a uint64_t. diff --git a/tests/8byte_tests.c b/tests/8byte_tests.c index f4188bfe..64c1a399 100644 --- a/tests/8byte_tests.c +++ b/tests/8byte_tests.c @@ -103,19 +103,26 @@ START_TEST (test_get_off_byte_boundary) ck_assert_int_eq(result, 0x01); } END_TEST +START_TEST (test_set_wont_fit) +{ + uint64_t data = 0; + fail_if(set_bit_field(&data, 100, 0, 1)); +} +END_TEST + START_TEST (test_set_field) { uint64_t data = 0; - set_bit_field(&data, 1, 0, 1); + fail_unless(set_bit_field(&data, 1, 0, 1)); uint64_t result = get_bit_field(data, 0, 1, false); ck_assert_int_eq(result, 0x1); data = 0; - set_bit_field(&data, 1, 1, 1); + fail_unless(set_bit_field(&data, 1, 1, 1)); result = get_bit_field(data, 1, 1, false); ck_assert_int_eq(result, 0x1); data = 0; - set_bit_field(&data, 0xf, 3, 4); + fail_unless(set_bit_field(&data, 0xf, 3, 4)); result = get_bit_field(data, 3, 4, false); ck_assert_int_eq(result, 0xf); } @@ -124,14 +131,14 @@ END_TEST START_TEST (test_set_doesnt_clobber_existing_data) { uint64_t data = 0xFFFC4DF300000000; - set_bit_field(&data, 0x4fc8, 16, 16); + fail_unless(set_bit_field(&data, 0x4fc8, 16, 16)); uint64_t result = get_bit_field(data, 16, 16, false); fail_unless(result == 0x4fc8, "Field retrieved in 0x%llx was 0x%llx instead of 0x%x", data, result, 0xc84f); data = 0x8000000000000000; - set_bit_field(&data, 1, 21, 1); + fail_unless(set_bit_field(&data, 1, 21, 1)); fail_unless(data == 0x8000040000000000LLU, "Expected combined value 0x8000040000000000 but got 0x%llx%llx", data >> 32, data); @@ -141,7 +148,7 @@ END_TEST START_TEST (test_set_off_byte_boundary) { uint64_t data = 0xFFFC4DF300000000; - set_bit_field(&data, 0x12, 12, 8); + fail_unless(set_bit_field(&data, 0x12, 12, 8)); uint64_t result = get_bit_field(data, 12, 12, false); ck_assert_int_eq(result,0x12d); } @@ -150,14 +157,14 @@ END_TEST START_TEST (test_set_odd_number_of_bits) { uint64_t data = 0xFFFC4DF300000000LLU; - set_bit_field(&data, 0x12, 11, 5); + fail_unless(set_bit_field(&data, 0x12, 11, 5)); uint64_t result = get_bit_field(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; - set_bit_field(&data, 0x2, 11, 5); + fail_unless(set_bit_field(&data, 0x2, 11, 5)); result = get_bit_field(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, @@ -202,6 +209,7 @@ Suite* bitfieldSuite(void) { tcase_add_test(tc_core, test_multi_byte); tcase_add_test(tc_core, test_get_multi_byte); tcase_add_test(tc_core, test_get_off_byte_boundary); + tcase_add_test(tc_core, test_set_wont_fit); tcase_add_test(tc_core, test_set_field); tcase_add_test(tc_core, test_set_doesnt_clobber_existing_data); tcase_add_test(tc_core, test_set_off_byte_boundary); -- cgit 1.2.3-korg From 50715d3d8783dd081a403c1e580b34177ffa57bf Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sun, 29 Dec 2013 12:14:29 -0500 Subject: Test parsing boolean. --- README.mkd | 23 +++++++++++++++++++++++ src/canutil/read.h | 8 ++++++++ tests/read_tests.c | 13 ++++++++++++- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/README.mkd b/README.mkd index 0d8efb74..8f6ac5f1 100644 --- a/README.mkd +++ b/README.mkd @@ -1,6 +1,29 @@ CAN Message Utilities for C ============ +## Bitfield Manipulation + +## CAN Signal Encoding + +## CAN Signal Decoding + +The library supports parsing floating point CAN signals as well as booleans. + + uint64_t payload = 0xeb00000000000000; + float result = bitfield_parse_float(payload, + 2, // starting bit + 4, // width of the signal's field + 1001.0, // transformation factor for the signal value + -30000.0); // transformation offset for the signal value + // result == -19990.0 + + bool result = bitfield_parse_bool(payload, + 0, // starting bit + 1, // width of the signal's field + 1.0, // transformation factor for the signal value + 0); // transformation offset for the signal value + // result == true + ## Testing The library includes a test suite that uses the `check` C unit test library. diff --git a/src/canutil/read.h b/src/canutil/read.h index 3742d6d1..028b03a6 100644 --- a/src/canutil/read.h +++ b/src/canutil/read.h @@ -19,6 +19,14 @@ extern "C" { float bitfield_parse_float(uint64_t data, uint8_t bit_offset, uint8_t bit_size, float factor, float offset); +/* Public: Parse a CAN signal from a message and interpret it as a boolean. + * + * signal - The details of the signal to decode and forward. + * data - The raw bytes of the CAN message that contains the signal, assumed + * to be in big-endian byte order from CAN. + * + * Returns false if the value was 0, otherwise true. + */ bool bitfield_parse_bool(uint64_t data, uint8_t bit_offset, uint8_t bit_size, float factor, float offset); diff --git a/tests/read_tests.c b/tests/read_tests.c index 62ced1f9..71b0ab65 100644 --- a/tests/read_tests.c +++ b/tests/read_tests.c @@ -6,18 +6,29 @@ const uint64_t BIG_ENDIAN_TEST_DATA = __builtin_bswap64(0xEB00000000000000); START_TEST (test_parse_float) { - float result = bitfield_parse_float(BIG_ENDIAN_TEST_DATA, 2, 4, 1001.0, -30000.0); + float result = bitfield_parse_float(BIG_ENDIAN_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_parse_bool) +{ + float result = bitfield_parse_bool(BIG_ENDIAN_TEST_DATA, 0, 1, 1.0, 0); + float correctResult = true; + fail_unless(result == correctResult, + "parse is incorrect: %d but should be %d", result, correctResult); +} +END_TEST + 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); suite_add_tcase(s, tc_core); return s; -- cgit 1.2.3-korg From e3bb578a0b11a25b0ae4c805fb7b98b724103b6f Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sun, 29 Dec 2013 13:57:37 -0500 Subject: Test all canutil functions and document in README. --- README.mkd | 28 ++++++++++++++++++++++++---- src/canutil/read.h | 22 +++++++++++++++------- src/canutil/write.c | 10 ++++++---- src/canutil/write.h | 28 ++++++++++++++++++++++++++-- tests/write_tests.c | 14 ++++++++++++++ 5 files changed, 85 insertions(+), 17 deletions(-) diff --git a/README.mkd b/README.mkd index 8f6ac5f1..b96d587b 100644 --- a/README.mkd +++ b/README.mkd @@ -3,26 +3,46 @@ CAN Message Utilities for C ## Bitfield Manipulation + uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; + uint8_t result = getByte(data, sizeof(data), 0); + uint8_t result = getNibble(data, sizeof(data), 0); + fail_unless(copyBitsRightAligned(data, 4, 4, 12, result, 4)); + +## 8 Byte Bitfield Manipulation + +TODO setting bit fields is just copying +TODO bring back old uint64_t implementation of getBitField if it's faster / + simpler + ## CAN Signal Encoding +The library supports encoding floating point CAN signals as well as booleans +into a uint64_t payload. + + uint64_t payload = bitfield_encode_float(1, 1, 3, 1, 0) + // payload == 0x1000000000000000 + + payload = bitfield_encode_bool(true, 1, 3); + // payload == 0x1000000000000000 + ## CAN Signal Decoding The library supports parsing floating point CAN signals as well as booleans. uint64_t payload = 0xeb00000000000000; - float result = bitfield_parse_float(payload, + float float_result = bitfield_parse_float(payload, 2, // starting bit 4, // width of the signal's field 1001.0, // transformation factor for the signal value -30000.0); // transformation offset for the signal value - // result == -19990.0 + // float_result == -19990.0 - bool result = bitfield_parse_bool(payload, + bool bool_result = bitfield_parse_bool(payload, 0, // starting bit 1, // width of the signal's field 1.0, // transformation factor for the signal value 0); // transformation offset for the signal value - // result == true + // bool_result == true ## Testing diff --git a/src/canutil/read.h b/src/canutil/read.h index 028b03a6..865bb278 100644 --- a/src/canutil/read.h +++ b/src/canutil/read.h @@ -10,20 +10,28 @@ extern "C" { /* Public: Parse a CAN signal from a message and apply required transformation. * - * signal - The details of the signal to decode and forward. - * data - The raw bytes of the CAN message that contains the signal, assumed - * to be in big-endian byte order from CAN. + * data - 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 + * 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 final, transformed value of the signal. + * Returns the decoded and transformed value of the signal. */ float bitfield_parse_float(uint64_t data, uint8_t bit_offset, uint8_t bit_size, float factor, float offset); /* Public: Parse a CAN signal from a message and interpret it as a boolean. * - * signal - The details of the signal to decode and forward. - * data - The raw bytes of the CAN message that contains the signal, assumed - * to be in big-endian byte order from CAN. + * data - 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 + * 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. */ diff --git a/src/canutil/write.c b/src/canutil/write.c index 14d2a449..583c2513 100644 --- a/src/canutil/write.c +++ b/src/canutil/write.c @@ -9,11 +9,13 @@ uint64_t bitfield_encode_float(float value, uint8_t bit_offset, uint8_t bit_size raw += 0.5; } uint64_t result = 0; - set_bit_field(&result, (uint64_t)raw, bit_offset, bit_size); + if(!set_bit_field(&result, (uint64_t)raw, bit_offset, bit_size)) { + // debug("%f will not fit in a %d bit field", value, bit_size); + } return result; } -uint64_t bitfield_encode_bool(bool value, uint8_t bit_offset, uint8_t bit_size, - float factor, float offset) { - return bitfield_encode_float(value, offset, factor, bit_offset, bit_size); +uint64_t bitfield_encode_bool(const bool value, const uint8_t bit_offset, + const uint8_t bit_size) { + return bitfield_encode_float(value, bit_offset, bit_size, 1.0, 0); } diff --git a/src/canutil/write.h b/src/canutil/write.h index 3d13b1df..f117a06c 100644 --- a/src/canutil/write.h +++ b/src/canutil/write.h @@ -8,11 +8,35 @@ extern "C" { #endif +/* Public: Encode a floating point number into a fixed point, fixed bit width + * field in a bit array. + * + * value - the floating point value to encode. + * bit_offset - the starting point for the encoded bits in the returned value. + * bit_size - The max width of the field in the resulting bit array. If bit_size + * isn't big enough to store the fixed point version of the value, the bitfeld + * will *not* be set. TODO some error reporting would be nice. + * factor - a factor used to transform from floating to fixed point before + * encoding. Use 1.0 for no factor. + * offset - an offset used to transform from floating to fixed point before + * encoding. Use 0 for no offset. + * + * Returns a big-endian uint64_t with the value encoded as a bitfield. + */ uint64_t bitfield_encode_float(float value, uint8_t bit_offset, uint8_t bit_size, float factor, float offset); -uint64_t bitfield_encode_bool(bool value, uint8_t bit_offset, uint8_t bit_size, - float factor, float offset); +/* Public: Encode a boolean into fixed bit width field in a bit array. + * + * value - the boolean value to encode - true will be 1, false will be 0. + * bit_offset - the starting point for the encoded bits in the returned value. + * bit_size - The max width of the field in the resulting bit array. If bit_size + * isn't big enough to store the fixed point version of the value, the bitfeld + * will *not* be set. TODO some error reporting would be nice. + * + * Returns a big-endian uint64_t with the value encoded as a bitfield. + */ +uint64_t bitfield_encode_bool(const bool value, const uint8_t bit_offset, const uint8_t bit_size); #ifdef __cplusplus } diff --git a/tests/write_tests.c b/tests/write_tests.c index ed555f60..8cc35e21 100644 --- a/tests/write_tests.c +++ b/tests/write_tests.c @@ -6,6 +6,9 @@ START_TEST (test_encode_can_signal) { uint64_t value = bitfield_encode_float(0, 1, 3, 1, 0); ck_assert_int_eq(value, 0); + + value = bitfield_encode_float(1, 1, 3, 1, 0); + ck_assert_int_eq(value, 0x1000000000000000LLU); } END_TEST @@ -16,11 +19,22 @@ START_TEST (test_encode_can_signal_rounding_precision) } END_TEST +START_TEST (test_encode_bool) +{ + uint64_t value = bitfield_encode_bool(true, 1, 3); + ck_assert_int_eq(value, 0x1000000000000000LLU); + value = bitfield_encode_bool(false, 1, 3); + ck_assert_int_eq(value, 0x0000000000000000LLU); +} +END_TEST +// TODO test encode bool + Suite* canwriteSuite(void) { Suite* s = suite_create("write"); TCase *tc_core = tcase_create("core"); tcase_add_checked_fixture(tc_core, NULL, NULL); tcase_add_test(tc_core, test_encode_can_signal); + tcase_add_test(tc_core, test_encode_bool); tcase_add_test(tc_core, test_encode_can_signal_rounding_precision); suite_add_tcase(s, tc_core); -- cgit 1.2.3-korg From e5a2a6b9550319cf05c3a3ae93080b17d322078e Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sun, 29 Dec 2013 14:18:50 -0500 Subject: Document all bitfield functions. --- README.mkd | 35 +++++++++++++++++++++++++++++++---- src/bitfield/8byte.c | 28 +++++++++++++++------------- src/bitfield/8byte.h | 8 ++++++-- src/bitfield/bitarray.c | 4 ++-- tests/8byte_tests.c | 4 ++-- 5 files changed, 56 insertions(+), 23 deletions(-) diff --git a/README.mkd b/README.mkd index b96d587b..76feddbe 100644 --- a/README.mkd +++ b/README.mkd @@ -1,5 +1,12 @@ CAN Message Utilities for C -============ +=========================== + +This is a C library with functions to help encode and decode Controller Area +Network (CAN) message payloads. Some of the bitfield functions may be useful for +other areas, too. + +The header files contain complete function documentation, but to get you +started, here are examples using the API: ## Bitfield Manipulation @@ -8,11 +15,31 @@ CAN Message Utilities for C uint8_t result = getNibble(data, sizeof(data), 0); fail_unless(copyBitsRightAligned(data, 4, 4, 12, result, 4)); -## 8 Byte Bitfield Manipulation +## 8 Byte Bitfield Decoding + + uint64_t data = 0x8000000000000000; + uint64_t result = get_bit_field(data, 0, 1, false); + // result == 0x1 + + data = 0x0402574d555a0401; + result = get_bit_field(data, 16, 32, false); + // result = 0x574d555a; + + data = 0x00000000F34DFCFF; + result = nth_byte(data, 0); + //result = 0x0 + + result = nth_byte(data, 4); + //result = 0xF3 + +## 8 Byte Bitfield Encoding + + uint64_t data = 0; + fail_unless(set_bit_field(&data, 1, 0, 1)); + uint64_t result = get_bit_field(data, 0, 1, false); + ck_assert_int_eq(result, 0x1); TODO setting bit fields is just copying -TODO bring back old uint64_t implementation of getBitField if it's faster / - simpler ## CAN Signal Encoding diff --git a/src/bitfield/8byte.c b/src/bitfield/8byte.c index 3b6b5466..845be8c0 100644 --- a/src/bitfield/8byte.c +++ b/src/bitfield/8byte.c @@ -18,26 +18,28 @@ static uint16_t bits_to_bytes(uint32_t bits) { return byte_count; } -uint64_t get_bit_field(uint64_t source, const uint16_t startBit, +uint64_t get_bit_field(uint64_t source, const uint16_t offset, const uint16_t bit_count, bool big_endian) { - uint8_t result[8] = {0}; + int startByte = offset / CHAR_BIT; + int endByte = (offset + bit_count - 1) / CHAR_BIT; + if(!big_endian) { source = __builtin_bswap64(source); } - copyBitsRightAligned((const uint8_t*)&source, sizeof(source), startBit, - bit_count, result, sizeof(result)); - uint64_t int_result = 0; - if(!big_endian) { - // we need to swap the byte order of the array to get it into a - // uint64_t, but it's been right aligned so we have to be more careful - for(int i = 0; i < bits_to_bytes(bit_count); i++) { - int_result |= result[bits_to_bytes(bit_count) - i - 1] << (CHAR_BIT * i); + uint8_t* bytes = (uint8_t*)&source; + 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++) { + ret = ret << 8; + ret = ret | bytes[i]; } - } else { - int_result = *(uint64_t*)result; } - return int_result; + + ret >>= 8 - find_end_bit(offset + bit_count); + return ret & bitmask(bit_count); } bool set_bit_field(uint64_t* destination, uint64_t value, const uint16_t offset, diff --git a/src/bitfield/8byte.h b/src/bitfield/8byte.h index 36b5fe60..1ee9c0ec 100644 --- a/src/bitfield/8byte.h +++ b/src/bitfield/8byte.h @@ -18,7 +18,7 @@ extern "C" { * * source - the bytes in question. * offset - the starting index of the bit field (beginning from 0). - * numBits - the width of the bit field to extract. + * bit_count - the width of the bit field to extract. * big_endian - if the data passed in is little endian, set this to false and it * will be flipped before grabbing the bit field. * @@ -44,7 +44,7 @@ extern "C" { * * uint64_t value = get_bit_field(data, 2, 4); * - * Returns the value of the requested bit field. + * Returns the value of the requested bit field, right aligned in a uint64_t. */ uint64_t get_bit_field(uint64_t source, const uint16_t offset, const uint16_t bit_count, bool big_endian); @@ -71,6 +71,10 @@ bool set_bit_field(uint64_t* destination, uint64_t value, const uint16_t offset, */ uint8_t nth_byte(const uint64_t source, const uint16_t byte_index); +/* Private: Determine the index of the last bit used. + */ +uint8_t find_end_bit(const uint16_t num_bits); + #ifdef __cplusplus } #endif diff --git a/src/bitfield/bitarray.c b/src/bitfield/bitarray.c index 8fbc941d..f8c23527 100644 --- a/src/bitfield/bitarray.c +++ b/src/bitfield/bitarray.c @@ -113,7 +113,7 @@ bool copyBits(const uint8_t* source_origin, const uint16_t source_length, * * Returns: a bit position from 0 to 7. */ -static uint8_t findEndBit(const uint16_t startBit, const uint16_t numBits) { +uint8_t find_end_bit(const uint16_t numBits) { int endBit = numBits % CHAR_BIT; return endBit == 0 ? CHAR_BIT : endBit; } @@ -125,5 +125,5 @@ bool copyBitsRightAligned(const uint8_t source[], const uint16_t source_length, destination_length, // provide a proper destination offset so the result is right // aligned - CHAR_BIT - findEndBit(offset, bit_count)); + CHAR_BIT - find_end_bit(bit_count)); } diff --git a/tests/8byte_tests.c b/tests/8byte_tests.c index 64c1a399..6166f1d7 100644 --- a/tests/8byte_tests.c +++ b/tests/8byte_tests.c @@ -56,10 +56,10 @@ START_TEST (test_one_byte) uint64_t data = 0xFA00000000000000; uint64_t result = get_bit_field(data, 0, 4, false); fail_unless(result == 0xF, - "First 4 bits in 0x%llx was 0x%llx instead of 0xF", data, result); + "First nibble in 0x%llx was 0x%llx instead of 0xF", data, result); result = get_bit_field(data, 4, 4, false); fail_unless(result == 0xA, - "First 4 bits in 0x%llx was 0x%llx instead of 0xA", data, result); + "Second nibble in 0x%llx was 0x%llx instead of 0xA", data, result); result = get_bit_field(data, 0, 8, false); fail_unless(result == 0xFA, "All bits in 0x%llx were 0x%llx instead of 0x%llx", data, result, data); -- cgit 1.2.3-korg From 3a6af99be9a10f795b84a5783939b86d7102fb63 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sun, 29 Dec 2013 14:20:12 -0500 Subject: Standardize function names to snake_case. --- README.mkd | 6 +++--- src/bitfield/bitarray.c | 6 +++--- src/bitfield/bitfield.c | 6 +++--- src/bitfield/bitfield.h | 14 +++++++------- tests/bitfield_tests.c | 16 ++++++++-------- tests/write_tests.c | 1 - 6 files changed, 24 insertions(+), 25 deletions(-) diff --git a/README.mkd b/README.mkd index 76feddbe..836b151e 100644 --- a/README.mkd +++ b/README.mkd @@ -11,9 +11,9 @@ started, here are examples using the API: ## Bitfield Manipulation uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; - uint8_t result = getByte(data, sizeof(data), 0); - uint8_t result = getNibble(data, sizeof(data), 0); - fail_unless(copyBitsRightAligned(data, 4, 4, 12, result, 4)); + uint8_t result = get_byte(data, sizeof(data), 0); + uint8_t result = get_nibble(data, sizeof(data), 0); + fail_unless(copy_bits_right_aligned(data, 4, 4, 12, result, 4)); ## 8 Byte Bitfield Decoding diff --git a/src/bitfield/bitarray.c b/src/bitfield/bitarray.c index f8c23527..35fc2d9e 100644 --- a/src/bitfield/bitarray.c +++ b/src/bitfield/bitarray.c @@ -20,7 +20,7 @@ static const uint8_t reverse_mask[] = static const uint8_t reverse_mask_xor[] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00 }; -bool copyBits(const uint8_t* source_origin, const uint16_t source_length, +bool copy_bits(const uint8_t* source_origin, const uint16_t source_length, const uint16_t source_offset, uint16_t bit_count, uint8_t* destination_origin, const uint16_t destination_length, const uint16_t destination_offset) { @@ -118,10 +118,10 @@ uint8_t find_end_bit(const uint16_t numBits) { return endBit == 0 ? CHAR_BIT : endBit; } -bool copyBitsRightAligned(const uint8_t source[], const uint16_t source_length, +bool copy_bits_right_aligned(const uint8_t source[], const uint16_t source_length, const uint16_t offset, const uint16_t bit_count, uint8_t* destination, const uint16_t destination_length) { - return copyBits(source, source_length, offset, bit_count, destination, + return copy_bits(source, source_length, offset, bit_count, destination, destination_length, // provide a proper destination offset so the result is right // aligned diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c index 3bf00ac0..7dfa7cd4 100644 --- a/src/bitfield/bitfield.c +++ b/src/bitfield/bitfield.c @@ -5,10 +5,10 @@ #define NIBBLE_SIZE (CHAR_BIT / 2) -uint8_t getNibble(const uint8_t source[], const uint8_t source_length, +uint8_t get_nibble(const uint8_t source[], const uint8_t source_length, const uint8_t nibble_index) { uint8_t byte_index = nibble_index / 2; - uint8_t result = getByte(source, source_length, byte_index); + uint8_t result = get_byte(source, source_length, byte_index); if(nibble_index % 2 == 0) { result >>= NIBBLE_SIZE; } @@ -16,7 +16,7 @@ uint8_t getNibble(const uint8_t source[], const uint8_t source_length, return result; } -uint8_t getByte(const uint8_t source[], const uint8_t source_length, +uint8_t get_byte(const uint8_t source[], const uint8_t source_length, const uint8_t byte_index) { if(byte_index < source_length) { return source[byte_index]; diff --git a/src/bitfield/bitfield.h b/src/bitfield/bitfield.h index 6f5f1c18..52ed143d 100644 --- a/src/bitfield/bitfield.h +++ b/src/bitfield/bitfield.h @@ -17,7 +17,7 @@ extern "C" { * * Returns the retreived nibble, right aligned in a uint8_t. */ -uint8_t getNibble(const uint8_t source[], const uint8_t source_length, +uint8_t get_nibble(const uint8_t source[], const uint8_t source_length, const uint8_t nibble_index); /* Public: Return a single byte from the byte array, with range checking. @@ -28,7 +28,7 @@ uint8_t getNibble(const uint8_t source[], const uint8_t source_length, * * Returns the retreived byte. */ -uint8_t getByte(const uint8_t source[], const uint8_t source_length, +uint8_t get_byte(const uint8_t source[], const uint8_t source_length, const uint8_t byte_index); /* Public: Copy a range of bits from one bit array to another. @@ -44,7 +44,7 @@ uint8_t getByte(const uint8_t source[], const uint8_t source_length, * * uint8_t source[4] = {0x11, 0x22, 0x33, 0x44}; * uint8_t destination[4] = {0}; - * copyBits(source, sizeof(source), 8, 8, destination, + * copy_bits(source, sizeof(source), 8, 8, destination, * sizeof(destination), 0); * // destination[0] == 0x22 * // destination[1] == 0x0 @@ -73,7 +73,7 @@ uint8_t getByte(const uint8_t source[], const uint8_t source_length, * Returns true if the copy was successful and false if the range exceeded the * size of the source or destination, or if the range size negative or 0. */ -bool copyBits(const uint8_t* source_origin, const uint16_t source_length, +bool copy_bits(const uint8_t* source_origin, const uint16_t source_length, const uint16_t source_offset, uint16_t bit_count, uint8_t* destination_origin, const uint16_t destination_length, const uint16_t destination_offset); @@ -88,7 +88,7 @@ bool copyBits(const uint8_t* source_origin, const uint16_t source_length, * * uint8_t source[4] = {0x11, 0x22, 0x33, 0x44}; * uint8_t destination[4] = {0}; - * copyBitsRightAligned(source, sizeof(source), 8, 8, destination, + * copy_bits_right_aligned(source, sizeof(source), 8, 8, destination, * sizeof(destination)); * // destination[0] == 0x0 * // destination[1] == 0x0 @@ -98,13 +98,13 @@ bool copyBits(const uint8_t* source_origin, const uint16_t source_length, * int value = (int)destination; * // value == 0x22 == 32 * - * The arguments are the same as copyBits, but without the destination_offset + * The arguments are the same as copy_bits, but without the destination_offset * option - that's set automatically to right align the result. * * Returns true if the copy was successful and false if the range exceeded the * size of the source or destination, or if the range size negative or 0. */ -bool copyBitsRightAligned(const uint8_t source[], const uint16_t source_length, +bool copy_bits_right_aligned(const uint8_t source[], const uint16_t source_length, const uint16_t offset, const uint16_t bit_count, uint8_t* destination, const uint16_t destination_length); diff --git a/tests/bitfield_tests.c b/tests/bitfield_tests.c index f6287c19..3f54eee1 100644 --- a/tests/bitfield_tests.c +++ b/tests/bitfield_tests.c @@ -5,9 +5,9 @@ START_TEST (test_get_byte) { uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; - uint8_t result = getByte(data, sizeof(data), 0); + uint8_t result = get_byte(data, sizeof(data), 0); ck_assert_int_eq(result, 0x12); - result = getByte(data, sizeof(data), 3); + result = get_byte(data, sizeof(data), 3); ck_assert_int_eq(result, 0x78); } END_TEST @@ -15,11 +15,11 @@ END_TEST START_TEST (test_get_nibble) { uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; - uint8_t result = getNibble(data, sizeof(data), 0); + uint8_t result = get_nibble(data, sizeof(data), 0); ck_assert_int_eq(result, 0x1); - result = getNibble(data, sizeof(data), 1); + result = get_nibble(data, sizeof(data), 1); ck_assert_int_eq(result, 0x2); - result = getNibble(data, sizeof(data), 2); + result = get_nibble(data, sizeof(data), 2); ck_assert_int_eq(result, 0x3); } END_TEST @@ -28,7 +28,7 @@ START_TEST (test_get_bits_out_of_range) { uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; uint8_t result[4]; - fail_if(copyBitsRightAligned(data, 4, 25, 16, result, 4)); + fail_if(copy_bits_right_aligned(data, 4, 25, 16, result, 4)); } END_TEST @@ -36,7 +36,7 @@ START_TEST (test_get_bits) { uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; uint8_t result[4] = {0}; - fail_unless(copyBitsRightAligned(data, 4, 0, 16, result, 4)); + fail_unless(copy_bits_right_aligned(data, 4, 0, 16, result, 4)); ck_assert_int_eq(result[0], 0x12); ck_assert_int_eq(result[1], 0x34); } @@ -46,7 +46,7 @@ START_TEST (test_get_uneven_bits) { uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; uint8_t result[4] = {0}; - fail_unless(copyBitsRightAligned(data, 4, 4, 12, result, 4)); + fail_unless(copy_bits_right_aligned(data, 4, 4, 12, result, 4)); ck_assert_int_eq(result[0], 0x2); ck_assert_int_eq(result[1], 0x34); } diff --git a/tests/write_tests.c b/tests/write_tests.c index 8cc35e21..4091ac4f 100644 --- a/tests/write_tests.c +++ b/tests/write_tests.c @@ -27,7 +27,6 @@ START_TEST (test_encode_bool) ck_assert_int_eq(value, 0x0000000000000000LLU); } END_TEST -// TODO test encode bool Suite* canwriteSuite(void) { Suite* s = suite_create("write"); -- cgit 1.2.3-korg From 0ba19fae04ee48392872a9647a3b711b9115f147 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sun, 29 Dec 2013 14:40:15 -0500 Subject: Add get_byte and get_nibble to 8byte function set. --- README.mkd | 16 ++++++++++++---- src/bitfield/8byte.c | 20 ++++++++++++++------ src/bitfield/8byte.h | 27 ++++++++++++++++++++++++++- src/bitfield/bitfield.c | 2 -- src/bitfield/bitfield.h | 2 ++ tests/8byte_tests.c | 44 +++++++++++++++++++++++++++++++++++++------- 6 files changed, 91 insertions(+), 20 deletions(-) diff --git a/README.mkd b/README.mkd index 836b151e..0ec51263 100644 --- a/README.mkd +++ b/README.mkd @@ -12,8 +12,13 @@ started, here are examples using the API: uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; uint8_t result = get_byte(data, sizeof(data), 0); - uint8_t result = get_nibble(data, sizeof(data), 0); - fail_unless(copy_bits_right_aligned(data, 4, 4, 12, result, 4)); + // result = 0x12; + result = get_nibble(data, sizeof(data), 0); + // result = 0x1; + bool success = copy_bits_right_aligned(data, 4, 4, 12, result, 4) + // success == true + // result[0] == 0x2 + // result[1] == 0x34 ## 8 Byte Bitfield Decoding @@ -26,12 +31,15 @@ started, here are examples using the API: // result = 0x574d555a; data = 0x00000000F34DFCFF; - result = nth_byte(data, 0); + result = eightbyte_get_byte(data, 0, false); //result = 0x0 - result = nth_byte(data, 4); + result = eightbyte_get_byte(data, 4, false); //result = 0xF3 + result = eightbyte_get_nibble(data, 10, false); + //result = 0x4; + ## 8 Byte Bitfield Encoding uint64_t data = 0; diff --git a/src/bitfield/8byte.c b/src/bitfield/8byte.c index 845be8c0..f08f227d 100644 --- a/src/bitfield/8byte.c +++ b/src/bitfield/8byte.c @@ -18,8 +18,21 @@ static uint16_t bits_to_bytes(uint32_t bits) { return byte_count; } +uint8_t eightbyte_get_nibble(const uint64_t source, const uint8_t nibble_index, + const bool big_endian) { + return get_bit_field(source, NIBBLE_SIZE * nibble_index, NIBBLE_SIZE, + big_endian); +} + +uint8_t eightbyte_get_byte(const uint64_t source, const uint8_t byte_index, + const bool big_endian) { + // TODO we're not handling swapped endianness - we could use get_bit_field + // but this might be more efficient + return (source >> (EIGHTBYTE_BIT - ((byte_index + 1) * CHAR_BIT))) & 0xFF; +} + uint64_t get_bit_field(uint64_t source, const uint16_t offset, - const uint16_t bit_count, bool big_endian) { + const uint16_t bit_count, const bool big_endian) { int startByte = offset / CHAR_BIT; int endByte = (offset + bit_count - 1) / CHAR_BIT; @@ -54,8 +67,3 @@ bool set_bit_field(uint64_t* destination, uint64_t value, const uint16_t offset, *destination |= value; return true; } - -uint8_t nth_byte(const uint64_t source, const uint16_t byte_index) { - return (source >> (EIGHTBYTE_BIT - ((byte_index + 1) * CHAR_BIT))) & 0xFF; -} - diff --git a/src/bitfield/8byte.h b/src/bitfield/8byte.h index 1ee9c0ec..818372d5 100644 --- a/src/bitfield/8byte.h +++ b/src/bitfield/8byte.h @@ -47,7 +47,32 @@ extern "C" { * Returns the value of the requested bit field, right aligned in a uint64_t. */ uint64_t get_bit_field(uint64_t source, const uint16_t offset, - const uint16_t bit_count, bool big_endian); + const uint16_t bit_count, const bool big_endian); + +/* Public: Return a single nibble from the payload, with range checking. + * + * source - the source payload. + * nibble_index - the index of the nibble to retreive. The leftmost nibble is + * index 0. + * big_endian - if the data passed in is little endian, set this to false and it + * will be flipped before grabbing the bit field. + * + * Returns the retreived nibble, right aligned in a uint8_t. + */ +uint8_t eightbyte_get_nibble(const uint64_t source, const uint8_t nibble_index, + const bool big_endian); + +/* Public: Return a single byte from the payload, with range checking. + * + * source - the source byte array. + * byte_index - the index of the byte to retreive. The leftmost byte is index 0. + * big_endian - if the data passed in is little endian, set this to false and it + * will be flipped before grabbing the bit field. + * + * Returns the retreived byte. + */ +uint8_t eightbyte_get_byte(const uint64_t source, const uint8_t byte_index, + const bool big_endian); /* Public: Set the bit field in the given data array to the new value. * diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c index 7dfa7cd4..af17d485 100644 --- a/src/bitfield/bitfield.c +++ b/src/bitfield/bitfield.c @@ -3,8 +3,6 @@ #include #include -#define NIBBLE_SIZE (CHAR_BIT / 2) - uint8_t get_nibble(const uint8_t source[], const uint8_t source_length, const uint8_t nibble_index) { uint8_t byte_index = nibble_index / 2; diff --git a/src/bitfield/bitfield.h b/src/bitfield/bitfield.h index 52ed143d..b58e4e59 100644 --- a/src/bitfield/bitfield.h +++ b/src/bitfield/bitfield.h @@ -4,6 +4,8 @@ #include #include +#define NIBBLE_SIZE (CHAR_BIT / 2) + #ifdef __cplusplus extern "C" { #endif diff --git a/tests/8byte_tests.c b/tests/8byte_tests.c index 6166f1d7..572253ce 100644 --- a/tests/8byte_tests.c +++ b/tests/8byte_tests.c @@ -172,31 +172,60 @@ START_TEST (test_set_odd_number_of_bits) } END_TEST -START_TEST(test_nth_byte) +START_TEST(test_eightbyte_get_byte) { uint64_t data = 0x00000000F34DFCFF; - uint8_t result = nth_byte(data, 0); + uint8_t result = eightbyte_get_byte(data, 0, false); uint8_t expected = 0x0; ck_assert_int_eq(result, expected); - result = nth_byte(data, 4); + result = eightbyte_get_byte(data, 4, false); expected = 0xF3; ck_assert_int_eq(result, expected); - result = nth_byte(data, 5); + result = eightbyte_get_byte(data, 5, false); expected = 0x4D; ck_assert_int_eq(result, expected); - result = nth_byte(data, 6); + result = eightbyte_get_byte(data, 6, false); expected = 0xFC; ck_assert_int_eq(result, expected); - result = nth_byte(data, 7); + result = eightbyte_get_byte(data, 7, false); expected = 0xFF; ck_assert_int_eq(result, expected); } END_TEST +START_TEST(test_eightbyte_get_nibble) +{ + uint64_t data = 0x00000000F34DFCFF; + uint8_t result = eightbyte_get_nibble(data, 0, false); + uint8_t expected = 0x0; + ck_assert_int_eq(result, expected); + + result = eightbyte_get_nibble(data, 2, false); + expected = 0x0; + ck_assert_int_eq(result, expected); + + result = eightbyte_get_nibble(data, 8, false); + expected = 0xF; + ck_assert_int_eq(result, expected); + + result = eightbyte_get_nibble(data, 9, false); + expected = 0x3; + ck_assert_int_eq(result, expected); + + result = eightbyte_get_nibble(data, 10, false); + expected = 0x4; + ck_assert_int_eq(result, expected); + + result = eightbyte_get_nibble(data, 13, false); + expected = 0xC; + ck_assert_int_eq(result, expected); +} +END_TEST + Suite* bitfieldSuite(void) { Suite* s = suite_create("bitfield"); TCase *tc_core = tcase_create("core"); @@ -214,7 +243,8 @@ Suite* bitfieldSuite(void) { tcase_add_test(tc_core, test_set_doesnt_clobber_existing_data); tcase_add_test(tc_core, test_set_off_byte_boundary); tcase_add_test(tc_core, test_set_odd_number_of_bits); - tcase_add_test(tc_core, test_nth_byte); + tcase_add_test(tc_core, test_eightbyte_get_nibble); + tcase_add_test(tc_core, test_eightbyte_get_byte); suite_add_tcase(s, tc_core); return s; -- cgit 1.2.3-korg From 418b64039712979dccd8b852cd1a28b857282f11 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sun, 29 Dec 2013 14:43:29 -0500 Subject: Add Travis CI config. --- .travis.yml | 10 ++++++++++ README.mkd | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..9ecb6a44 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: c +compiler: + - gcc +script: make test +before_install: + - sudo apt-get update -qq + - sudo apt-get install check +notifications: + hipchat: + - secure: "ZO/hEAoOTZ4FJytMW0m4LZrsdFVM1/V0Hu13zfj8mdcHkf2MyfxthPDecnn5\naZVn4P8mSSwpp39EnAfa9fBcWcDESnKM1YQKPPGkoxZZHIOd2rYhRv34XfpE\n5qNLkQ/lEPQCBEmvIQ5ZJxsiZjGhO7KxWvdNdruH6cdVCYSh4Xo=" diff --git a/README.mkd b/README.mkd index 0ec51263..c6dfb43c 100644 --- a/README.mkd +++ b/README.mkd @@ -81,7 +81,8 @@ The library supports parsing floating point CAN signals as well as booleans. ## Testing -The library includes a test suite that uses the `check` C unit test library. +The library includes a test suite that uses the `check` C unit test library. It +requires the unit testing library `check`. $ make test -- cgit 1.2.3-korg From 9817085bc127532b9724d80e16343cb78e3ca27a Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sun, 29 Dec 2013 14:46:27 -0500 Subject: Remove function declaration for deleted function. --- src/bitfield/8byte.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/bitfield/8byte.h b/src/bitfield/8byte.h index 818372d5..e4773a51 100644 --- a/src/bitfield/8byte.h +++ b/src/bitfield/8byte.h @@ -87,15 +87,6 @@ uint8_t eightbyte_get_byte(const uint64_t source, const uint8_t byte_index, bool set_bit_field(uint64_t* destination, uint64_t value, const uint16_t offset, const uint16_t bit_count); -/* Public: Retreive the nth byte out of 8 bytes in a uint64_t. - * - * source - the source data to retreive the byte from. - * byte_index - the index of the byte, starting at 0 and assuming big-endian order. - * - * Returns the requested byte from the source bytes. - */ -uint8_t nth_byte(const uint64_t source, const uint16_t byte_index); - /* Private: Determine the index of the last bit used. */ uint8_t find_end_bit(const uint16_t num_bits); -- cgit 1.2.3-korg From 518430f122772016715660086a630ff595e4fcfd Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sun, 29 Dec 2013 15:15:16 -0500 Subject: Add a function to set a single nibble in a bitarray. --- src/bitfield/bitfield.c | 6 ++++++ src/bitfield/bitfield.h | 3 +++ tests/bitfield_tests.c | 15 +++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c index af17d485..ae1be403 100644 --- a/src/bitfield/bitfield.c +++ b/src/bitfield/bitfield.c @@ -21,3 +21,9 @@ uint8_t get_byte(const uint8_t source[], const uint8_t source_length, } return 0; } + +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 b58e4e59..990482fc 100644 --- a/src/bitfield/bitfield.h +++ b/src/bitfield/bitfield.h @@ -110,6 +110,9 @@ bool copy_bits_right_aligned(const uint8_t source[], const uint16_t source_lengt const uint16_t offset, const uint16_t bit_count, uint8_t* destination, const uint16_t destination_length); +bool set_nibble(const uint16_t nibble_index, const uint8_t value, + uint8_t* destination, const uint16_t destination_length); + #ifdef __cplusplus } #endif diff --git a/tests/bitfield_tests.c b/tests/bitfield_tests.c index 3f54eee1..e0646e6a 100644 --- a/tests/bitfield_tests.c +++ b/tests/bitfield_tests.c @@ -12,6 +12,20 @@ START_TEST (test_get_byte) } END_TEST +START_TEST (test_set_nibble) +{ + uint8_t data[4] = {0}; + fail_unless(set_nibble(0, 0x1, data, sizeof(data))); + fail_unless(set_nibble(1, 0x2, data, sizeof(data))); + fail_unless(set_nibble(2, 0x3, data, sizeof(data))); + fail_unless(set_nibble(3, 0x4, data, sizeof(data))); + fail_unless(set_nibble(4, 0x5, data, sizeof(data))); + ck_assert_int_eq(data[0], 0x12); + ck_assert_int_eq(data[1], 0x34); + ck_assert_int_eq(data[2], 0x50); +} +END_TEST + START_TEST (test_get_nibble) { uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; @@ -57,6 +71,7 @@ Suite* bitfieldSuite(void) { TCase *tc_core = tcase_create("core"); tcase_add_test(tc_core, test_get_byte); tcase_add_test(tc_core, test_get_nibble); + tcase_add_test(tc_core, test_set_nibble); tcase_add_test(tc_core, test_get_bits); tcase_add_test(tc_core, test_get_bits_out_of_range); tcase_add_test(tc_core, test_get_uneven_bits); -- cgit 1.2.3-korg From cd74b88432054107c439c4e565bea14840dd9ea5 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Mon, 30 Dec 2013 13:28:39 -0500 Subject: Rename library, it's not really about CAN. --- CHANGELOG.mkd | 2 +- README.mkd | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.mkd b/CHANGELOG.mkd index e710764f..eea48c06 100644 --- a/CHANGELOG.mkd +++ b/CHANGELOG.mkd @@ -1,4 +1,4 @@ -# CAN Message Utilities for C +# Bitfield Utilities in C ## v0.1 diff --git a/README.mkd b/README.mkd index c6dfb43c..749b7995 100644 --- a/README.mkd +++ b/README.mkd @@ -1,9 +1,8 @@ -CAN Message Utilities for C +Bitfield Utilities in C =========================== This is a C library with functions to help encode and decode Controller Area -Network (CAN) message payloads. Some of the bitfield functions may be useful for -other areas, too. +Network (CAN) message payloads or other bitfields. The header files contain complete function documentation, but to get you started, here are examples using the API: -- cgit 1.2.3-korg From 4af52c415f1668fbd168da74d0aca903c592463f Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Tue, 31 Dec 2013 11:40:15 -0500 Subject: Fix byte alignment for right aligned functions. --- src/bitfield/8byte.c | 8 -------- src/bitfield/bitarray.c | 18 +++++++++++++++++- src/bitfield/bitfield.h | 27 +++++++++++++++++++++++++++ tests/bitfield_tests.c | 28 ++++++++++++++++++++++------ 4 files changed, 66 insertions(+), 15 deletions(-) diff --git a/src/bitfield/8byte.c b/src/bitfield/8byte.c index f08f227d..e3eddf20 100644 --- a/src/bitfield/8byte.c +++ b/src/bitfield/8byte.c @@ -10,14 +10,6 @@ uint64_t bitmask(const uint8_t bit_count) { return (((uint64_t)0x1) << bit_count) - 1; } -static uint16_t bits_to_bytes(uint32_t bits) { - uint8_t byte_count = bits / CHAR_BIT; - if(bits % CHAR_BIT != 0) { - ++byte_count; - } - return byte_count; -} - uint8_t eightbyte_get_nibble(const uint64_t source, const uint8_t nibble_index, const bool big_endian) { return get_bit_field(source, NIBBLE_SIZE * nibble_index, NIBBLE_SIZE, diff --git a/src/bitfield/bitarray.c b/src/bitfield/bitarray.c index 35fc2d9e..dcb9a08f 100644 --- a/src/bitfield/bitarray.c +++ b/src/bitfield/bitarray.c @@ -108,6 +108,14 @@ bool copy_bits(const uint8_t* source_origin, const uint16_t source_length, return true; } +uint16_t bits_to_bytes(uint32_t bits) { + uint8_t byte_count = bits / CHAR_BIT; + if(bits % CHAR_BIT != 0) { + ++byte_count; + } + return byte_count; +} + /** * Find the ending bit of a bitfield within the final byte. * @@ -125,5 +133,13 @@ bool copy_bits_right_aligned(const uint8_t source[], const uint16_t source_lengt destination_length, // provide a proper destination offset so the result is right // aligned - CHAR_BIT - find_end_bit(bit_count)); + (destination_length - bits_to_bytes(bit_count)) * CHAR_BIT + + CHAR_BIT - find_end_bit(bit_count)); +} + +bool copy_bytes_right_aligned(const uint8_t source[], const uint16_t source_length, + const uint16_t offset, const uint16_t byte_count, + uint8_t* destination, const uint16_t destination_length) { + return copy_bits_right_aligned(source, source_length, offset * CHAR_BIT, + byte_count * CHAR_BIT, destination, destination_length); } diff --git a/src/bitfield/bitfield.h b/src/bitfield/bitfield.h index 990482fc..ef04d9ca 100644 --- a/src/bitfield/bitfield.h +++ b/src/bitfield/bitfield.h @@ -110,9 +110,36 @@ bool copy_bits_right_aligned(const uint8_t source[], const uint16_t source_lengt const uint16_t offset, const uint16_t bit_count, uint8_t* destination, const uint16_t destination_length); +/* Public: Copy a range of bytes from one byte array to another. + * + * The source and destination do not have to be the same size (as long as the + * desitnation has enough room to fit the range). + * + * source_origin - the source array. + * source_length - the total length of the source array in bytes, + * for range checking. + * source_offset - a byte offset to start the copy from the source array. + * Specify 0 to start from source_origin. + * byte_count - the number of bytes to copy. + * destination_origin - the destination array. + * desitnation_length - the total length of the destination array in bytes, + * for range checking. + * destination_offset - an offset in bytes to start placing the copied range into + * the destination array. Specify 0 to start from the beginning of the + * destination. + * + * Returns true if the copy was successful and false if the range exceeded the + * size of the source or destination, or if the range size negative or 0. + */ +bool copy_bytes_right_aligned(const uint8_t source[], const uint16_t source_length, + const uint16_t offset, const uint16_t byte_count, + uint8_t* destination, const uint16_t destination_length); + bool set_nibble(const uint16_t nibble_index, const uint8_t value, uint8_t* destination, const uint16_t destination_length); +uint16_t bits_to_bytes(uint32_t bits); + #ifdef __cplusplus } #endif diff --git a/tests/bitfield_tests.c b/tests/bitfield_tests.c index e0646e6a..b03882a2 100644 --- a/tests/bitfield_tests.c +++ b/tests/bitfield_tests.c @@ -42,7 +42,8 @@ START_TEST (test_get_bits_out_of_range) { uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; uint8_t result[4]; - fail_if(copy_bits_right_aligned(data, 4, 25, 16, result, 4)); + fail_if(copy_bits_right_aligned(data, sizeof(data), 25, 16, result, + sizeof(result))); } END_TEST @@ -50,9 +51,22 @@ START_TEST (test_get_bits) { uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; uint8_t result[4] = {0}; - fail_unless(copy_bits_right_aligned(data, 4, 0, 16, result, 4)); - ck_assert_int_eq(result[0], 0x12); + fail_unless(copy_bits_right_aligned(data, sizeof(data), 0, 16, result, + sizeof(result))); + ck_assert_int_eq(result[2], 0x12); + ck_assert_int_eq(result[3], 0x34); +} +END_TEST + +START_TEST (test_copy_bytes) +{ + uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; + uint8_t result[4] = {0}; + fail_unless(copy_bytes_right_aligned(data, sizeof(data), 1, 3, result, + sizeof(result))); ck_assert_int_eq(result[1], 0x34); + ck_assert_int_eq(result[2], 0x56); + ck_assert_int_eq(result[3], 0x78); } END_TEST @@ -60,9 +74,10 @@ START_TEST (test_get_uneven_bits) { uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; uint8_t result[4] = {0}; - fail_unless(copy_bits_right_aligned(data, 4, 4, 12, result, 4)); - ck_assert_int_eq(result[0], 0x2); - ck_assert_int_eq(result[1], 0x34); + fail_unless(copy_bits_right_aligned(data, sizeof(data), 4, 12, result, + sizeof(result))); + ck_assert_int_eq(result[2], 0x2); + ck_assert_int_eq(result[3], 0x34); } END_TEST @@ -73,6 +88,7 @@ Suite* bitfieldSuite(void) { tcase_add_test(tc_core, test_get_nibble); tcase_add_test(tc_core, test_set_nibble); tcase_add_test(tc_core, test_get_bits); + tcase_add_test(tc_core, test_copy_bytes); tcase_add_test(tc_core, test_get_bits_out_of_range); tcase_add_test(tc_core, test_get_uneven_bits); suite_add_tcase(s, tc_core); -- cgit 1.2.3-korg From 31caa9c77dbfc438a104fbcab6db5165528c0f89 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Thu, 2 Jan 2014 17:56:20 -0500 Subject: Clarify when you need to specify endianness. --- README.mkd | 18 ++++++++++++------ src/bitfield/8byte.c | 17 +++++++++-------- src/bitfield/8byte.h | 24 +++++++----------------- 3 files changed, 28 insertions(+), 31 deletions(-) diff --git a/README.mkd b/README.mkd index 749b7995..59d5ae5d 100644 --- a/README.mkd +++ b/README.mkd @@ -9,6 +9,8 @@ started, here are examples using the API: ## Bitfield Manipulation +The bitfields are stored in `uint8_t[]`. + uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; uint8_t result = get_byte(data, sizeof(data), 0); // result = 0x12; @@ -19,7 +21,13 @@ started, here are examples using the API: // result[0] == 0x2 // result[1] == 0x34 -## 8 Byte Bitfield Decoding +## 8 Byte Helpers + +If you are dealing with 8 byte CAN messages as `uint64_t`, there are some +additional functions prefixed with `eightbyte_` that may be faster or more +useful. + +### 8 Byte Decoding uint64_t data = 0x8000000000000000; uint64_t result = get_bit_field(data, 0, 1, false); @@ -39,16 +47,14 @@ started, here are examples using the API: result = eightbyte_get_nibble(data, 10, false); //result = 0x4; -## 8 Byte Bitfield Encoding +### 8 Byte Encoding uint64_t data = 0; fail_unless(set_bit_field(&data, 1, 0, 1)); uint64_t result = get_bit_field(data, 0, 1, false); ck_assert_int_eq(result, 0x1); -TODO setting bit fields is just copying - -## CAN Signal Encoding +### CAN Signal Encoding The library supports encoding floating point CAN signals as well as booleans into a uint64_t payload. @@ -59,7 +65,7 @@ into a uint64_t payload. payload = bitfield_encode_bool(true, 1, 3); // payload == 0x1000000000000000 -## CAN Signal Decoding +### CAN Signal Decoding The library supports parsing floating point CAN signals as well as booleans. diff --git a/src/bitfield/8byte.c b/src/bitfield/8byte.c index e3eddf20..d3160934 100644 --- a/src/bitfield/8byte.c +++ b/src/bitfield/8byte.c @@ -11,24 +11,25 @@ uint64_t bitmask(const uint8_t bit_count) { } uint8_t eightbyte_get_nibble(const uint64_t source, const uint8_t nibble_index, - const bool big_endian) { + const bool data_is_big_endian) { return get_bit_field(source, NIBBLE_SIZE * nibble_index, NIBBLE_SIZE, - big_endian); + data_is_big_endian); } -uint8_t eightbyte_get_byte(const uint64_t source, const uint8_t byte_index, - const bool big_endian) { - // TODO we're not handling swapped endianness - we could use get_bit_field - // but this might be more efficient +uint8_t eightbyte_get_byte(uint64_t source, const uint8_t byte_index, + const bool data_is_big_endian) { + if(data_is_big_endian) { + source = __builtin_bswap64(source); + } return (source >> (EIGHTBYTE_BIT - ((byte_index + 1) * CHAR_BIT))) & 0xFF; } uint64_t get_bit_field(uint64_t source, const uint16_t offset, - const uint16_t bit_count, const bool big_endian) { + const uint16_t bit_count, const bool data_is_big_endian) { int startByte = offset / CHAR_BIT; int endByte = (offset + bit_count - 1) / CHAR_BIT; - if(!big_endian) { + if(!data_is_big_endian) { source = __builtin_bswap64(source); } diff --git a/src/bitfield/8byte.h b/src/bitfield/8byte.h index e4773a51..0abc1f07 100644 --- a/src/bitfield/8byte.h +++ b/src/bitfield/8byte.h @@ -8,25 +8,15 @@ extern "C" { #endif -// TODO using uint64_t everywhere for CAN message payload is kind of cute, but -// in actuality a CAN message may have a smaller payload, and it makes all of -// these functions not applicable to other data sizes. It's also fairly -// inefficient on 32-bit platforms. how much work is it to switch vi-firmware -// to using uint8_t*? - /* Public: Reads a subset of bits into a uint64_t. * * source - the bytes in question. * offset - the starting index of the bit field (beginning from 0). * bit_count - the width of the bit field to extract. - * big_endian - if the data passed in is little endian, set this to false and it + * data_is_big_endian - if the data passed in is little endian, set this to false and it * will be flipped before grabbing the bit field. * - * Bit fields are positioned according to big-endian bit layout, but inside the - * bit field, values are represented as little-endian. Therefore, to get the bit - * field, we swap the overall byte order if big_endian == false and - * use the value we find in the field (assuming the embedded platform is little - * endian). + * Bit fields are positioned according to big-endian bit layout. * * For example, the bit layout of the value "42" (i.e. 00101010 set at position * 14 with length 6 is: @@ -47,32 +37,32 @@ extern "C" { * Returns the value of the requested bit field, right aligned in a uint64_t. */ uint64_t get_bit_field(uint64_t source, const uint16_t offset, - const uint16_t bit_count, const bool big_endian); + const uint16_t bit_count, const bool data_is_big_endian); /* Public: Return a single nibble from the payload, with range checking. * * source - the source payload. * nibble_index - the index of the nibble to retreive. The leftmost nibble is * index 0. - * big_endian - if the data passed in is little endian, set this to false and it + * data_is_big_endian - if the data passed in is little endian, set this to false and it * will be flipped before grabbing the bit field. * * Returns the retreived nibble, right aligned in a uint8_t. */ uint8_t eightbyte_get_nibble(const uint64_t source, const uint8_t nibble_index, - const bool big_endian); + const bool data_is_big_endian); /* Public: Return a single byte from the payload, with range checking. * * source - the source byte array. * byte_index - the index of the byte to retreive. The leftmost byte is index 0. - * big_endian - if the data passed in is little endian, set this to false and it + * data_is_big_endian - if the data passed in is little endian, set this to false and it * will be flipped before grabbing the bit field. * * Returns the retreived byte. */ uint8_t eightbyte_get_byte(const uint64_t source, const uint8_t byte_index, - const bool big_endian); + const bool data_is_big_endian); /* Public: Set the bit field in the given data array to the new value. * -- cgit 1.2.3-korg From 8ae1d522ae3074ef2de40c90650d7a15f0023cc2 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Fri, 3 Jan 2014 12:43:58 -0500 Subject: Build with test coverage calculation. --- .gitignore | 1 + Makefile | 32 ++++++++++++++++++++++++-------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index b4225c09..834a305d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .DS_Store *~ *.bin +build diff --git a/Makefile b/Makefile index d841c208..c3c3e5a4 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,11 @@ CC = gcc INCLUDES = -Isrc -CFLAGS = $(INCLUDES) -c -w -Wall -Werror -g -ggdb -std=gnu99 -LDFLAGS = +CFLAGS = $(INCLUDES) -c -w -Wall -Werror -g -ggdb -std=gnu++0x -coverage +LDFLAGS = -coverage -lm LDLIBS = -lcheck TEST_DIR = tests +TEST_OBJDIR = build # Guard against \r\n line endings only in Cygwin OSTYPE := $(shell uname) @@ -17,20 +18,35 @@ endif SRC = $(wildcard src/**/*.c) OBJS = $(SRC:.c=.o) -TEST_SRC = $(wildcard $(TEST_DIR)/*.c) -TEST_OBJS = $(TEST_SRC:.c=.o) -TESTS=$(patsubst %.c,%.bin,$(TEST_SRC)) +OBJS = $(patsubst %,$(TEST_OBJDIR)/%,$(SRC:.c=.o)) +TEST_SRC = $(wildcard $(TEST_DIR)/*_tests.c) +TESTS=$(patsubst %.c,$(TEST_OBJDIR)/%.bin,$(TEST_SRC)) all: $(OBJS) test: $(TESTS) @set -o $(TEST_SET_OPTS) >/dev/null 2>&1 @export SHELLOPTS - @sh runtests.sh $(TEST_DIR) + @sh runtests.sh $(TEST_OBJDIR)/$(TEST_DIR) -$(TEST_DIR)/%.bin: $(TEST_DIR)/%.o $(OBJS) +COVERAGE_INFO_FILENAME = coverage.info +COVERAGE_INFO_PATH = $(TEST_OBJDIR)/$(COVERAGE_INFO_FILENAME) +coverage: + @lcov --base-directory . --directory $(TEST_OBJDIR) --zerocounters -q + @make clean + @make test + @lcov --base-directory . --directory $(TEST_OBJDIR) -c -o $(TEST_OBJDIR)/coverage.info + @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)" + +$(TEST_OBJDIR)/%.o: %.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) $(CC_SYMBOLS) $(INCLUDES) -o $@ $< + +$(TEST_OBJDIR)/%.bin: $(TEST_OBJDIR)/%.o $(OBJS) $(TEST_SUPPORT_OBJS) @mkdir -p $(dir $@) $(CC) $(LDFLAGS) $(CC_SYMBOLS) $(INCLUDES) -o $@ $^ $(LDLIBS) clean: - rm -rf **/*.o $(TEST_DIR)/*.bin + rm -rf $(TEST_OBJDIR) -- cgit 1.2.3-korg From 09dc97c24f9f9a9c2638405167bffe339f666e2a Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Fri, 3 Jan 2014 12:45:27 -0500 Subject: Document how to run coverage. --- README.mkd | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.mkd b/README.mkd index 59d5ae5d..d16a8931 100644 --- a/README.mkd +++ b/README.mkd @@ -91,6 +91,11 @@ requires the unit testing library `check`. $ make test +You can also see the test coverage if you have `lcov` installed and the +`BROWSER` environment variable set to your choice of web browsers: + + $ BROWSER=google-chrome-stable make coverage + ## Authors Chris Peplin cpeplin@ford.com -- cgit 1.2.3-korg From 921b43ea8aaa377a42a11cede653165ec84d8aa4 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Fri, 3 Jan 2014 22:51:54 -0500 Subject: Fix some implicitly defined functions - import proper headers. --- src/bitfield/8byte.c | 4 ---- src/bitfield/bitfield.c | 4 ++++ src/bitfield/bitfield.h | 6 ++++++ src/canutil/read.c | 2 ++ src/canutil/write.c | 3 ++- tests/8byte_tests.c | 3 --- 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/bitfield/8byte.c b/src/bitfield/8byte.c index d3160934..bfceb788 100644 --- a/src/bitfield/8byte.c +++ b/src/bitfield/8byte.c @@ -6,10 +6,6 @@ #define EIGHTBYTE_BIT (8 * sizeof(uint64_t)) -uint64_t bitmask(const uint8_t bit_count) { - return (((uint64_t)0x1) << bit_count) - 1; -} - uint8_t eightbyte_get_nibble(const uint64_t source, const uint8_t nibble_index, const bool data_is_big_endian) { return get_bit_field(source, NIBBLE_SIZE * nibble_index, NIBBLE_SIZE, diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c index ae1be403..3b0c5fdd 100644 --- a/src/bitfield/bitfield.c +++ b/src/bitfield/bitfield.c @@ -3,6 +3,10 @@ #include #include +uint64_t bitmask(const uint8_t bit_count) { + return (((uint64_t)0x1) << bit_count) - 1; +} + uint8_t get_nibble(const uint8_t source[], const uint8_t source_length, const uint8_t nibble_index) { uint8_t byte_index = nibble_index / 2; diff --git a/src/bitfield/bitfield.h b/src/bitfield/bitfield.h index ef04d9ca..5dd976f0 100644 --- a/src/bitfield/bitfield.h +++ b/src/bitfield/bitfield.h @@ -138,8 +138,14 @@ bool copy_bytes_right_aligned(const uint8_t source[], const uint16_t source_leng bool set_nibble(const uint16_t nibble_index, const uint8_t value, uint8_t* destination, const uint16_t destination_length); +/* Private: + */ uint16_t bits_to_bytes(uint32_t bits); +/* Private: + */ +uint64_t bitmask(const uint8_t bit_count); + #ifdef __cplusplus } #endif diff --git a/src/canutil/read.c b/src/canutil/read.c index 5e882c3d..fddf75e3 100644 --- a/src/canutil/read.c +++ b/src/canutil/read.c @@ -1,4 +1,6 @@ +#include #include +#include float bitfield_parse_float(uint64_t data, uint8_t bit_offset, uint8_t bit_size, float factor, float offset) { diff --git a/src/canutil/write.c b/src/canutil/write.c index 583c2513..12c8fa28 100644 --- a/src/canutil/write.c +++ b/src/canutil/write.c @@ -1,5 +1,6 @@ -#include "write.h" +#include #include +#include uint64_t bitfield_encode_float(float value, uint8_t bit_offset, uint8_t bit_size, float factor, float offset) { diff --git a/tests/8byte_tests.c b/tests/8byte_tests.c index 572253ce..de5adfa7 100644 --- a/tests/8byte_tests.c +++ b/tests/8byte_tests.c @@ -4,9 +4,6 @@ START_TEST (test_large_bitmask) { - // yeah, this isn't a public method but I wanted to unit test it to track - // down a bug - extern uint64_t bitmask(int numBits); uint64_t result = bitmask(32); fail_if(result != 0xffffffff); } -- cgit 1.2.3-korg From 6f3a81ed8287357b54aad16bff27495c6eaca6df Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Fri, 3 Jan 2014 23:45:40 -0500 Subject: Checkpoint commit renaming some functions for clarity. --- src/bitfield/8byte.c | 4 ++-- src/bitfield/8byte.h | 10 +++++----- src/canutil/read.c | 16 +++++++++++----- src/canutil/read.h | 10 +++++++--- src/canutil/write.c | 14 +++++++++++--- src/canutil/write.h | 18 +++++++++++------- tests/8byte_tests.c | 40 ++++++++++++++++++++-------------------- tests/read_tests.c | 4 ++-- tests/write_tests.c | 10 +++++----- 9 files changed, 74 insertions(+), 52 deletions(-) diff --git a/src/bitfield/8byte.c b/src/bitfield/8byte.c index bfceb788..76dccc75 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 get_bit_field(source, NIBBLE_SIZE * nibble_index, NIBBLE_SIZE, + return eightbyte_get_bit_field(source, NIBBLE_SIZE * nibble_index, NIBBLE_SIZE, data_is_big_endian); } @@ -20,7 +20,7 @@ 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 get_bit_field(uint64_t source, const uint16_t offset, +uint64_t eightbyte_get_bit_field(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; diff --git a/src/bitfield/8byte.h b/src/bitfield/8byte.h index 0abc1f07..194007c8 100644 --- a/src/bitfield/8byte.h +++ b/src/bitfield/8byte.h @@ -36,7 +36,7 @@ extern "C" { * * Returns the value of the requested bit field, right aligned in a uint64_t. */ -uint64_t get_bit_field(uint64_t source, const uint16_t offset, +uint64_t eightbyte_get_bit_field(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. @@ -50,7 +50,7 @@ uint64_t get_bit_field(uint64_t source, const uint16_t offset, * Returns the retreived nibble, right aligned in a uint8_t. */ uint8_t eightbyte_get_nibble(const uint64_t source, const uint8_t nibble_index, - const bool data_is_big_endian); + const bool data_is_big_endian); /* Public: Return a single byte from the payload, with range checking. * @@ -62,7 +62,7 @@ uint8_t eightbyte_get_nibble(const uint64_t source, const uint8_t nibble_index, * Returns the retreived byte. */ uint8_t eightbyte_get_byte(const uint64_t source, const uint8_t byte_index, - const bool data_is_big_endian); + const bool data_is_big_endian); /* Public: Set the bit field in the given data array to the new value. * @@ -74,8 +74,8 @@ uint8_t eightbyte_get_byte(const uint64_t source, const uint8_t byte_index, * Returns true if the bit_count is enough to fully represent the value, and * false if it will not fit. */ -bool set_bit_field(uint64_t* destination, uint64_t value, const uint16_t offset, - const uint16_t bit_count); +bool eightbyte_set_bit_field(uint64_t* destination, uint64_t value, + const uint16_t offset, const uint16_t bit_count); /* Private: Determine the index of the last bit used. */ diff --git a/src/canutil/read.c b/src/canutil/read.c index fddf75e3..4864a60f 100644 --- a/src/canutil/read.c +++ b/src/canutil/read.c @@ -2,15 +2,21 @@ #include #include -float bitfield_parse_float(uint64_t data, uint8_t bit_offset, uint8_t bit_size, +float eightbyte_parse_float(uint64_t data, uint8_t bit_offset, uint8_t bit_size, float factor, float offset) { - uint64_t raw = get_bit_field(data, bit_offset, - bit_size, true); + uint64_t raw = eightbyte_get_bit_field(data, bit_offset, bit_size, true); return raw * factor + offset; } -bool bitfield_parse_bool(uint64_t data, uint8_t bit_offset, uint8_t bit_size, +bool eightbyte_parse_bool(uint64_t data, uint8_t bit_offset, uint8_t bit_size, float factor, float offset) { - float value = bitfield_parse_float(data, bit_offset, bit_size, factor, offset); + float value = eightbyte_parse_float(data, bit_offset, bit_size, factor, offset); return value == 0.0 ? false : true; } + +float bitfield_parse_float(const uint8_t data[], const uint16_t size, + const uint8_t bit_offset, const uint8_t bit_size, const float factor, + const float offset) { + //TODO + return 0; +} diff --git a/src/canutil/read.h b/src/canutil/read.h index 865bb278..bf6c0ade 100644 --- a/src/canutil/read.h +++ b/src/canutil/read.h @@ -20,8 +20,12 @@ extern "C" { * * Returns the decoded and transformed value of the signal. */ -float bitfield_parse_float(uint64_t data, uint8_t bit_offset, uint8_t bit_size, - float factor, float offset); +float eightbyte_parse_float(const uint64_t data, 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, + 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. * @@ -35,7 +39,7 @@ float bitfield_parse_float(uint64_t data, uint8_t bit_offset, uint8_t bit_size, * * Returns false if the value was 0, otherwise true. */ -bool bitfield_parse_bool(uint64_t data, uint8_t bit_offset, uint8_t bit_size, +bool eightbyte_parse_bool(uint64_t data, uint8_t bit_offset, uint8_t bit_size, float factor, float offset); #ifdef __cplusplus diff --git a/src/canutil/write.c b/src/canutil/write.c index 12c8fa28..09e6caa3 100644 --- a/src/canutil/write.c +++ b/src/canutil/write.c @@ -2,11 +2,13 @@ #include #include -uint64_t bitfield_encode_float(float value, uint8_t bit_offset, uint8_t bit_size, +uint64_t eightbyte_encode_float(float value, uint8_t bit_offset, uint8_t bit_size, float factor, float offset) { float raw = (value - offset) / factor; if(raw > 0) { // round up to avoid losing precision when we cast to an int + // TODO do we need a way to encode an int back to a signal without any + // rounding? raw += 0.5; } uint64_t result = 0; @@ -16,7 +18,13 @@ uint64_t bitfield_encode_float(float value, uint8_t bit_offset, uint8_t bit_size return result; } -uint64_t bitfield_encode_bool(const bool value, const uint8_t bit_offset, +uint64_t eightbyte_encode_bool(const bool value, const uint8_t bit_offset, const uint8_t bit_size) { - return bitfield_encode_float(value, bit_offset, bit_size, 1.0, 0); + return eightbyte_encode_float(value, bit_offset, bit_size, 1.0, 0); +} + +bool bitfield_encode_float(float value, uint8_t bit_offset, + uint8_t bit_size, float factor, float offset, uint8_t destination[]) { + // TODO + return 0; } diff --git a/src/canutil/write.h b/src/canutil/write.h index f117a06c..8fd18cdb 100644 --- a/src/canutil/write.h +++ b/src/canutil/write.h @@ -14,8 +14,8 @@ extern "C" { * value - the floating point value to encode. * bit_offset - the starting point for the encoded bits in the returned value. * bit_size - The max width of the field in the resulting bit array. If bit_size - * isn't big enough to store the fixed point version of the value, the bitfeld - * will *not* be set. TODO some error reporting would be nice. + * isn't big enough to store the fixed point version of the value, the + * bitfeld will *not* be set. TODO some error reporting would be nice. * factor - a factor used to transform from floating to fixed point before * encoding. Use 1.0 for no factor. * offset - an offset used to transform from floating to fixed point before @@ -23,20 +23,24 @@ extern "C" { * * Returns a big-endian uint64_t with the value encoded as a bitfield. */ -uint64_t bitfield_encode_float(float value, uint8_t bit_offset, uint8_t bit_size, - float factor, float offset); +uint64_t eightbyte_encode_float(float value, uint8_t bit_offset, + uint8_t bit_size, float factor, float offset); + +bool bitfield_encode_float(float value, uint8_t bit_offset, + uint8_t bit_size, float factor, float offset, uint8_t destination[]); /* Public: Encode a boolean into fixed bit width field in a bit array. * * value - the boolean value to encode - true will be 1, false will be 0. * bit_offset - the starting point for the encoded bits in the returned value. * bit_size - The max width of the field in the resulting bit array. If bit_size - * isn't big enough to store the fixed point version of the value, the bitfeld - * will *not* be set. TODO some error reporting would be nice. + * isn't big enough to store the fixed point version of the value, the + * bitfeld will *not* be set. TODO some error reporting would be nice. * * Returns a big-endian uint64_t with the value encoded as a bitfield. */ -uint64_t bitfield_encode_bool(const bool value, const uint8_t bit_offset, const uint8_t bit_size); +uint64_t eightbyte_encode_bool(const bool value, const uint8_t bit_offset, + const uint8_t bit_size); #ifdef __cplusplus } diff --git a/tests/8byte_tests.c b/tests/8byte_tests.c index de5adfa7..5ebb0db0 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 = get_bit_field(data, 0, 1, false); + uint64_t result = eightbyte_get_bit_field(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 = get_bit_field(data, 0, 1, false); + uint64_t result = eightbyte_get_bit_field(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 = get_bit_field(data, 16, 32, false); + uint64_t result = eightbyte_get_bit_field(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 = get_bit_field(data, 16, 16, false); + uint64_t result = eightbyte_get_bit_field(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 = get_bit_field(data, 0, 4, false); + uint64_t result = eightbyte_get_bit_field(data, 0, 4, false); fail_unless(result == 0xF, "First nibble in 0x%llx was 0x%llx instead of 0xF", data, result); - result = get_bit_field(data, 4, 4, false); + result = eightbyte_get_bit_field(data, 4, 4, false); fail_unless(result == 0xA, "Second nibble in 0x%llx was 0x%llx instead of 0xA", data, result); - result = get_bit_field(data, 0, 8, false); + result = eightbyte_get_bit_field(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 = get_bit_field(data, 0, 4, false); + uint64_t result = eightbyte_get_bit_field(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 = get_bit_field(data, 4, 4, false); + result = eightbyte_get_bit_field(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 = get_bit_field(data, 8, 4, false); + result = eightbyte_get_bit_field(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 = get_bit_field(data, 12, 4, false); + result = eightbyte_get_bit_field(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 = get_bit_field(data, 0, 9, false); + uint64_t result = eightbyte_get_bit_field(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 = get_bit_field(data, 12, 8, false); + uint64_t result = eightbyte_get_bit_field(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 = get_bit_field(data, 0, 1, false); + uint64_t result = eightbyte_get_bit_field(data, 0, 1, false); ck_assert_int_eq(result, 0x1); data = 0; fail_unless(set_bit_field(&data, 1, 1, 1)); - result = get_bit_field(data, 1, 1, false); + result = eightbyte_get_bit_field(data, 1, 1, false); ck_assert_int_eq(result, 0x1); data = 0; fail_unless(set_bit_field(&data, 0xf, 3, 4)); - result = get_bit_field(data, 3, 4, false); + result = eightbyte_get_bit_field(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 = get_bit_field(data, 16, 16, false); + uint64_t result = eightbyte_get_bit_field(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 = get_bit_field(data, 12, 12, false); + uint64_t result = eightbyte_get_bit_field(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 = get_bit_field(data, 11, 5, false); + uint64_t result = eightbyte_get_bit_field(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 = get_bit_field(data, 11, 5, false); + result = eightbyte_get_bit_field(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 71b0ab65..1cde4612 100644 --- a/tests/read_tests.c +++ b/tests/read_tests.c @@ -6,7 +6,7 @@ const uint64_t BIG_ENDIAN_TEST_DATA = __builtin_bswap64(0xEB00000000000000); START_TEST (test_parse_float) { - float result = bitfield_parse_float(BIG_ENDIAN_TEST_DATA, 2, 4, 1001.0, + float result = eightbyte_parse_float(BIG_ENDIAN_TEST_DATA, 2, 4, 1001.0, -30000.0); float correctResult = 0xA * 1001.0 - 30000.0; fail_unless(result == correctResult, @@ -16,7 +16,7 @@ END_TEST START_TEST (test_parse_bool) { - float result = bitfield_parse_bool(BIG_ENDIAN_TEST_DATA, 0, 1, 1.0, 0); + float result = eightbyte_parse_bool(BIG_ENDIAN_TEST_DATA, 0, 1, 1.0, 0); float correctResult = true; fail_unless(result == correctResult, "parse is incorrect: %d but should be %d", result, correctResult); diff --git a/tests/write_tests.c b/tests/write_tests.c index 4091ac4f..8f34a468 100644 --- a/tests/write_tests.c +++ b/tests/write_tests.c @@ -4,26 +4,26 @@ START_TEST (test_encode_can_signal) { - uint64_t value = bitfield_encode_float(0, 1, 3, 1, 0); + uint64_t value = eightbyte_encode_float(0, 1, 3, 1, 0); ck_assert_int_eq(value, 0); - value = bitfield_encode_float(1, 1, 3, 1, 0); + value = eightbyte_encode_float(1, 1, 3, 1, 0); ck_assert_int_eq(value, 0x1000000000000000LLU); } END_TEST START_TEST (test_encode_can_signal_rounding_precision) { - uint64_t value = bitfield_encode_float(50, 2, 19, 0.001, 0); + uint64_t value = eightbyte_encode_float(50, 2, 19, 0.001, 0); ck_assert_int_eq(value, 0x061a800000000000LLU); } END_TEST START_TEST (test_encode_bool) { - uint64_t value = bitfield_encode_bool(true, 1, 3); + uint64_t value = eightbyte_encode_bool(true, 1, 3); ck_assert_int_eq(value, 0x1000000000000000LLU); - value = bitfield_encode_bool(false, 1, 3); + value = eightbyte_encode_bool(false, 1, 3); ck_assert_int_eq(value, 0x0000000000000000LLU); } END_TEST -- cgit 1.2.3-korg From 08db5c9eb826f7aa0dba36cbef8011d7bc6b55a5 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sat, 4 Jan 2014 10:51:16 -0500 Subject: Add a get_bitfield function for byte arrays. --- Makefile | 3 ++- README.mkd | 6 +++--- src/bitfield/8byte.c | 10 ++++++---- src/bitfield/8byte.h | 4 ++-- src/bitfield/bitfield.c | 18 ++++++++++++++++++ src/bitfield/bitfield.h | 34 +++++++++++++++++++++++++++++++++- src/canutil/read.c | 18 ++++++++++++++---- src/canutil/read.h | 42 +++++++++++++++++++++++++++++++++++++----- tests/8byte_tests.c | 40 ++++++++++++++++++++-------------------- tests/read_tests.c | 35 +++++++++++++++++++++++++++++------ 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 #include #include +#include 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 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; -- cgit 1.2.3-korg From 57ea37a8fad405df23256144367b6a18a5ab1580 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sat, 4 Jan 2014 11:12:11 -0500 Subject: Use more portable endinaness macros to check architecture. --- src/bitfield/bitfield.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c index 52f368f5..dddb0ee2 100644 --- a/src/bitfield/bitfield.c +++ b/src/bitfield/bitfield.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include uint64_t bitmask(const uint8_t bit_count) { return (((uint64_t)0x1) << bit_count) - 1; @@ -40,7 +40,10 @@ uint64_t get_bitfield(const uint8_t source[], const uint8_t source_length, } combined; copy_bits_right_aligned(source, source_length, offset, bit_count, combined.bytes, sizeof(combined.bytes)); - return htobe64(combined.whole); + if(BYTE_ORDER == LITTLE_ENDIAN) { + combined.whole = __builtin_bswap64(combined.whole); + } + return combined.whole; } bool set_nibble(const uint16_t nibble_index, const uint8_t value, -- cgit 1.2.3-korg From 561145ed1f4f281ce47f3daaf0b1ec033c0b0402 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sat, 4 Jan 2014 11:12:21 -0500 Subject: Standardize names for functions. --- README.mkd | 16 ++++++++-------- src/bitfield/8byte.c | 2 +- src/bitfield/8byte.h | 2 +- src/bitfield/bitfield.h | 2 +- src/canutil/write.c | 2 +- tests/8byte_tests.c | 18 +++++++++--------- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/README.mkd b/README.mkd index 0cad3d21..99ede1ad 100644 --- a/README.mkd +++ b/README.mkd @@ -30,11 +30,11 @@ useful. ### 8 Byte Decoding uint64_t data = 0x8000000000000000; - uint64_t result = get_bitfield(data, 0, 1, false); + uint64_t result = eightbyte_get_bitfield(data, 0, 1, false); // result == 0x1 data = 0x0402574d555a0401; - result = get_bitfield(data, 16, 32, false); + result = eightbyte_get_bitfield(data, 16, 32, false); // result = 0x574d555a; data = 0x00000000F34DFCFF; @@ -50,8 +50,8 @@ useful. ### 8 Byte Encoding uint64_t data = 0; - fail_unless(set_bit_field(&data, 1, 0, 1)); - uint64_t result = get_bitfield(data, 0, 1, false); + fail_unless(8byte_set_bitfield(&data, 1, 0, 1)); + uint64_t result = eightbyte_get_bitfield(data, 0, 1, false); ck_assert_int_eq(result, 0x1); ### CAN Signal Encoding @@ -59,10 +59,10 @@ useful. The library supports encoding floating point CAN signals as well as booleans into a uint64_t payload. - uint64_t payload = bitfield_encode_float(1, 1, 3, 1, 0) + uint64_t payload = eightbyte_encode_float(1, 1, 3, 1, 0) // payload == 0x1000000000000000 - payload = bitfield_encode_bool(true, 1, 3); + payload = eightbyte_encode_bool(true, 1, 3); // payload == 0x1000000000000000 ### CAN Signal Decoding @@ -70,14 +70,14 @@ into a uint64_t payload. The library supports parsing floating point CAN signals as well as booleans. uint64_t payload = 0xeb00000000000000; - float float_result = bitfield_parse_float(payload, + float float_result = eightbyte_parse_float(payload, 2, // starting bit 4, // width of the signal's field 1001.0, // transformation factor for the signal value -30000.0); // transformation offset for the signal value // float_result == -19990.0 - bool bool_result = bitfield_parse_bool(payload, + bool bool_result = eightbyte_parse_bool(payload, 0, // starting bit 1, // width of the signal's field 1.0, // transformation factor for the signal value diff --git a/src/bitfield/8byte.c b/src/bitfield/8byte.c index 3c555f08..5f310425 100644 --- a/src/bitfield/8byte.c +++ b/src/bitfield/8byte.c @@ -46,7 +46,7 @@ uint64_t eightbyte_get_bitfield(uint64_t source, const uint16_t offset, return ret & bitmask(bit_count); } -bool set_bit_field(uint64_t* destination, uint64_t value, const uint16_t offset, +bool eightbyte_set_bitfield(uint64_t* destination, uint64_t value, const uint16_t offset, const uint16_t bit_count) { if(value > bitmask(bit_count)) { return false; diff --git a/src/bitfield/8byte.h b/src/bitfield/8byte.h index ab775caa..2916c218 100644 --- a/src/bitfield/8byte.h +++ b/src/bitfield/8byte.h @@ -74,7 +74,7 @@ uint8_t eightbyte_get_byte(const uint64_t source, const uint8_t byte_index, * Returns true if the bit_count is enough to fully represent the value, and * false if it will not fit. */ -bool eightbyte_set_bit_field(uint64_t* destination, uint64_t value, +bool eightbyte_set_bitfield(uint64_t* destination, uint64_t value, const uint16_t offset, const uint16_t bit_count); /* Private: Determine the index of the last bit used. diff --git a/src/bitfield/bitfield.h b/src/bitfield/bitfield.h index 80f31243..a080c866 100644 --- a/src/bitfield/bitfield.h +++ b/src/bitfield/bitfield.h @@ -37,7 +37,7 @@ extern "C" { * * 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, +uint64_t get_bitfield(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. diff --git a/src/canutil/write.c b/src/canutil/write.c index 09e6caa3..5b91aaf9 100644 --- a/src/canutil/write.c +++ b/src/canutil/write.c @@ -12,7 +12,7 @@ uint64_t eightbyte_encode_float(float value, uint8_t bit_offset, uint8_t bit_siz raw += 0.5; } uint64_t result = 0; - if(!set_bit_field(&result, (uint64_t)raw, bit_offset, bit_size)) { + if(!eightbyte_set_bitfield(&result, (uint64_t)raw, bit_offset, bit_size)) { // debug("%f will not fit in a %d bit field", value, bit_size); } return result; diff --git a/tests/8byte_tests.c b/tests/8byte_tests.c index 12ff417d..51e927e4 100644 --- a/tests/8byte_tests.c +++ b/tests/8byte_tests.c @@ -103,23 +103,23 @@ START_TEST (test_get_off_byte_boundary) START_TEST (test_set_wont_fit) { uint64_t data = 0; - fail_if(set_bit_field(&data, 100, 0, 1)); + fail_if(eightbyte_set_bitfield(&data, 100, 0, 1)); } END_TEST START_TEST (test_set_field) { uint64_t data = 0; - fail_unless(set_bit_field(&data, 1, 0, 1)); + fail_unless(eightbyte_set_bitfield(&data, 1, 0, 1)); 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)); + fail_unless(eightbyte_set_bitfield(&data, 1, 1, 1)); 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)); + fail_unless(eightbyte_set_bitfield(&data, 0xf, 3, 4)); result = eightbyte_get_bitfield(data, 3, 4, false); ck_assert_int_eq(result, 0xf); } @@ -128,14 +128,14 @@ END_TEST START_TEST (test_set_doesnt_clobber_existing_data) { uint64_t data = 0xFFFC4DF300000000; - fail_unless(set_bit_field(&data, 0x4fc8, 16, 16)); + fail_unless(eightbyte_set_bitfield(&data, 0x4fc8, 16, 16)); 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); data = 0x8000000000000000; - fail_unless(set_bit_field(&data, 1, 21, 1)); + fail_unless(eightbyte_set_bitfield(&data, 1, 21, 1)); fail_unless(data == 0x8000040000000000LLU, "Expected combined value 0x8000040000000000 but got 0x%llx%llx", data >> 32, data); @@ -145,7 +145,7 @@ END_TEST START_TEST (test_set_off_byte_boundary) { uint64_t data = 0xFFFC4DF300000000; - fail_unless(set_bit_field(&data, 0x12, 12, 8)); + fail_unless(eightbyte_set_bitfield(&data, 0x12, 12, 8)); uint64_t result = eightbyte_get_bitfield(data, 12, 12, false); ck_assert_int_eq(result,0x12d); } @@ -154,14 +154,14 @@ END_TEST START_TEST (test_set_odd_number_of_bits) { uint64_t data = 0xFFFC4DF300000000LLU; - fail_unless(set_bit_field(&data, 0x12, 11, 5)); + fail_unless(eightbyte_set_bitfield(&data, 0x12, 11, 5)); 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)); + fail_unless(eightbyte_set_bitfield(&data, 0x2, 11, 5)); 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, -- cgit 1.2.3-korg From 28e30830755758d13458c05ebe2a8db5dc9f43a0 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sat, 4 Jan 2014 11:32:15 -0500 Subject: Build with GNU89 standard for greater compatibility. --- Makefile | 2 +- src/bitfield/8byte.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 89fbf25a..d831b5ad 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc INCLUDES = -Isrc -CFLAGS = $(INCLUDES) -c -w -Wall -Werror -g -ggdb -std=gnu99 -coverage +CFLAGS = $(INCLUDES) -c -w -Wall -Werror -g -ggdb -coverage LDFLAGS = -coverage -lm LDLIBS = -lcheck diff --git a/src/bitfield/8byte.c b/src/bitfield/8byte.c index 5f310425..72f7e32b 100644 --- a/src/bitfield/8byte.c +++ b/src/bitfield/8byte.c @@ -36,7 +36,8 @@ uint64_t eightbyte_get_bitfield(uint64_t source, const uint16_t offset, uint64_t ret = bytes[startByte]; if(startByte != endByte) { // The lowest byte address contains the most significant bit. - for(uint8_t i = startByte + 1; i <= endByte; i++) { + uint8_t i; + for(i = startByte + 1; i <= endByte; i++) { ret = ret << 8; ret = ret | bytes[i]; } -- cgit 1.2.3-korg From f0d31caa3955365f6a393d788831f4b53fade000 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sat, 4 Jan 2014 11:51:14 -0500 Subject: Fix parse_bool tests. --- src/bitfield/bitfield.c | 1 + src/canutil/read.c | 2 +- src/canutil/read.h | 2 +- tests/read_tests.c | 7 ++----- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c index dddb0ee2..e40ab1ab 100644 --- a/src/bitfield/bitfield.c +++ b/src/bitfield/bitfield.c @@ -38,6 +38,7 @@ uint64_t get_bitfield(const uint8_t source[], const uint8_t source_length, uint64_t whole; uint8_t bytes[sizeof(uint64_t)]; } combined; + memset(combined.bytes, 0, sizeof(combined.bytes)); copy_bits_right_aligned(source, source_length, offset, bit_count, combined.bytes, sizeof(combined.bytes)); if(BYTE_ORDER == LITTLE_ENDIAN) { diff --git a/src/canutil/read.c b/src/canutil/read.c index 3931721a..b662e9bd 100644 --- a/src/canutil/read.c +++ b/src/canutil/read.c @@ -23,7 +23,7 @@ float bitfield_parse_float(const uint8_t source[], const uint16_t source_length, return raw * factor + offset; } -float bitfield_parse_bool(const uint8_t source[], const uint16_t source_length, +bool 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, diff --git a/src/canutil/read.h b/src/canutil/read.h index 733e3509..86fea785 100644 --- a/src/canutil/read.h +++ b/src/canutil/read.h @@ -70,7 +70,7 @@ bool eightbyte_parse_bool(uint64_t source, uint8_t bit_offset, uint8_t bit_size, * * Returns false if the value was 0, otherwise true. */ -float bitfield_parse_float(const uint8_t source[], const uint16_t source_size, +bool bitfield_parse_bool(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); diff --git a/tests/read_tests.c b/tests/read_tests.c index 512d87e8..5008cc52 100644 --- a/tests/read_tests.c +++ b/tests/read_tests.c @@ -36,11 +36,8 @@ 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); + fail_unless(bitfield_parse_bool(ARRAY_TEST_DATA, sizeof(ARRAY_TEST_DATA), + 0, 1, 1.0, 0)); } END_TEST -- cgit 1.2.3-korg From cc2f44eeedac7d6e86005543c7e1596c3c78d551 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Mon, 6 Jan 2014 12:03:18 -0500 Subject: DRY up the float parser. --- src/canutil/read.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/canutil/read.c b/src/canutil/read.c index b662e9bd..d0cbb71a 100644 --- a/src/canutil/read.c +++ b/src/canutil/read.c @@ -2,10 +2,14 @@ #include #include +static float decode_float(uint64_t raw, float factor, float offset) { + return raw * factor + offset; +} + float eightbyte_parse_float(uint64_t data, uint8_t bit_offset, uint8_t bit_size, float factor, float offset) { - uint64_t raw = eightbyte_get_bitfield(data, bit_offset, bit_size, true); - return raw * factor + offset; + return decode_float(eightbyte_get_bitfield(data, bit_offset, bit_size, + true), factor, offset); } bool eightbyte_parse_bool(uint64_t data, uint8_t bit_offset, uint8_t bit_size, @@ -17,10 +21,8 @@ bool eightbyte_parse_bool(uint64_t data, uint8_t bit_offset, uint8_t bit_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) { - 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; + return decode_float(get_bitfield(source, source_length, bit_offset, bit_size), + factor, offset); } bool bitfield_parse_bool(const uint8_t source[], const uint16_t source_length, -- cgit 1.2.3-korg From eab0c42eac865a7e965878a7f2ad548371bd34d5 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Mon, 6 Jan 2014 13:58:36 -0500 Subject: Standardize order of arguments - destination is always last. --- README.mkd | 2 +- src/bitfield/8byte.c | 4 +-- src/bitfield/8byte.h | 4 +-- src/bitfield/bitfield.c | 24 +++++++++++++--- src/bitfield/bitfield.h | 23 +++++++++++++++ src/canutil/write.c | 32 ++++++++++++++++----- src/canutil/write.h | 9 ++++-- tests/8byte_tests.c | 18 ++++++------ tests/bitfield_tests.c | 23 +++++++++++++++ tests/write_tests.c | 76 +++++++++++++++++++++++++++++++++++++++++-------- 10 files changed, 176 insertions(+), 39 deletions(-) diff --git a/README.mkd b/README.mkd index 99ede1ad..439b3dd0 100644 --- a/README.mkd +++ b/README.mkd @@ -50,7 +50,7 @@ useful. ### 8 Byte Encoding uint64_t data = 0; - fail_unless(8byte_set_bitfield(&data, 1, 0, 1)); + fail_unless(8byte_set_bitfield(1, 0, 1, &data)); uint64_t result = eightbyte_get_bitfield(data, 0, 1, false); ck_assert_int_eq(result, 0x1); diff --git a/src/bitfield/8byte.c b/src/bitfield/8byte.c index 72f7e32b..0ae6894b 100644 --- a/src/bitfield/8byte.c +++ b/src/bitfield/8byte.c @@ -47,8 +47,8 @@ uint64_t eightbyte_get_bitfield(uint64_t source, const uint16_t offset, return ret & bitmask(bit_count); } -bool eightbyte_set_bitfield(uint64_t* destination, uint64_t value, const uint16_t offset, - const uint16_t bit_count) { +bool eightbyte_set_bitfield(uint64_t value, const uint16_t offset, + const uint16_t bit_count, uint64_t* destination) { if(value > bitmask(bit_count)) { return false; } diff --git a/src/bitfield/8byte.h b/src/bitfield/8byte.h index 2916c218..04512690 100644 --- a/src/bitfield/8byte.h +++ b/src/bitfield/8byte.h @@ -74,8 +74,8 @@ uint8_t eightbyte_get_byte(const uint64_t source, const uint8_t byte_index, * Returns true if the bit_count is enough to fully represent the value, and * false if it will not fit. */ -bool eightbyte_set_bitfield(uint64_t* destination, uint64_t value, - const uint16_t offset, const uint16_t bit_count); +bool eightbyte_set_bitfield(uint64_t value, + const uint16_t offset, const uint16_t bit_count, uint64_t* destination); /* Private: Determine the index of the last bit used. */ diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c index e40ab1ab..b244c9b1 100644 --- a/src/bitfield/bitfield.c +++ b/src/bitfield/bitfield.c @@ -34,10 +34,7 @@ uint64_t get_bitfield(const uint8_t source[], const uint8_t source_length, return 0; } - union { - uint64_t whole; - uint8_t bytes[sizeof(uint64_t)]; - } combined; + ArrayOrBytes combined; memset(combined.bytes, 0, sizeof(combined.bytes)); copy_bits_right_aligned(source, source_length, offset, bit_count, combined.bytes, sizeof(combined.bytes)); @@ -53,3 +50,22 @@ bool set_nibble(const uint16_t nibble_index, const uint8_t value, destination_length, nibble_index * NIBBLE_SIZE); } +bool set_bitfield(const uint64_t value, const uint16_t offset, + const uint16_t bit_count, uint8_t destination[], + uint16_t destination_length) { + if(value > bitmask(bit_count)) { + return false; + } + + ArrayOrBytes combined = { + whole: value + }; + + if(BYTE_ORDER == LITTLE_ENDIAN) { + combined.whole = __builtin_bswap64(combined.whole); + } + + return copy_bits(combined.bytes, sizeof(combined.bytes), + sizeof(combined.bytes) * CHAR_BIT - bit_count, bit_count, + destination, destination_length, offset); +} diff --git a/src/bitfield/bitfield.h b/src/bitfield/bitfield.h index a080c866..b3c30f02 100644 --- a/src/bitfield/bitfield.h +++ b/src/bitfield/bitfield.h @@ -168,6 +168,22 @@ bool copy_bytes_right_aligned(const uint8_t source[], const uint16_t source_leng bool set_nibble(const uint16_t nibble_index, const uint8_t value, uint8_t* destination, const uint16_t destination_length); +/* Public: Set the bit field in the given data array to the new value. + * + * value - the value to set in the bit field. + * offset - the starting index of the bit field (beginning from 0). + * bit_count - the number of bits to set in the data. + * destination - the destination array. + * destination_length - the total length of the destination array in bytes, + * for range checking. + * + * Returns true if the bit_count is enough to fully represent the value, and + * false if it will not fit. + */ +bool set_bitfield(const uint64_t value, const uint16_t offset, + const uint16_t bit_count, uint8_t destination[], + uint16_t destination_length); + /* Private: */ uint16_t bits_to_bytes(uint32_t bits); @@ -178,6 +194,13 @@ uint16_t bits_to_bytes(uint32_t bits); */ uint64_t bitmask(const uint8_t bit_count); +/* Private: A union to assist swapping between uint64_t and a uint8_t array. + */ +typedef union { + uint64_t whole; + uint8_t bytes[sizeof(uint64_t)]; +} ArrayOrBytes; + #ifdef __cplusplus } #endif diff --git a/src/canutil/write.c b/src/canutil/write.c index 5b91aaf9..3b3ae25d 100644 --- a/src/canutil/write.c +++ b/src/canutil/write.c @@ -2,8 +2,8 @@ #include #include -uint64_t eightbyte_encode_float(float value, uint8_t bit_offset, uint8_t bit_size, - float factor, float offset) { +static uint64_t float_to_fixed_point(const float value, const float factor, + const float offset) { float raw = (value - offset) / factor; if(raw > 0) { // round up to avoid losing precision when we cast to an int @@ -11,8 +11,14 @@ uint64_t eightbyte_encode_float(float value, uint8_t bit_offset, uint8_t bit_siz // rounding? raw += 0.5; } + return (uint64_t)raw; +} + +uint64_t eightbyte_encode_float(float value, uint8_t bit_offset, uint8_t bit_size, + float factor, float offset) { uint64_t result = 0; - if(!eightbyte_set_bitfield(&result, (uint64_t)raw, bit_offset, bit_size)) { + if(!eightbyte_set_bitfield(float_to_fixed_point(value, factor, offset), + bit_offset, bit_size, &result)) { // debug("%f will not fit in a %d bit field", value, bit_size); } return result; @@ -23,8 +29,20 @@ uint64_t eightbyte_encode_bool(const bool value, const uint8_t bit_offset, return eightbyte_encode_float(value, bit_offset, bit_size, 1.0, 0); } -bool bitfield_encode_float(float value, uint8_t bit_offset, - uint8_t bit_size, float factor, float offset, uint8_t destination[]) { - // TODO - return 0; +bool bitfield_encode_float(const float value, const uint8_t bit_offset, + const uint8_t bit_size, const float factor, const float offset, + uint8_t destination[], const uint8_t destination_length) { + if(!set_bitfield(float_to_fixed_point(value, factor, offset), bit_offset, + bit_size, destination, destination_length)) { + // debug("%f will not fit in a %d bit field", value, bit_size); + return false; + } + return true; +} + +bool bitfield_encode_bool(const bool value, const uint8_t bit_offset, + const uint8_t bit_size, uint8_t destination[], + const uint16_t destination_length) { + return bitfield_encode_float(value, bit_offset, bit_size, 1.0, 0, + destination, destination_length); } diff --git a/src/canutil/write.h b/src/canutil/write.h index 8fd18cdb..28b7e052 100644 --- a/src/canutil/write.h +++ b/src/canutil/write.h @@ -26,8 +26,9 @@ extern "C" { uint64_t eightbyte_encode_float(float value, uint8_t bit_offset, uint8_t bit_size, float factor, float offset); -bool bitfield_encode_float(float value, uint8_t bit_offset, - uint8_t bit_size, float factor, float offset, uint8_t destination[]); +bool bitfield_encode_float(const float value, const uint8_t bit_offset, + const uint8_t bit_size, const float factor, const float offset, + uint8_t destination[], const uint8_t destination_length); /* Public: Encode a boolean into fixed bit width field in a bit array. * @@ -42,6 +43,10 @@ bool bitfield_encode_float(float value, uint8_t bit_offset, uint64_t eightbyte_encode_bool(const bool value, const uint8_t bit_offset, const uint8_t bit_size); +bool bitfield_encode_bool(const bool value, const uint8_t bit_offset, const + uint8_t bit_size, uint8_t destination[], + const uint16_t destination_length); + #ifdef __cplusplus } #endif diff --git a/tests/8byte_tests.c b/tests/8byte_tests.c index 51e927e4..258b8805 100644 --- a/tests/8byte_tests.c +++ b/tests/8byte_tests.c @@ -103,23 +103,23 @@ START_TEST (test_get_off_byte_boundary) START_TEST (test_set_wont_fit) { uint64_t data = 0; - fail_if(eightbyte_set_bitfield(&data, 100, 0, 1)); + fail_if(eightbyte_set_bitfield(100, 0, 1, &data)); } END_TEST START_TEST (test_set_field) { uint64_t data = 0; - fail_unless(eightbyte_set_bitfield(&data, 1, 0, 1)); + fail_unless(eightbyte_set_bitfield(1, 0, 1, &data)); uint64_t result = eightbyte_get_bitfield(data, 0, 1, false); ck_assert_int_eq(result, 0x1); data = 0; - fail_unless(eightbyte_set_bitfield(&data, 1, 1, 1)); + fail_unless(eightbyte_set_bitfield(1, 1, 1, &data)); result = eightbyte_get_bitfield(data, 1, 1, false); ck_assert_int_eq(result, 0x1); data = 0; - fail_unless(eightbyte_set_bitfield(&data, 0xf, 3, 4)); + fail_unless(eightbyte_set_bitfield(0xf, 3, 4, &data)); result = eightbyte_get_bitfield(data, 3, 4, false); ck_assert_int_eq(result, 0xf); } @@ -128,14 +128,14 @@ END_TEST START_TEST (test_set_doesnt_clobber_existing_data) { uint64_t data = 0xFFFC4DF300000000; - fail_unless(eightbyte_set_bitfield(&data, 0x4fc8, 16, 16)); + fail_unless(eightbyte_set_bitfield(0x4fc8, 16, 16, &data)); 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); data = 0x8000000000000000; - fail_unless(eightbyte_set_bitfield(&data, 1, 21, 1)); + fail_unless(eightbyte_set_bitfield(1, 21, 1, &data)); fail_unless(data == 0x8000040000000000LLU, "Expected combined value 0x8000040000000000 but got 0x%llx%llx", data >> 32, data); @@ -145,7 +145,7 @@ END_TEST START_TEST (test_set_off_byte_boundary) { uint64_t data = 0xFFFC4DF300000000; - fail_unless(eightbyte_set_bitfield(&data, 0x12, 12, 8)); + fail_unless(eightbyte_set_bitfield(0x12, 12, 8, &data)); uint64_t result = eightbyte_get_bitfield(data, 12, 12, false); ck_assert_int_eq(result,0x12d); } @@ -154,14 +154,14 @@ END_TEST START_TEST (test_set_odd_number_of_bits) { uint64_t data = 0xFFFC4DF300000000LLU; - fail_unless(eightbyte_set_bitfield(&data, 0x12, 11, 5)); + fail_unless(eightbyte_set_bitfield(0x12, 11, 5, &data)); 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(eightbyte_set_bitfield(&data, 0x2, 11, 5)); + fail_unless(eightbyte_set_bitfield(0x2, 11, 5, &data)); 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, diff --git a/tests/bitfield_tests.c b/tests/bitfield_tests.c index b03882a2..b8c83b59 100644 --- a/tests/bitfield_tests.c +++ b/tests/bitfield_tests.c @@ -26,6 +26,27 @@ START_TEST (test_set_nibble) } END_TEST +START_TEST (test_set_bitfield) +{ + uint8_t data[4] = {0}; + fail_unless(set_bitfield(0x12, 0, 8, data, sizeof(data))); + fail_unless(set_bitfield(bitmask(3), 10, 3, data, sizeof(data))); + ck_assert_int_eq(data[0], 0x12); + ck_assert_int_eq(data[1], 0x38); +} +END_TEST + +START_TEST (test_set_bitfield_doesnt_fit) +{ + uint8_t data[4] = {0}; + fail_if(set_bitfield(0xffff, 0, 8, data, sizeof(data))); + ck_assert_int_eq(data[0], 0); + ck_assert_int_eq(data[1], 0); + ck_assert_int_eq(data[2], 0); + ck_assert_int_eq(data[3], 0); +} +END_TEST + START_TEST (test_get_nibble) { uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; @@ -87,6 +108,8 @@ Suite* bitfieldSuite(void) { tcase_add_test(tc_core, test_get_byte); tcase_add_test(tc_core, test_get_nibble); tcase_add_test(tc_core, test_set_nibble); + tcase_add_test(tc_core, test_set_bitfield); + tcase_add_test(tc_core, test_set_bitfield_doesnt_fit); tcase_add_test(tc_core, test_get_bits); tcase_add_test(tc_core, test_copy_bytes); tcase_add_test(tc_core, test_get_bits_out_of_range); diff --git a/tests/write_tests.c b/tests/write_tests.c index 8f34a468..4d5d8fc3 100644 --- a/tests/write_tests.c +++ b/tests/write_tests.c @@ -2,7 +2,14 @@ #include #include -START_TEST (test_encode_can_signal) +START_TEST (test_eightbyte_encode_float_precision) +{ + uint64_t value = eightbyte_encode_float(50, 2, 19, 0.001, 0); + ck_assert_int_eq(value, 0x061a800000000000LLU); +} +END_TEST + +START_TEST (test_eightbyte_encode_float) { uint64_t value = eightbyte_encode_float(0, 1, 3, 1, 0); ck_assert_int_eq(value, 0); @@ -12,14 +19,7 @@ START_TEST (test_encode_can_signal) } END_TEST -START_TEST (test_encode_can_signal_rounding_precision) -{ - uint64_t value = eightbyte_encode_float(50, 2, 19, 0.001, 0); - ck_assert_int_eq(value, 0x061a800000000000LLU); -} -END_TEST - -START_TEST (test_encode_bool) +START_TEST (test_eightbyte_encode_bool) { uint64_t value = eightbyte_encode_bool(true, 1, 3); ck_assert_int_eq(value, 0x1000000000000000LLU); @@ -28,13 +28,65 @@ START_TEST (test_encode_bool) } END_TEST +START_TEST (test_bitfield_encode_float) +{ + uint8_t data[8] = {0}; + bitfield_encode_float(0, 1, 3, 1, 0, data, sizeof(data)); + ck_assert_int_eq(data[0], 0); + ck_assert_int_eq(data[1], 0); + ck_assert_int_eq(data[2], 0); + ck_assert_int_eq(data[3], 0); + ck_assert_int_eq(data[4], 0); + ck_assert_int_eq(data[5], 0); + ck_assert_int_eq(data[6], 0); + ck_assert_int_eq(data[7], 0); + + bitfield_encode_float(1, 1, 3, 1, 0, data, sizeof(data)); + ck_assert_int_eq(data[0], 0x10); + ck_assert_int_eq(data[1], 0); + ck_assert_int_eq(data[2], 0); + ck_assert_int_eq(data[3], 0); + ck_assert_int_eq(data[4], 0); + ck_assert_int_eq(data[5], 0); + ck_assert_int_eq(data[6], 0); + ck_assert_int_eq(data[7], 0); +} +END_TEST + +START_TEST (test_bitfield_encode_bool) +{ + uint8_t data[8] = {0}; + bitfield_encode_bool(true, 1, 3, data, sizeof(data)); + ck_assert_int_eq(data[0], 0x10); + ck_assert_int_eq(data[1], 0); + ck_assert_int_eq(data[2], 0); + ck_assert_int_eq(data[3], 0); + ck_assert_int_eq(data[4], 0); + ck_assert_int_eq(data[5], 0); + ck_assert_int_eq(data[6], 0); + ck_assert_int_eq(data[7], 0); + + bitfield_encode_bool(false, 1, 3, data, sizeof(data)); + ck_assert_int_eq(data[0], 0); + ck_assert_int_eq(data[1], 0); + ck_assert_int_eq(data[2], 0); + ck_assert_int_eq(data[3], 0); + ck_assert_int_eq(data[4], 0); + ck_assert_int_eq(data[5], 0); + ck_assert_int_eq(data[6], 0); + ck_assert_int_eq(data[7], 0); +} +END_TEST + Suite* canwriteSuite(void) { Suite* s = suite_create("write"); TCase *tc_core = tcase_create("core"); tcase_add_checked_fixture(tc_core, NULL, NULL); - tcase_add_test(tc_core, test_encode_can_signal); - tcase_add_test(tc_core, test_encode_bool); - tcase_add_test(tc_core, test_encode_can_signal_rounding_precision); + tcase_add_test(tc_core, test_eightbyte_encode_float); + tcase_add_test(tc_core, test_eightbyte_encode_bool); + tcase_add_test(tc_core, test_eightbyte_encode_float_precision); + tcase_add_test(tc_core, test_bitfield_encode_float); + tcase_add_test(tc_core, test_bitfield_encode_bool); suite_add_tcase(s, tc_core); return s; -- cgit 1.2.3-korg From 6f243098abadbde2e9b2e5b13a94029960ea2e51 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Mon, 6 Jan 2014 14:53:42 -0500 Subject: Add more documentation. --- src/bitfield/bitfield.h | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/bitfield/bitfield.h b/src/bitfield/bitfield.h index b3c30f02..df92639a 100644 --- a/src/bitfield/bitfield.h +++ b/src/bitfield/bitfield.h @@ -165,6 +165,18 @@ bool copy_bytes_right_aligned(const uint8_t source[], const uint16_t source_leng const uint16_t offset, const uint16_t byte_count, uint8_t* destination, const uint16_t destination_length); +/* Public: Set the a nibble in the given data array to the new value. + * + * nibble_index - the index of the nibble to retreive. The leftmost nibble is + * index 0. + * value - the value to set in the bit field. + * destination - the destination array. + * destination_length - the total length of the destination array in bytes, + * for range checking. + * + * Returns true if the bit_count is enough to fully represent the value, and + * false if it will not fit. + */ bool set_nibble(const uint16_t nibble_index, const uint8_t value, uint8_t* destination, const uint16_t destination_length); @@ -184,16 +196,16 @@ bool set_bitfield(const uint64_t value, const uint16_t offset, const uint16_t bit_count, uint8_t destination[], uint16_t destination_length); -/* Private: - */ -uint16_t bits_to_bytes(uint32_t bits); - /* 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); +/* Private: + */ +uint16_t bits_to_bytes(uint32_t bits); + /* Private: A union to assist swapping between uint64_t and a uint8_t array. */ typedef union { -- cgit 1.2.3-korg From 05e7cb6cfd0929046abe0ea44bab7a43d7f6d0d2 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Mon, 6 Jan 2014 15:40:35 -0500 Subject: Watch for an error when getting a bit field. --- src/bitfield/bitfield.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c index b244c9b1..795f0208 100644 --- a/src/bitfield/bitfield.c +++ b/src/bitfield/bitfield.c @@ -36,10 +36,13 @@ uint64_t get_bitfield(const uint8_t source[], const uint8_t source_length, ArrayOrBytes combined; memset(combined.bytes, 0, sizeof(combined.bytes)); - copy_bits_right_aligned(source, source_length, offset, bit_count, - combined.bytes, sizeof(combined.bytes)); - if(BYTE_ORDER == LITTLE_ENDIAN) { - combined.whole = __builtin_bswap64(combined.whole); + if(copy_bits_right_aligned(source, source_length, offset, bit_count, + combined.bytes, sizeof(combined.bytes))) { + if(BYTE_ORDER == LITTLE_ENDIAN) { + combined.whole = __builtin_bswap64(combined.whole); + } + } else { + // debug("couldn't copy enough bits from source") } return combined.whole; } -- cgit 1.2.3-korg From 7f1d5473842361f97fef886bc4e98949ecf853b6 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Tue, 7 Jan 2014 00:07:11 -0500 Subject: Enable warnings when compiling and fix a few. --- Makefile | 2 +- src/bitfield/8byte.c | 4 ++-- tests/8byte_tests.c | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index d831b5ad..e93efb47 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc INCLUDES = -Isrc -CFLAGS = $(INCLUDES) -c -w -Wall -Werror -g -ggdb -coverage +CFLAGS = $(INCLUDES) -c -Wall -Werror -g -ggdb -coverage LDFLAGS = -coverage -lm LDLIBS = -lcheck diff --git a/src/bitfield/8byte.c b/src/bitfield/8byte.c index 0ae6894b..9325ed1b 100644 --- a/src/bitfield/8byte.c +++ b/src/bitfield/8byte.c @@ -8,8 +8,8 @@ uint8_t eightbyte_get_nibble(const uint64_t source, const uint8_t nibble_index, const bool data_is_big_endian) { - return eightbyte_get_bitfield(source, NIBBLE_SIZE * nibble_index, NIBBLE_SIZE, - data_is_big_endian); + return (uint8_t) eightbyte_get_bitfield(source, NIBBLE_SIZE * nibble_index, + NIBBLE_SIZE, data_is_big_endian); } uint8_t eightbyte_get_byte(uint64_t source, const uint8_t byte_index, diff --git a/tests/8byte_tests.c b/tests/8byte_tests.c index 258b8805..64554acc 100644 --- a/tests/8byte_tests.c +++ b/tests/8byte_tests.c @@ -1,6 +1,7 @@ #include #include #include +#include START_TEST (test_large_bitmask) { -- cgit 1.2.3-korg From 500668d68145e0afb7a08e5757bf22a6dd7d74bb Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Wed, 5 Mar 2014 15:39:52 -0500 Subject: Make float_to_fixed_point a public function. --- src/canutil/write.c | 2 +- src/canutil/write.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/canutil/write.c b/src/canutil/write.c index 3b3ae25d..7f3a3e04 100644 --- a/src/canutil/write.c +++ b/src/canutil/write.c @@ -2,7 +2,7 @@ #include #include -static uint64_t float_to_fixed_point(const float value, const float factor, +uint64_t float_to_fixed_point(const float value, const float factor, const float offset) { float raw = (value - offset) / factor; if(raw > 0) { diff --git a/src/canutil/write.h b/src/canutil/write.h index 28b7e052..c2bef20e 100644 --- a/src/canutil/write.h +++ b/src/canutil/write.h @@ -26,6 +26,9 @@ extern "C" { uint64_t eightbyte_encode_float(float value, uint8_t bit_offset, uint8_t bit_size, float factor, float offset); +uint64_t float_to_fixed_point(const float value, const float factor, + const float offset); + bool bitfield_encode_float(const float value, const uint8_t bit_offset, const uint8_t bit_size, const float factor, const float offset, uint8_t destination[], const uint8_t destination_length); -- cgit 1.2.3-korg From a34745ec93ae0a1d4f1b640dba8fb6702331a8e9 Mon Sep 17 00:00:00 2001 From: Christopher Peplin Date: Sat, 19 Jul 2014 14:36:45 -0400 Subject: Remove old hipchat token from Travis CI config. --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9ecb6a44..7654abaa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,3 @@ script: make test before_install: - sudo apt-get update -qq - sudo apt-get install check -notifications: - hipchat: - - secure: "ZO/hEAoOTZ4FJytMW0m4LZrsdFVM1/V0Hu13zfj8mdcHkf2MyfxthPDecnn5\naZVn4P8mSSwpp39EnAfa9fBcWcDESnKM1YQKPPGkoxZZHIOd2rYhRv34XfpE\n5qNLkQ/lEPQCBEmvIQ5ZJxsiZjGhO7KxWvdNdruH6cdVCYSh4Xo=" -- cgit 1.2.3-korg