/firmware/tests/T2-Timeout/src/T2-Timeout-exerciser.cc

http://github.com/makerbot/G3Firmware · C++ · 273 lines · 223 code · 32 blank · 18 comment · 36 complexity · 9221628c15681862c91d698636c529c8 MD5 · raw file

  1. /*
  2. * T1-UART-exerciser.cc
  3. *
  4. * Created on: Dec 10, 2009
  5. * Author: phooky
  6. */
  7. /// Based on the hoary old serial-programming HOWTO
  8. #include <termios.h>
  9. #include <stdio.h>
  10. #include <unistd.h>
  11. #include <fcntl.h>
  12. #include <sys/signal.h>
  13. #include <sys/types.h>
  14. #include <stdlib.h>
  15. #include <getopt.h>
  16. #include <sys/time.h>
  17. #include <gtest/gtest.h>
  18. #include "Packet.hh"
  19. std::ostream& operator<<(std::ostream& stream, const uint8_t val) {
  20. return stream << (unsigned int)val;
  21. }
  22. const char* default_port = "/dev/ttyUSB0";
  23. #define BAUDRATE B38400
  24. #define _POSIX_SOURCE 1 /* POSIX compliant source */
  25. const int INDIVIDUAL_TEST_COUNT = 10;
  26. const int MIXED_TEST_COUNT = 100;
  27. const int STRESS_TEST_COUNT = 5000;
  28. class SerialTest : public ::testing::Test {
  29. protected:
  30. const char* port_name_;
  31. int serial_fd_;
  32. struct termios oldtio_;
  33. InPacket in_;
  34. OutPacket out_;
  35. uint16_t sequence_number_;
  36. uint16_t tests_run;
  37. uint16_t tests_succeeded;
  38. void recordTest() {
  39. tests_run++;
  40. }
  41. void recordSuccess() {
  42. tests_succeeded++;
  43. }
  44. void clearStats() {
  45. tests_run = 0;
  46. tests_succeeded = 0;
  47. }
  48. void reportStats() {
  49. if (HasFatalFailure()) {
  50. FAIL() << " (" << (tests_run-tests_succeeded) <<
  51. " out of " << tests_run << " failed)";
  52. }
  53. }
  54. public:
  55. SerialTest() : sequence_number_(0) { srandom(time(0)); }
  56. void SetUp() {
  57. clearStats();
  58. port_name_ = getenv("PORT");
  59. if (port_name_ == NULL) {
  60. port_name_ = default_port;
  61. }
  62. struct termios newtio;
  63. char buf[255];
  64. /* open the device to be non-blocking (read will return immediately) */
  65. serial_fd_ = open(port_name_, O_RDWR | O_NOCTTY | O_NONBLOCK);
  66. if (serial_fd_ < 0) {
  67. perror(port_name_);
  68. return;
  69. }
  70. tcgetattr(serial_fd_, &oldtio_); /* save current port settings */
  71. /* set new port settings for canonical input processing */
  72. newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
  73. newtio.c_cflag &= ~PARENB;
  74. newtio.c_cflag &= ~CSTOPB;
  75. newtio.c_cflag &= ~CSIZE;
  76. newtio.c_cflag |= CS8;
  77. newtio.c_iflag = IGNPAR;
  78. newtio.c_oflag = 0;
  79. newtio.c_lflag = 0;
  80. newtio.c_cc[VMIN] = 1;
  81. newtio.c_cc[VTIME] = 0;
  82. tcflush(serial_fd_, TCIOFLUSH);
  83. tcsetattr(serial_fd_, TCSANOW, &newtio);
  84. }
  85. void TearDown() {
  86. reportStats();
  87. /* restore old port settings */
  88. tcsetattr(serial_fd_, TCSANOW, &oldtio_);
  89. close(serial_fd_);
  90. }
  91. uint8_t makePacket(bool passthru);
  92. uint8_t makeVersionPacket();
  93. void writePacket(int16_t stop_after = -1);
  94. void readPacketWithTimeout(uint16_t timeout);
  95. void runPacket(bool passthru, bool timeout);
  96. };
  97. const char* port_string = default_port;
  98. class Timer {
  99. private:
  100. struct timeval start_;
  101. public:
  102. Timer() {
  103. gettimeofday(&start_, NULL);
  104. }
  105. long millisSince() {
  106. struct timeval now;
  107. gettimeofday(&now, NULL);
  108. return ((now.tv_sec - start_.tv_sec) * 1000L)
  109. + (now.tv_usec - start_.tv_usec) / 1000L;
  110. }
  111. };
  112. uint8_t SerialTest::makePacket(bool passthru) {
  113. // remove one byte for echo, another for passthru
  114. const uint8_t max_payload_length = passthru?30:31;
  115. uint8_t length_in_bytes = random() % max_payload_length;
  116. if (passthru) {
  117. out_.append8(0x73);
  118. }
  119. out_.append8(0x70); // echo test
  120. for (int i = 0; i < length_in_bytes; i++) {
  121. uint8_t val = (i % 2 == 0) ? (sequence_number_ & 0xff) : (sequence_number_ >> 8);
  122. out_.append8(val);
  123. }
  124. return length_in_bytes;
  125. }
  126. uint8_t SerialTest::makeVersionPacket() {
  127. // remove one byte for echo, another for passthru
  128. uint8_t length_in_bytes = 3;
  129. out_.append8(0x0);
  130. out_.append8(0x0);
  131. out_.append8(0x15);
  132. return length_in_bytes;
  133. }
  134. void SerialTest::writePacket(int16_t stop_after) {
  135. while (!out_.isFinished() && stop_after-- != 0) {
  136. uint8_t out_byte = out_.getNextByteToSend();
  137. write(serial_fd_, &out_byte, 1);
  138. }
  139. }
  140. void SerialTest::readPacketWithTimeout(uint16_t timeout) {
  141. Timer mark;
  142. while (!in_.isFinished()) {
  143. if (mark.millisSince() > timeout) {
  144. in_.timeout();
  145. break;
  146. }
  147. uint8_t in_byte;
  148. int count = read(serial_fd_, &in_byte, 1);
  149. if (count == 1) {
  150. in_.processByte(in_byte);
  151. }
  152. }
  153. }
  154. void SerialTest::runPacket(bool passthru,bool timeout) {
  155. recordTest();
  156. // write a packet
  157. in_.reset();
  158. out_.reset();
  159. sequence_number_++;
  160. uint8_t packet_length = makePacket(passthru);
  161. uint8_t to_send = timeout? ((random()%(packet_length+1))+1) : -1;
  162. writePacket(to_send);
  163. readPacketWithTimeout(80);
  164. if (timeout) {
  165. ASSERT_FALSE(in_.isFinished());
  166. ASSERT_TRUE(in_.hasError());
  167. ASSERT_EQ(in_.getErrorCode(),PacketError::PACKET_TIMEOUT);
  168. } else {
  169. ASSERT_TRUE(in_.isFinished());
  170. ASSERT_FALSE(in_.hasError());
  171. if (in_.getLength() == 1 && packet_length != 1) {
  172. // Get the presumed response code, like a downstream timeout,
  173. // logged
  174. ASSERT_EQ(RC_OK,in_.read8(0));
  175. }
  176. ASSERT_EQ(in_.getLength(),packet_length);
  177. for (int i = 0; i < packet_length; i++) {
  178. uint8_t val = (i % 2 == 0) ? (sequence_number_ & 0xff)
  179. : (sequence_number_ >> 8);
  180. ASSERT_EQ(in_.read8(i),val);
  181. }
  182. }
  183. recordSuccess();
  184. }
  185. TEST_F(SerialTest,GoodVersionPacket) {
  186. for (int i = 0; i < INDIVIDUAL_TEST_COUNT; i++) {
  187. // write a packet
  188. in_.reset();
  189. out_.reset();
  190. sequence_number_++;
  191. makeVersionPacket();
  192. writePacket();
  193. readPacketWithTimeout(80);
  194. ASSERT_TRUE(in_.isFinished());
  195. ASSERT_FALSE(in_.hasError());
  196. if (in_.getLength() == 2) {
  197. // Get the presumed response code, like a downstream timeout,
  198. // logged
  199. ASSERT_EQ(RC_OK,in_.read8(0));
  200. }
  201. }
  202. }
  203. TEST_F(SerialTest,GoodLocalPacket) {
  204. for (int i = 0; i < INDIVIDUAL_TEST_COUNT; i++) {
  205. runPacket(false,false);
  206. }
  207. }
  208. TEST_F(SerialTest,TimeoutLocalPacket) {
  209. for (int i = 0; i < INDIVIDUAL_TEST_COUNT; i++) {
  210. runPacket(false,true);
  211. }
  212. }
  213. TEST_F(SerialTest,GoodPassthruPacket) {
  214. for (int i = 0; i < INDIVIDUAL_TEST_COUNT; i++) {
  215. runPacket(true,false);
  216. }
  217. }
  218. TEST_F(SerialTest,TimeoutPassthruPacket) {
  219. for (int i = 0; i < INDIVIDUAL_TEST_COUNT; i++) {
  220. runPacket(true,true);
  221. }
  222. }
  223. TEST_F(SerialTest,MixedLocalPackets) {
  224. for (int i = 0; i < MIXED_TEST_COUNT; i++) {
  225. bool timeout = (random()%2) == 0;
  226. runPacket(false,timeout);
  227. }
  228. }
  229. TEST_F(SerialTest,MixedPassthruPackets) {
  230. for (int i = 0; i < MIXED_TEST_COUNT; i++) {
  231. bool timeout = (random()%2) == 0;
  232. runPacket(true,timeout);
  233. }
  234. }
  235. TEST_F(SerialTest,MixedAllPackets) {
  236. for (int i = 0; i < STRESS_TEST_COUNT; i++) {
  237. bool passthru = (random()%2) == 0;
  238. bool timeout = (random()%2) == 0;
  239. runPacket(passthru,timeout);
  240. }
  241. }