test_scalar_encoding.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /*
  2. * Copyright (c) 2016 UAVCAN Team
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in all
  12. * copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. *
  22. * Contributors: https://github.com/UAVCAN/libcanard/contributors
  23. */
  24. #include <type_traits>
  25. #include <algorithm>
  26. #include <stdexcept>
  27. #include <memory>
  28. #include <catch.hpp>
  29. #include <iostream>
  30. #include "canard_internals.h"
  31. TEST_CASE("BigEndian, Check")
  32. {
  33. // Assuming that unit tests can only be run on little-endian platforms!
  34. REQUIRE_FALSE(isBigEndian());
  35. }
  36. template <typename T>
  37. static inline T read(CanardRxTransfer* transfer, uint32_t bit_offset, uint8_t bit_length)
  38. {
  39. auto value = T();
  40. const int res = canardDecodeScalar(transfer, uint16_t(bit_offset), bit_length, std::is_signed<T>::value, &value);
  41. if (res != bit_length)
  42. {
  43. throw std::runtime_error("Unexpected return value; expected " +
  44. std::to_string(unsigned(bit_length)) + ", got " + std::to_string(res));
  45. }
  46. return value;
  47. }
  48. TEST_CASE("ScalarDecode, SingleFrame")
  49. {
  50. auto transfer = CanardRxTransfer();
  51. static const uint8_t buf[7] =
  52. {
  53. 0b10100101, // 0
  54. 0b11000011, // 8
  55. 0b11100111, // 16
  56. 0b01111110, // 24
  57. 0b01010101,
  58. 0b10101010,
  59. 0b11101000
  60. };
  61. transfer.payload_head = &buf[0];
  62. transfer.payload_len = sizeof(buf);
  63. REQUIRE(0b10100101 == read<uint8_t>(&transfer, 0, 8));
  64. REQUIRE(0b01011100 == read<uint8_t>(&transfer, 4, 8));
  65. REQUIRE(0b00000101 == read<uint8_t>(&transfer, 4, 4));
  66. REQUIRE(read<bool>(&transfer, 9, 1));
  67. REQUIRE_FALSE(read<bool>(&transfer, 10, 1));
  68. REQUIRE(0b11101000101010100101010101111110 == read<uint32_t>(&transfer, 24, 32));
  69. /*
  70. * Raw bit stream with offset 21:
  71. * 111 01111110 01010101 10101010 11101
  72. * New byte segmentation:
  73. * 11101111 11001010 10110101 01011101
  74. * Which is little endian representation of:
  75. * 0b01011101101101011100101011101111
  76. */
  77. REQUIRE(0b01011101101101011100101011101111 == read<uint32_t>(&transfer, 21, 32));
  78. // Should fail
  79. REQUIRE_THROWS_AS(read<uint32_t>(&transfer, 25, 32), std::runtime_error);
  80. // Inexact size
  81. REQUIRE(0b010111101101011100101011101111 == read<uint32_t>(&transfer, 21, 30));
  82. // Negatives; reference values taken from libuavcan test suite or computed manually
  83. REQUIRE(-1 == read<int8_t>(&transfer, 16, 3)); // 0b111
  84. REQUIRE(-4 == read<int8_t>(&transfer, 2, 3)); // 0b100
  85. REQUIRE(-91 == read<int8_t>(&transfer, 0, 8)); // 0b10100101
  86. REQUIRE(-15451 == read<int16_t>(&transfer, 0, 16)); // 0b1100001110100101
  87. REQUIRE(-7771 == read<int16_t>(&transfer, 0, 15)); // 0b100001110100101
  88. }
  89. TEST_CASE("ScalarDecode, MultiFrame")
  90. {
  91. /*
  92. * Configuring allocator
  93. */
  94. CanardPoolAllocatorBlock allocator_blocks[2];
  95. CanardPoolAllocator allocator;
  96. initPoolAllocator(&allocator, &allocator_blocks[0], 2);
  97. /*
  98. * Configuring the transfer object
  99. */
  100. auto transfer = CanardRxTransfer();
  101. uint8_t head[CANARD_MULTIFRAME_RX_PAYLOAD_HEAD_SIZE];
  102. for (auto& x : head)
  103. {
  104. x = 0b10100101;
  105. }
  106. static_assert(CANARD_MULTIFRAME_RX_PAYLOAD_HEAD_SIZE == 6, "Assumption is not met, are we on a 32-bit x86 machine?");
  107. auto middle_a = createBufferBlock(&allocator);
  108. auto middle_b = createBufferBlock(&allocator);
  109. std::fill_n(&middle_a->data[0], CANARD_BUFFER_BLOCK_DATA_SIZE, 0b01011010);
  110. std::fill_n(&middle_b->data[0], CANARD_BUFFER_BLOCK_DATA_SIZE, 0b11001100);
  111. middle_a->next = middle_b;
  112. middle_b->next = nullptr;
  113. const uint8_t tail[4] =
  114. {
  115. 0b00010001,
  116. 0b00100010,
  117. 0b00110011,
  118. 0b01000100
  119. };
  120. transfer.payload_head = &head[0];
  121. transfer.payload_middle = middle_a;
  122. transfer.payload_tail = &tail[0];
  123. transfer.payload_len =
  124. uint16_t(CANARD_MULTIFRAME_RX_PAYLOAD_HEAD_SIZE + CANARD_BUFFER_BLOCK_DATA_SIZE * 2 + sizeof(tail));
  125. std::cout << "Payload size: " << transfer.payload_len << std::endl;
  126. /*
  127. * Testing
  128. */
  129. REQUIRE(0b10100101 == read<uint8_t>(&transfer, 0, 8));
  130. REQUIRE(0b01011010 == read<uint8_t>(&transfer, 4, 8));
  131. REQUIRE(0b00000101 == read<uint8_t>(&transfer, 4, 4));
  132. REQUIRE_FALSE(read<bool>(&transfer, CANARD_MULTIFRAME_RX_PAYLOAD_HEAD_SIZE * 8, 1));
  133. REQUIRE(read<bool>(&transfer, CANARD_MULTIFRAME_RX_PAYLOAD_HEAD_SIZE * 8 + 1, 1));
  134. // 64 from beginning, 48 bits from head, 16 bits from the middle
  135. REQUIRE(0b0101101001011010101001011010010110100101101001011010010110100101ULL == read<uint64_t>(&transfer, 0, 64));
  136. // 64 from two middle blocks, 32 from the first, 32 from the second
  137. REQUIRE(0b1100110011001100110011001100110001011010010110100101101001011010ULL ==
  138. read<uint64_t>(&transfer,
  139. CANARD_MULTIFRAME_RX_PAYLOAD_HEAD_SIZE * 8 + CANARD_BUFFER_BLOCK_DATA_SIZE * 8 - 32, 64));
  140. // Last 64
  141. REQUIRE(0b0100010000110011001000100001000111001100110011001100110011001100ULL ==
  142. read<uint64_t>(&transfer, transfer.payload_len * 8U - 64U, 64));
  143. /*
  144. * Testing without the middle
  145. */
  146. transfer.payload_middle = nullptr;
  147. transfer.payload_len = uint16_t(transfer.payload_len - CANARD_BUFFER_BLOCK_DATA_SIZE * 2U);
  148. // Last 64
  149. REQUIRE(0b0100010000110011001000100001000110100101101001011010010110100101ULL ==
  150. read<uint64_t>(&transfer, transfer.payload_len * 8U - 64U, 64));
  151. }
  152. TEST_CASE("ScalarEncode, Basic")
  153. {
  154. uint8_t buffer[32];
  155. std::fill_n(std::begin(buffer), sizeof(buffer), 0);
  156. uint8_t u8 = 123;
  157. canardEncodeScalar(buffer, 0, 8, &u8);
  158. REQUIRE(123 == buffer[0]);
  159. REQUIRE(0 == buffer[1]);
  160. u8 = 0b1111;
  161. canardEncodeScalar(buffer, 5, 4, &u8);
  162. REQUIRE((123U | 0b111U) == buffer[0]);
  163. REQUIRE(0b10000000 == buffer[1]);
  164. int16_t s16 = -1;
  165. canardEncodeScalar(buffer, 9, 15, &s16);
  166. REQUIRE((123U | 0b111U) == buffer[0]);
  167. REQUIRE(0b11111111 == buffer[1]);
  168. REQUIRE(0b11111111 == buffer[2]);
  169. REQUIRE(0b00000000 == buffer[3]);
  170. auto s64 = int64_t(0b0000000100100011101111000110011110001001101010111100110111101111L);
  171. canardEncodeScalar(buffer, 16, 60, &s64);
  172. REQUIRE((123U | 0b111U) == buffer[0]); // 0
  173. REQUIRE(0b11111111 == buffer[1]); // 8
  174. REQUIRE(0b11101111 == buffer[2]); // 16
  175. REQUIRE(0b11001101 == buffer[3]);
  176. REQUIRE(0b10101011 == buffer[4]);
  177. REQUIRE(0b10001001 == buffer[5]);
  178. REQUIRE(0b01100111 == buffer[6]);
  179. REQUIRE(0b10111100 == buffer[7]);
  180. REQUIRE(0b00100011 == buffer[8]);
  181. REQUIRE(0b00010000 == buffer[9]);
  182. }