diff --git a/include/vsl_integ.h b/include/vsl_integ.h index b0684d4..90f9e4d 100644 --- a/include/vsl_integ.h +++ b/include/vsl_integ.h @@ -1,7 +1,7 @@ /* MIT License -Copyright (c) 2022-2024 Jérémie Chabloz +Copyright (c) 2024 Jérémie Chabloz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -25,10 +25,10 @@ SOFTWARE. #ifndef VSL_INTEG_H #define VSL_INTEG_H -#include #include "cJSON.h" #include "verilated.h" +#include namespace vsl{ @@ -43,18 +43,21 @@ typedef enum { } vsl_state_t; -template class VslInteg { +class VslInteg { public: - VslInteg(T* const model, const int port=5100, const int timeout=120); + //VslInteg(VerilatedModel* const model, const int port=5100, const int timeout=120); + VslInteg(const int port=5100, const int timeout=120); ~VslInteg(); - + void run(); private: + + //VerilatedModel* p_model; //Pointer to VerilatedModel derived class + vsl_state_t _state {VSL_STATE_INIT}; //Verisocks state - T* p_model; //Pointer to VerilatedModel derived class - cJSON* p_cmd; //Pointer to current/latest command + cJSON* p_cmd {nullptr}; //Pointer to current/latest command int num_port {5100}; // Port number int num_timeout_sec {120}; //Timeout, in seconds @@ -66,57 +69,34 @@ template class VslInteg { void main_connect(); void main_wait(); void main_process(); - void main_run(); -}; - - -/*Use a collection of type map associate key and command handler function - * pointers together*/ + void main_sim(); -/* -What do we need to have here and in the accompanying .cc file? - -* One class that: - * encapsulates the top-level state machine for the Verisocks Verilator - integration - * members - * Verilator context (pointer) - * simulation/verisocks state - * server socket current timeout setting - * descriptor for server socket - * descriptor for the currently connected client socket - * pointer to current/latest received command (CJSON*) - * methods: - * Constructor - * Destructor - * main Verisocks loop (state machine) - -* Command handler function table -* Command handler sub-functions table(s) -* One class or struct that represents signals that can be used in - Verisocks commands. Maybe this class already exists and is defined in - verilated.h. -* Find a way to register callbacks - either based on simulation time or based - on signal values - - - -* One enumeration that defines a type to support the different possible states - of the top-level state machine -*/ +}; /** * @brief Type for a command handler function pointer */ -typedef int (*vsl_cmd_handler_t)(void); +typedef void (*vsl_cmd_handler_t)(void); + +/** + * @brief Struct type for commands + * Associates a command name with a command handler function pointer + */ +typedef struct vsl_cmd { + vsl_cmd_handler_t cmd_handler; // Pointer to handler function + const char *cmd_name; // Command name + const char *cmd_key; // Command key if not cmd_name, NULL otherwise +} vsl_cmd_t; + + /** * @brief Helper macro to declare a command handler function * @param cmd Command short name */ -#define VSL_CMD_HANDLER(cmd) static int VSL_ ## cmd ## _cmd_handler() +#define VSL_CMD_HANDLER(cmd) static void VSL_ ## cmd ## _cmd_handler() /** * @brief Helper marco to define a command structure with a command name and diff --git a/src/vsl_integ.cpp b/src/vsl_integ.cpp index 1e46d84..4381c11 100644 --- a/src/vsl_integ.cpp +++ b/src/vsl_integ.cpp @@ -1,43 +1,77 @@ +/* +MIT License + +Copyright (c) 2024 Jérémie Chabloz + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ -#include -#include -#include -//#include -//#include -//#include #include "vsl_integ.h" -#include "verilated.h" + +//#include "verilated.h" +//#include "verilated_vpi.h" #include "vs_server.h" #include "vs_logging.h" - +#include "vs_msg.h" +//#include "cJSON.h" + +// #include +// #include +//#include +#include +#include +//#include namespace vsl{ -template VslInteg::VslInteg(T* const _p_model__, const int port, const int timeout) { - static_assert(std::is_base_of::value, - "Expected a Verilated model for type"); +/* Constructor */ +VslInteg::VslInteg(const int port, const int timeout) { + num_port = port; + num_timeout_sec = timeout; +} +/* +template VslInteg::VslInteg(T* const _p_model__, const int port, + const int timeout) { + // static_assert(std::is_base_of::value, + // "Expected a Verilated model for type"); p_model = _p_model__; num_port = port; num_timeout_sec = timeout; } +*/ - -template VslInteg::~VslInteg() { - if (0 <= fd_server_socket) close(fd_server_socket); - if (NULL != p_cmd) cJSON_Delete(p_cmd); +/* Destructor */ +VslInteg::~VslInteg() { + if (0 < fd_server_socket) close(fd_server_socket); + if (nullptr != p_cmd) cJSON_Delete(p_cmd); } -template void VslInteg::run() { +void VslInteg::run() { printf("******************************************\n"); printf("* __ __ _ _ *\n"); printf("* \\ \\ / /__ _ _(_)___ ___ __| |__ ___ *\n"); printf("* \\ V / -_) '_| (_- void VslInteg::run() { } break; case VSL_STATE_SIM_RUNNING: - main_run(); + main_sim(); break; case VSL_STATE_EXIT: if (0 <= fd_server_socket) { @@ -69,7 +103,8 @@ template void VslInteg::run() { return; case VSL_STATE_ERROR: default: - vs_log_error("Exiting Verisocks main loop (error state)"); + vs_log_mod_error("vsl", + "Exiting Verisocks main loop (error state)"); if (0 <= fd_server_socket) { close(fd_server_socket); fd_server_socket = -1; @@ -82,11 +117,11 @@ template void VslInteg::run() { } -template void VslInteg::main_init() { - +void VslInteg::main_init() { + /* Check state consistency */ if (_state != VSL_STATE_INIT) { - vs_log_error("Wrong state in init function %d", _state); + vs_log_mod_error("vsl", "Wrong state in init function %d", _state); _state = VSL_STATE_ERROR; return; } @@ -94,7 +129,7 @@ template void VslInteg::main_init() { /* Create server socket */ fd_server_socket = vs_server_make_socket(num_port); if (0 > fd_server_socket) { - vs_log_error("Issue making socket at port %d", num_port); + vs_log_mod_error("vsl", "Issue making socket at port %d", num_port); _state = VSL_STATE_ERROR; return; } @@ -103,20 +138,20 @@ template void VslInteg::main_init() { struct sockaddr_in sin; socklen_t len = sizeof(sin); if (0 > getsockname(fd_server_socket, (struct sockaddr *) &sin, &len)) { - vs_log_error("Issue getting socket address info"); + vs_log_mod_error("vsl", "Issue getting socket address info"); _state = VSL_STATE_ERROR; return; } uint32_t s_addr = ntohl(sin.sin_addr.s_addr); /* Logs server address and port number */ - vs_log_info("Server address: %d.%d.%d.%d", + vs_log_mod_info("vsl", "Server address: %d.%d.%d.%d", (s_addr & 0xff000000) >> 24u, (s_addr & 0x00ff0000) >> 16u, (s_addr & 0x0000ff00) >> 8u, (s_addr & 0x000000ff) ); - vs_log_info("Port: %d", ntohs(sin.sin_port)); + vs_log_mod_info("vsl", "Port: %d", ntohs(sin.sin_port)); /* Update state */ _state = VSL_STATE_CONNECT; @@ -124,21 +159,87 @@ template void VslInteg::main_init() { } -template void VslInteg::main_connect() { +void VslInteg::main_connect() { + char hostname_buffer[128]; + struct timeval timeout; + timeout.tv_sec = num_timeout_sec; + timeout.tv_usec = 0; + + vs_log_mod_debug( + "vsl", + "Waiting for a client to connect (%ds timeout) ...", + (int) timeout.tv_sec); + fd_client_socket = vs_server_accept( + fd_server_socket, hostname_buffer, sizeof(hostname_buffer), &timeout); + if (0 > fd_client_socket) { + vs_log_mod_error("vsl", "Failed to connect"); + _state = VSL_STATE_ERROR; + return; + } + vs_log_mod_info("vsl", "Connected to %s", hostname_buffer); + _state = VSL_STATE_WAITING; + return; } -template void VslInteg::main_wait() { -} -template void VslInteg::main_process() { +void VslInteg::main_wait() { + char read_buffer[4096]; + int msg_len; + msg_len = vs_msg_read(fd_client_socket, + read_buffer, + sizeof(read_buffer)); + if (0 > msg_len) { + close(fd_client_socket); + vs_log_mod_debug( + "vsl", + "Lost connection. Waiting for a client to (re-)connect ..." + ); + _state = VSL_STATE_CONNECT; + return; + } + if (msg_len >= (int) sizeof(read_buffer)) { + read_buffer[sizeof(read_buffer) - 1] = '\0'; + vs_log_mod_warning( + "vsl", + "Received message longer than RX buffer, discarding it" + ); + vs_msg_return(fd_client_socket, "error", + "Message too long - Discarding"); + return; + } + else { + read_buffer[msg_len] = '\0'; + } + vs_log_mod_debug("vsl", "Message: %s", &read_buffer[2]); + p_cmd = vs_msg_read_json(read_buffer); + if (nullptr != p_cmd) { + _state = VSL_STATE_PROCESSING; + return; + } + vs_log_mod_warning( + "vsl", + "Received message content cannot be interpreted as a valid JSON \ +content. Discarding it." + ); + vs_msg_return(fd_client_socket, "error", + "Invalid message content - Discarding"); + return; } -template void VslInteg::main_run() { + +void VslInteg::main_process() { + vs_log_mod_info("vsl", "Processing command"); + //TODO + vs_msg_return(fd_client_socket, "info", "Command processing not yet implemented"); + _state = VSL_STATE_WAITING; } +void VslInteg::main_sim() { + vs_log_mod_info("vsl", "Simulation ongoing"); + //TODO +} } //namespace vsl -int main() { } //Temporary for compilation //EOF