463 lines
14 KiB
C++
463 lines
14 KiB
C++
/*
|
|
* Copyright 2017 NXP
|
|
* All rights reserved.
|
|
*
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "erpc_crc16.hpp"
|
|
#include "erpc_tcp_transport.hpp"
|
|
#include "erpc_transport.hpp"
|
|
#include "erpc_transport_setup.h"
|
|
#include "erpc_version.h"
|
|
|
|
#include "ErpcLexer.hpp"
|
|
#include "InterfaceDefinition.hpp"
|
|
#include "Logging.hpp"
|
|
#include "SearchPath.hpp"
|
|
#include "Sniffer.hpp"
|
|
#include "UniqueIdChecker.hpp"
|
|
#include "annotations.h"
|
|
#include "options.hpp"
|
|
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <stdexcept>
|
|
#include <vector>
|
|
|
|
/*!
|
|
* @brief Entry point for the tool.
|
|
*/
|
|
int main(int argc, char *argv[], char *envp[]);
|
|
|
|
using namespace erpc;
|
|
using namespace erpcgen;
|
|
using namespace std;
|
|
namespace erpcsniffer {
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Variables
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/*! The tool's name. */
|
|
const char k_toolName[] = "erpcsniffer";
|
|
|
|
/*! Current version number for the tool. */
|
|
const char k_version[] = ERPC_VERSION;
|
|
|
|
/*! Copyright string. */
|
|
const char k_copyright[] = "Copyright 2017 NXP. All rights reserved.";
|
|
|
|
static const char *k_optionsDefinition[] = { "?|help",
|
|
"V|version",
|
|
"o:output <filePath>",
|
|
"v|verbose",
|
|
"I:path <filePath>",
|
|
"t:transport <transport>",
|
|
"q:quantity <quantity>",
|
|
"b:baudrate <baudrate>",
|
|
"p:port <port>",
|
|
"h:host <host>",
|
|
NULL };
|
|
|
|
/*! Help string. */
|
|
const char k_usageText[] =
|
|
"\nOptions:\n\
|
|
-?/--help Show this help\n\
|
|
-V/--version Display tool version\n\
|
|
-o/--output <filePath> Set path to output file (file name included)\n\
|
|
-v/--verbose Print extra detailed log information\n\
|
|
-I/--path <filePath> Add search path for imports\n\
|
|
-t/--transport <transport> Type of transport.\n\
|
|
-q/--quantity <quantity> Record messages count (0 - infinity).\n\
|
|
-b/--baudrate <baudrate> Baud rate.\n\
|
|
-p/--port <port> Port name or port number.\n\
|
|
-h/--host <host> Host definition.\n\
|
|
\n\
|
|
Available transports (use with -t option):\n\
|
|
tcp Tcp transport type (host, port number).\n\
|
|
serial Serial transport type (port name, baud rate).\n\
|
|
\n";
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Code
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/*!
|
|
* @brief Class that encapsulates the erpcsniffer tool.
|
|
*
|
|
* A single global logger instance is created during object construction. It is
|
|
* never freed because we need it up to the last possible minute, when an
|
|
* exception could be thrown.
|
|
*/
|
|
class erpcsnifferTool
|
|
{
|
|
protected:
|
|
enum class verbose_type_t
|
|
{
|
|
kWarning,
|
|
kInfo,
|
|
kDebug,
|
|
kExtraDebug
|
|
}; /*!< Types of verbose outputs from erpcsniffer application. */
|
|
|
|
enum class transports_t
|
|
{
|
|
kNoneTransport,
|
|
kTcpTransport,
|
|
kSerialTransport
|
|
}; /*!< Type of transport to use. */
|
|
|
|
typedef vector<string> string_vector_t;
|
|
|
|
int m_argc; /*!< Number of command line arguments. */
|
|
char **m_argv; /*!< String value for each command line argument. */
|
|
StdoutLogger *m_logger; /*!< Singleton logger instance. */
|
|
verbose_type_t m_verboseType; /*!< Which type of log is need to set (warning, info, debug). */
|
|
const char *m_outputFilePath; /*!< Path to the output file. */
|
|
const char *m_ErpcFile; /*!< ERPC file. */
|
|
string_vector_t m_positionalArgs;
|
|
transports_t m_transport; /*!< Transport used for receiving messages. */
|
|
uint64_t m_quantity; /*!< Quantity of logs to store. */
|
|
uint32_t m_baudrate; /*!< Baudrate rate speed. */
|
|
const char *m_port; /*!< Name or number of port. Based on used transport. */
|
|
const char *m_host; /*!< Host name */
|
|
|
|
public:
|
|
/*!
|
|
* @brief Constructor.
|
|
*
|
|
* @param[in] argc Count of arguments in argv variable.
|
|
* @param[in] argv Pointer to array of arguments.
|
|
*
|
|
* Creates the singleton logger instance.
|
|
*/
|
|
erpcsnifferTool(int argc, char *argv[]) :
|
|
m_argc(argc), m_argv(argv), m_logger(0), m_verboseType(verbose_type_t::kWarning), m_outputFilePath(NULL),
|
|
m_ErpcFile(NULL), m_transport(transports_t::kNoneTransport), m_quantity(10), m_baudrate(115200), m_port(NULL),
|
|
m_host(NULL)
|
|
{
|
|
// create logger instance
|
|
m_logger = new StdoutLogger();
|
|
m_logger->setFilterLevel(Logger::log_level_t::kWarning);
|
|
Log::setLogger(m_logger);
|
|
}
|
|
|
|
/*!
|
|
* @brief Destructor.
|
|
*/
|
|
~erpcsnifferTool() {}
|
|
|
|
/*!
|
|
* @brief Reads the command line options passed into the constructor.
|
|
*
|
|
* This method can return a return code to its caller, which will cause the
|
|
* tool to exit immediately with that return code value. Normally, though, it
|
|
* will return -1 to signal that the tool should continue to execute and
|
|
* all options were processed successfully.
|
|
*
|
|
* The Options class is used to parse command line options. See
|
|
* #k_optionsDefinition for the list of options and #k_usageText for the
|
|
* descriptive help for each option.
|
|
*
|
|
* @retval -1 The options were processed successfully. Let the tool run normally.
|
|
* @return A zero or positive result is a return code value that should be
|
|
* returned from the tool as it exits immediately.
|
|
*/
|
|
int processOptions()
|
|
{
|
|
Options options(*m_argv, k_optionsDefinition);
|
|
OptArgvIter iter(--m_argc, ++m_argv);
|
|
|
|
// process command line options
|
|
int optchar;
|
|
const char *optarg;
|
|
while ((optchar = options(iter, optarg)))
|
|
{
|
|
switch (optchar)
|
|
{
|
|
case '?':
|
|
{
|
|
printUsage(options);
|
|
return 0;
|
|
}
|
|
|
|
case 'V':
|
|
{
|
|
printf("%s %s\n%s\n", k_toolName, k_version, k_copyright);
|
|
return 0;
|
|
}
|
|
|
|
case 'o':
|
|
{
|
|
m_outputFilePath = optarg;
|
|
break;
|
|
}
|
|
|
|
case 'v':
|
|
{
|
|
if (m_verboseType != verbose_type_t::kExtraDebug)
|
|
{
|
|
m_verboseType = (verbose_type_t)(((int)m_verboseType) + 1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 'I':
|
|
{
|
|
PathSearcher::getGlobalSearcher().addSearchPath(optarg);
|
|
break;
|
|
}
|
|
|
|
case 't':
|
|
{
|
|
string transport = optarg;
|
|
if (transport == "tcp")
|
|
{
|
|
m_transport = transports_t::kTcpTransport;
|
|
}
|
|
else if (transport == "serial")
|
|
{
|
|
m_transport = transports_t::kSerialTransport;
|
|
}
|
|
else
|
|
{
|
|
Log::error("error: unknown transport type %s", transport.c_str());
|
|
return 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 'q':
|
|
{
|
|
m_quantity = strtoul(optarg, NULL, 10);
|
|
break;
|
|
}
|
|
|
|
case 'b':
|
|
{
|
|
m_baudrate = strtoul(optarg, NULL, 10);
|
|
break;
|
|
}
|
|
|
|
case 'p':
|
|
{
|
|
m_port = optarg;
|
|
break;
|
|
}
|
|
|
|
case 'h':
|
|
{
|
|
m_host = optarg;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
Log::error("error: unrecognized option\n\n");
|
|
printUsage(options);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// handle positional args
|
|
if (iter.index() < m_argc)
|
|
{
|
|
// Log::debug("positional args:\n");
|
|
int i;
|
|
for (i = iter.index(); i < m_argc; ++i)
|
|
{
|
|
// Log::debug("%d: %s\n", i - iter.index(), m_argv[i]);
|
|
m_positionalArgs.push_back(m_argv[i]);
|
|
}
|
|
}
|
|
|
|
// all is well
|
|
return -1;
|
|
}
|
|
|
|
/*!
|
|
* @brief Prints help for the tool.
|
|
*
|
|
* @param[in] options Options, which can be used.
|
|
*/
|
|
void printUsage(Options &options)
|
|
{
|
|
options.usage(cout, "files...");
|
|
printf(k_usageText);
|
|
}
|
|
|
|
/*!
|
|
* @brief Core of the tool.
|
|
*
|
|
* Calls processOptions() to handle command line options before performing the
|
|
* real work the tool does.
|
|
*
|
|
* @retval 1 The functions wasn't processed successfully.
|
|
* @retval 0 The function was processed successfully.
|
|
*
|
|
* @exception Log::error This function is called, when function wasn't
|
|
* processed successfully.
|
|
* @exception runtime_error Thrown, when positional args is empty.
|
|
*/
|
|
int run()
|
|
{
|
|
try
|
|
{
|
|
// read command line options
|
|
int result;
|
|
if ((result = processOptions()) != -1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
// set verbose logging
|
|
setVerboseLogging();
|
|
|
|
// check argument values
|
|
checkArguments();
|
|
if (!m_positionalArgs.size())
|
|
{
|
|
throw runtime_error("no input file provided");
|
|
}
|
|
|
|
m_ErpcFile = m_positionalArgs[0].c_str();
|
|
if (!m_outputFilePath)
|
|
{
|
|
m_outputFilePath = "";
|
|
}
|
|
|
|
// Parse and build definition model.
|
|
InterfaceDefinition def;
|
|
|
|
// Check for duplicate function IDs
|
|
UniqueIdChecker uniqueIdCheck;
|
|
uniqueIdCheck.makeIdsUnique(def);
|
|
|
|
Transport *_transport;
|
|
switch (m_transport)
|
|
{
|
|
case transports_t::kTcpTransport:
|
|
{
|
|
uint16_t portNumber = strtoul(m_port, NULL, 10);
|
|
TCPTransport *tcpTransport = new TCPTransport(m_host, portNumber, true);
|
|
if (erpc_status_t err = tcpTransport->open())
|
|
{
|
|
return err;
|
|
}
|
|
_transport = tcpTransport;
|
|
break;
|
|
}
|
|
|
|
case transports_t::kSerialTransport:
|
|
{
|
|
erpc_transport_t transport = erpc_transport_serial_init(m_port, m_baudrate);
|
|
_transport = reinterpret_cast<Transport *>(transport);
|
|
assert(_transport);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
Crc16 crc;
|
|
if (def.hasProgramSymbol())
|
|
{
|
|
Program *program = def.getProgramSymbol();
|
|
if (program->findAnnotation(CRC_ANNOTATION, Annotation::program_lang_t::kC) != nullptr)
|
|
{
|
|
crc.setCrcStart(def.getIdlCrc16());
|
|
}
|
|
}
|
|
_transport->setCrc16(&crc);
|
|
Sniffer s(_transport, &def, m_outputFilePath, m_quantity);
|
|
return s.run();
|
|
}
|
|
catch (exception &e)
|
|
{
|
|
Log::error("error: %s\n", e.what());
|
|
return 1;
|
|
}
|
|
catch (...)
|
|
{
|
|
Log::error("error: unexpected exception\n");
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
* @brief Validate arguments that can be checked.
|
|
*
|
|
* @exception runtime_error Thrown if an argument value fails to pass validation.
|
|
*/
|
|
void checkArguments()
|
|
{
|
|
// if (m_outputFilePath == NULL)
|
|
// {
|
|
// throw runtime_error("no output file was specified");
|
|
// }
|
|
}
|
|
|
|
/*!
|
|
* @brief Turns on verbose logging.
|
|
*/
|
|
void setVerboseLogging()
|
|
{
|
|
// verbose only affects the INFO and DEBUG filter levels
|
|
// if the user has selected quiet mode, it overrides verbose
|
|
switch (m_verboseType)
|
|
{
|
|
case verbose_type_t::kWarning:
|
|
{
|
|
Log::getLogger()->setFilterLevel(Logger::log_level_t::kWarning);
|
|
break;
|
|
}
|
|
case verbose_type_t::kInfo:
|
|
{
|
|
Log::getLogger()->setFilterLevel(Logger::log_level_t::kInfo);
|
|
break;
|
|
}
|
|
case verbose_type_t::kDebug:
|
|
{
|
|
Log::getLogger()->setFilterLevel(Logger::log_level_t::kDebug);
|
|
break;
|
|
}
|
|
case verbose_type_t::kExtraDebug:
|
|
{
|
|
Log::getLogger()->setFilterLevel(Logger::log_level_t::kDebug2);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace erpcsniffer
|
|
|
|
/*!
|
|
* @brief Main application entry point.
|
|
*
|
|
* Creates a tool instance and lets it take over.
|
|
*/
|
|
int main(int argc, char *argv[], char *envp[])
|
|
{
|
|
(void)envp;
|
|
try
|
|
{
|
|
return erpcsniffer::erpcsnifferTool(argc, argv).run();
|
|
}
|
|
catch (...)
|
|
{
|
|
Log::error("error: unexpected exception\n");
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|