Standardize order of arguments - destination is always last.
authorChristopher Peplin <chris.peplin@rhubarbtech.com>
Mon, 6 Jan 2014 18:58:36 +0000 (13:58 -0500)
committerChristopher Peplin <chris.peplin@rhubarbtech.com>
Mon, 6 Jan 2014 18:58:36 +0000 (13:58 -0500)
README.mkd
src/bitfield/8byte.c
src/bitfield/8byte.h
src/bitfield/bitfield.c
src/bitfield/bitfield.h
src/canutil/write.c
src/canutil/write.h
tests/8byte_tests.c
tests/bitfield_tests.c
tests/write_tests.c

index 99ede1a..439b3dd 100644 (file)
@@ -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);
 
index 72f7e32..0ae6894 100644 (file)
@@ -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;
     }
index 2916c21..0451269 100644 (file)
@@ -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.
  */
index e40ab1a..b244c9b 100644 (file)
@@ -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);
+}
index a080c86..b3c30f0 100644 (file)
@@ -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
index 5b91aaf..3b3ae25 100644 (file)
@@ -2,8 +2,8 @@
 #include <bitfield/bitfield.h>
 #include <bitfield/8byte.h>
 
-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);
 }
index 8fd18cd..28b7e05 100644 (file)
@@ -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
index 51e927e..258b880 100644 (file)
@@ -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,
index b03882a..b8c83b5 100644 (file)
@@ -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);
index 8f34a46..4d5d8fc 100644 (file)
@@ -2,7 +2,14 @@
 #include <check.h>
 #include <stdint.h>
 
-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;