PageRenderTime 34ms CodeModel.GetById 13ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

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