diff options
Diffstat (limited to 'src/wm_connection.cpp')
-rw-r--r-- | src/wm_connection.cpp | 457 |
1 files changed, 457 insertions, 0 deletions
diff --git a/src/wm_connection.cpp b/src/wm_connection.cpp new file mode 100644 index 0000000..10ecc3b --- /dev/null +++ b/src/wm_connection.cpp @@ -0,0 +1,457 @@ +/* + * Copyright (c) 2017 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wm_connection.hpp" +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "json_helper.hpp" +#include "util.hpp" + +extern "C" +{ +#include <afb/afb-binding.h> +#include <systemd/sd-event.h> +} + + +/** + * namespace wm + */ +namespace wm +{ + + +namespace +{ + +static const char kPathConnectionConfigFile[] = "/etc/connection.json"; +static const char kDefaultIpAddr[] = "192.168.10.10"; +static const int kDefaultPort = 4000; + +static int onIoEventReceive(sd_event_source *src, int fd, uint32_t revents, void * data) +{ + WMConnection *p_wmcon = (WMConnection*)data; + + json_object *j_out; + int ret = p_wmcon->receive(&j_out); + if (0 > ret) + { + return 0; + } + + const char* rq = jh::getStringFromJson(j_out, "req"); + const char* id = jh::getStringFromJson(j_out, "appid"); + const char* dn = jh::getStringFromJson(j_out, "drawing_name"); + const char* da = jh::getStringFromJson(j_out, "drawing_area"); + + HMI_DEBUG("req:%s appid:%s, drawing_name:%s, drawing_area:%s", rq, id, dn, da); + + // Callback + p_wmcon->callOnReceivedHandler(j_out); + + return 0; +} + +static int onIoEventAccept(sd_event_source *src, int fd, uint32_t revents, void * data) +{ + struct sockaddr_in addr; + + WMConnection *p_wmcon = (WMConnection*)data; + + // Accept connection + socklen_t len = sizeof(addr); + int my_socket = p_wmcon->getMySocket(); + int connected_socket = accept(my_socket, (struct sockaddr *)&addr, &len); + if (0 > connected_socket) + { + HMI_ERROR("Failed to accept connection (%s)", strerror(errno)); + return -1; + } + + // Store connected socket + p_wmcon->setConnectedSocket(connected_socket); + + // Register callback to receive + int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr, + connected_socket, EPOLLIN, + onIoEventReceive, p_wmcon); + if (0 > ret) + { + HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret)); + return -1; + } + + return 0; +} + +} // namespace + +WMConnection::WMConnection() +{ + // Load connection config file + this->loadConnectionConfigFile(); + + // TODO: ECU name should be decide by config file + this->ecu_name = this->mode; +} + +int WMConnection::initialize() +{ + int ret; + + // Initialize for Master/Slave + if (this->isMasterMode()) + { + ret = this->initializeMaster(); + } + else + { + ret = this->initializeSlave(); + } + + return ret; +} + +void WMConnection::registerCallback(ReceivedHandler on_received) +{ + this->onReceived = on_received; +} + +int WMConnection::sendRequest(char const *req, char const *appid, + char const *drawing_name, char const *drawing_area) +{ + int ret; + json_object *j_obj = json_object_new_object(); + json_object_object_add(j_obj, "req", json_object_new_string(req)); + json_object_object_add(j_obj, "appid", json_object_new_string(appid)); + json_object_object_add(j_obj, "drawing_name", json_object_new_string(drawing_name)); + json_object_object_add(j_obj, "drawing_area", json_object_new_string(drawing_area)); + + ret = this->send(j_obj); + + json_object_put(j_obj); + + return ret; +} + +int WMConnection::send(struct json_object* j_in) +{ + // Convert json_object to string to send + const char *buf = json_object_to_json_string(j_in); + if (nullptr == buf) + { + HMI_ERROR("Failed to convert json_object to string"); + return -1; + } + + int len = strlen(buf); + + HMI_DEBUG("Send data(len:%d): %s", len, buf); + + int n = write(this->connected_socket, buf, len); + if(0 > n) + { + HMI_ERROR("Failed to send data (%s)", strerror(errno)); + return -1; + } + + return 0; +} + +bool WMConnection::isMasterMode() +{ + if ("master" == this->mode) + { + return true; + } + else + { + return false; + } +} + +bool WMConnection::isMasterArea(const char* area) +{ + if (nullptr == area) + { + return false; + } + + std::string str_area = std::string(area); + if ("" == str_area) + { + return false; + } + + std::vector<std::string> elements; + elements = parseString(str_area, '.'); + + if ("master" == elements[0]) + { + return true; + } + else + { + return false; + } +} + +bool WMConnection::isConnecting() +{ + return (0 > this->connected_socket) ? false : true; +} + +std::string WMConnection::parseMasterArea(const char* area) +{ + std::string ret_area = ""; + std::vector<std::string> elements; + elements = parseString(std::string(area), '.'); + + if ("master" != elements[0]) + { + return std::string(area); + } + + for (auto itr = (elements.begin() + 1); itr != elements.end(); ++itr) + { + ret_area += *itr; + + if ((elements.end() - 1) != itr) + { + ret_area += "."; + } + } + return ret_area; +} + +bool WMConnection::isSyncDrawingForRemote(const char* appid) +{ + if (std::string(appid) == this->syndDrawingAppId) + { + return true; + } + else + { + return false; + } +} + +void WMConnection::startSyncDrawForRemote(const char* appid) +{ + this->syndDrawingAppId = std::string(appid); +} + +void WMConnection::finishSyncDrawForRemote(const char* appid) +{ + if (std::string(appid) == this->syndDrawingAppId) + { + this->syndDrawingAppId = ""; + } +} + +int WMConnection::getMySocket() +{ + return this->my_socket; +} + +int WMConnection::getConnectedSocket() +{ + return this->connected_socket; +} + +void WMConnection::setConnectedSocket(int connected_socket) +{ + this->connected_socket = connected_socket; +} + +std::string WMConnection::getEcuName() +{ + return this->ecu_name; +} + +void WMConnection::callOnReceivedHandler(json_object *j_out) +{ + this->onReceived(j_out); +} + +int WMConnection::initializeMaster() +{ + int ret = 0; + struct sockaddr_in addr; + + // Create socket + this->my_socket = socket(AF_INET, SOCK_STREAM, 0); + if (0 > this->my_socket) + { + HMI_ERROR("Failed to create socket (%s)", strerror(errno)); + return -1; + } + + // Bind socket + addr.sin_family = AF_INET; + addr.sin_port = htons(this->port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + ret = bind(this->my_socket, (struct sockaddr *)&addr, sizeof(addr)); + if (0 > ret) + { + HMI_ERROR("Failed to bind socket (%s)", strerror(errno)); + return -1; + } + + // Listen connection + ret = listen(this->my_socket, 1); + if (0 > ret) + { + HMI_ERROR("Failed to listen connection (%s)", strerror(errno)); + return -1; + } + + // Register callback to accept connection + ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr, + this->my_socket, EPOLLIN, + onIoEventAccept, this); + if (0 > ret) + { + HMI_ERROR("Failed to add I/O event accept(%s)", strerror(-ret)); + return -1; + } + + return ret; +} + +int WMConnection::initializeSlave() +{ + // Create socket + this->my_socket = socket(AF_INET, SOCK_STREAM, 0); + if (0 > this->my_socket) + { + HMI_ERROR("Failed to create socket (%s)", strerror(errno)); + return -1; + } + + return 0; +} + +int WMConnection::connectToMaster() +{ + int ret = 0; + struct sockaddr_in addr; + + // Connect to master + addr.sin_family = AF_INET; + addr.sin_port = htons(this->port); + addr.sin_addr.s_addr = inet_addr(this->ip.c_str()); + + ret = connect(this->my_socket, (struct sockaddr *)&addr, sizeof(addr)); + if (0 > ret) + { + HMI_ERROR("Failed to connect to master (%s)", strerror(errno)); + return ret; + } + + HMI_DEBUG("Connected to master"); + + // Store connected socket + this->connected_socket = this->my_socket; + + // Register callback to receive + ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr, + this->connected_socket, EPOLLIN, + onIoEventReceive, this); + if (0 > ret) + { + HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret)); + return -1; + } + + return ret; +} + +int WMConnection::receive(struct json_object** j_out) +{ + char buf[1024]; + int n; + + n = read(this->connected_socket, buf, sizeof(buf)); + if(0 > n) + { + HMI_ERROR("Failed to receive data (%s)", strerror(errno)); + return -1; + } + + HMI_DEBUG("Received data length: %d", n); + HMI_DEBUG("Received data: %s", buf); + + // Parse received data + struct json_tokener *tokener = json_tokener_new(); + *j_out = json_tokener_parse_ex(tokener, buf, n); + if (nullptr == *j_out) + { + HMI_DEBUG("Failed to parse received data"); + return -1; + } + + return 0; +} + +int WMConnection::loadConnectionConfigFile() +{ + // Get afm application installed dir + char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR"); + if (!afm_app_install_dir) + { + HMI_ERROR("AFM_APP_INSTALL_DIR is not defined"); + } + std::string path = std::string(afm_app_install_dir) + std::string(kPathConnectionConfigFile); + + // Load connection config file + json_object* json_obj; + int ret = jh::inputJsonFilie(path.c_str(), &json_obj); + if (0 > ret) + { + HMI_ERROR("Could not open %s, so use default mode \"slave\"", kPathConnectionConfigFile); + this->mode = "slave"; + this->ip = kDefaultIpAddr; + this->port = kDefaultPort; + return 0; + } + HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj)); + + const char* mode = jh::getStringFromJson(json_obj, "mode"); + this->mode = (nullptr != mode) ? mode : "slave"; + + const char* ip = jh::getStringFromJson(json_obj, "master_ip"); + this->ip = (nullptr != ip) ? ip : kDefaultIpAddr; + + int port = jh::getIntFromJson(json_obj, "master_port"); + this->port = (0 != port) ? port : kDefaultPort; + + // Check + HMI_DEBUG("mode:%s master_ip:%s master_port:%d", mode, ip, port); + + // Release json_object + json_object_put(json_obj); + + return 0; +} + + +} // namespace wm |