blob: daf3a40a997cbe2aa177225ca7c0c8e0b5ddc4b2 [file] [log] [blame]
#ifndef SRC_UTIL_H
#define SRC_UTIL_H
#include <chrono>
#include <iostream>
#include <memory>
#include <thread>
#include <vector>
#include <google/protobuf/message.h>
#ifdef ANDROID
#define CONFIG_NO_UART 1
#endif // ANDROID
#ifndef CONFIG_NO_UART
#include <termios.h>
#include "src/lib/inc/frame_layer.h"
#include "src/lib/inc/frame_layer_types.h"
#endif // CONFIG_NO_UART
#include "nugget_tools.h"
using std::string;
using std::vector;
using std::unique_ptr;
namespace test_harness {
/** The approximate time it takes to transmit one bit over UART at 115200
* baud. */
const auto BIT_TIME = std::chrono::microseconds(10000 / 1152);
/** The approximate time it takes to transmit one byte over UART at 115200
* baud. */
const auto BYTE_TIME = std::chrono::microseconds(80000 / 1152);
const size_t PROTO_BUFFER_MAX_LEN = 512;
enum error_codes : int {
NO_ERROR = 0,
GENERIC_ERROR = 1,
TIMEOUT = 2,
TRANSPORT_ERROR = 3,
OVERFLOW_ERROR = 4,
SERIALIZE_ERROR = 5,
};
const char* error_codes_name(int code);
struct raw_message {
uint16_t type; // The "magic number" used to identify the contents of data[].
uint16_t data_len; // How much data is in the buffer data[].
uint8_t data[PROTO_BUFFER_MAX_LEN - 2]; // The payload of the message.
};
class TestHarness {
public:
enum VerbosityLevels : int {
SILENT = 0,
CRITICAL = 10,
ERROR = 20,
WARNING = 30,
INFO = 40,
};
static std::unique_ptr<TestHarness> MakeUnique();
TestHarness();
/**
* @param path The device path to the tty (e.g. "/dev/tty1"). */
TestHarness(const char* path);
~TestHarness();
/**
* @return true if data can be sent and received over the tty. */
bool ttyState() const;
int getVerbosity() const;
int setVerbosity(int v);
/** Reads from tty until it would block. */
void flushConsole();
/** Reads from tty until the specified duration has passed. */
string ReadUntil(std::chrono::microseconds end);
void PrintUntilClosed();
bool RebootNugget();
int SendData(const raw_message& msg);
int SendOneofProto(uint16_t type, uint16_t subtype,
const google::protobuf::Message& message);
int SendProto(uint16_t type, const google::protobuf::Message& message);
int GetData(raw_message* msg, std::chrono::microseconds timeout);
bool UsingSpi() const;
#ifndef CONFIG_NO_UART
bool SwitchFromConsoleToProtoApi();
bool SwitchFromProtoApiToConsole(raw_message* out_msg);
#endif // CONFIG_NO_UART
protected:
int verbosity;
vector<uint8_t> output_buffer;
vector<uint8_t> input_buffer;
void Init(const char* path);
/** Writes @len bytes from @data until complete. */
void BlockingWrite(const char* data, size_t len);
/** Reads raw bytes from the tty until either an end of line is reached or
* the input would block.
*
* @return a single line with the '\n' character unless the last read() would
* have blocked.*/
string ReadLineUntilBlock();
// Needed for AHDLC / UART.
#ifndef CONFIG_NO_UART
struct termios tty_state;
ahdlc_frame_encoder_t encoder;
ahdlc_frame_decoder_t decoder;
int SendAhdlc(const raw_message& msg);
int GetAhdlc(raw_message* msg, std::chrono::microseconds timeout);
#endif // CONFIG_NO_UART
int tty_fd;
// Needed for libnos / SPI.
unique_ptr<nos::NuggetClientInterface> client;
int SendSpi(const raw_message& msg);
int GetSpi(raw_message* msg, std::chrono::microseconds timeout);
std::unique_ptr<std::thread> print_uart_worker;
};
void FatalError(const string& msg);
} // namespace test_harness
#endif // SRC_UTIL_H