diff --git a/apps/HeadUnit/CMakeLists.txt b/apps/HeadUnit/CMakeLists.txt index c31a9a6..99b4495 100644 --- a/apps/HeadUnit/CMakeLists.txt +++ b/apps/HeadUnit/CMakeLists.txt @@ -5,14 +5,25 @@ project(HeadUnit VERSION 0.1 LANGUAGES CXX) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) +set(VSOMEIP_CONFIG_FILES "./vsomeip.json") find_package(Qt6 6.5 REQUIRED COMPONENTS Quick Qml) +find_package(Qt6 REQUIRED COMPONENTS Quick WebEngineWidgets Qml) +find_package(vsomeip3 3.5.3 REQUIRED) +find_package( Boost 1.55 COMPONENTS system thread log REQUIRED) + +include_directories( + ${Boost_INCLUDE_DIR} + ${VSOMEIP_INCLUDE_DIR} + ) qt_standard_project_setup(REQUIRES 6.5) qt_add_executable(head-unit main.cpp + HeadUnit.cpp + # SpeedClient.cpp resources.qrc shared/utils/envmanager.h @@ -22,6 +33,12 @@ qt_add_executable(head-unit modules/spotify/spotify.h modules/spotify/spotify.cpp + HeadUnit.h + clients/speed_client/speed_client.cpp + clients/battery_client/battery_client.cpp + clients/gear_data_receiving_client/gear_client.cpp + clients/ambient_sender/alsender.cpp + ${VSOMEIP_CONFIG_FILES} ) qt_add_qml_module(head-unit @@ -40,10 +57,18 @@ qt_add_qml_module(head-unit modules/youtube/Youtube_main.qml SOURCES + HeadUnit.h + clients/speed_client/speed_client.hpp + clients/battery_client/battery_client.hpp + clients/gear_data_receiving_client/gear_client.hpp + clients/ambient_sender/alsender.hpp + clients/server.hpp modules/spotify/spotify.h modules/spotify/spotify.cpp shared/utils/envmanager.h shared/utils/envmanager.cpp + shared/utils/someip.cpp + shared/utils/someip.h DEPENDENCIES QtQuick QtQml @@ -53,8 +78,14 @@ qt_add_qml_module(head-unit ) -find_package(Qt6 REQUIRED COMPONENTS Quick WebEngineWidgets Qml) -target_link_libraries(head-unit PRIVATE Qt6::Quick Qt6::WebEngineWidgets Qt6::Qml) +target_link_libraries(head-unit + PRIVATE + vsomeip3 + ${Boost_LIBRARIES} + Qt6::Quick + Qt6::WebEngineWidgets + Qt6::Qml +) find_package(Qt6 6.5 REQUIRED COMPONENTS Quick Qml Bluetooth) target_link_libraries(head-unit PRIVATE Qt6::Bluetooth) diff --git a/apps/HeadUnit/HeadUnit.cpp b/apps/HeadUnit/HeadUnit.cpp new file mode 100644 index 0000000..8f5c357 --- /dev/null +++ b/apps/HeadUnit/HeadUnit.cpp @@ -0,0 +1,72 @@ +#include "HeadUnit.h" + +HeadUnit::HeadUnit(QObject* parent) + : QObject(parent) +{} + +const QString& HeadUnit::currentGear() const +{ + return _currentGear; +} + +int HeadUnit::ambientLighting() +{ + return _ambientLighting; +} + +int HeadUnit::speed() const +{ + return _speed; +} + +int HeadUnit::batteryPercentage() const +{ + return _batteryPercentage; +} + +bool HeadUnit::chargingState() const +{ + return _chargingState; +} + +void HeadUnit::setCurrentGear(const QString& gear) +{ + if (_currentGear != gear) { + _currentGear = gear; + emit currentGearChanged(gear); + } +} + +void HeadUnit::setAmbientLighting(int colorValue) +{ + if (_ambientLighting != colorValue) { + _ambientLighting = colorValue; + emit ambientLightingChanged(colorValue); + } +} + +void HeadUnit::setSpeed(int speed) +{ + if (_speed != speed) { + _speed = speed; + emit speedChanged(speed); + } +} + +void HeadUnit::setBatteryPercentage(int batteryPercentage) +{ + if (_batteryPercentage != batteryPercentage) { + _batteryPercentage = batteryPercentage; + emit batteryPercentageChanged(batteryPercentage); + } +} + +void HeadUnit::setChargingState(bool state) +{ + if (_chargingState != state) { + _chargingState = state; + emit chargingStateChanged(state); + } +} + + diff --git a/apps/HeadUnit/HeadUnit.h b/apps/HeadUnit/HeadUnit.h new file mode 100644 index 0000000..befae76 --- /dev/null +++ b/apps/HeadUnit/HeadUnit.h @@ -0,0 +1,42 @@ +#pragma once + +#include + +class HeadUnit : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString currentGear READ currentGear WRITE setCurrentGear NOTIFY currentGearChanged) + Q_PROPERTY(int ambientLighting READ ambientLighting WRITE setAmbientLighting NOTIFY ambientLightingChanged) + Q_PROPERTY(int speed READ speed WRITE setSpeed NOTIFY speedChanged) + Q_PROPERTY(int batteryPercentage READ batteryPercentage WRITE setBatteryPercentage NOTIFY batteryPercentageChanged) + Q_PROPERTY(int chargingState READ chargingState WRITE setChargingState NOTIFY chargingStateChanged) + +public: + explicit HeadUnit(QObject *parent = nullptr); + + const QString& currentGear() const; + int ambientLighting(); + int speed() const; + int batteryPercentage() const; + bool chargingState() const; + + void setAmbientLighting(int colorValue); + void setCurrentGear(const QString& gear); + void setSpeed(int speed); + void setBatteryPercentage(int batteryPercentage); + void setChargingState(bool state); + +signals: + void currentGearChanged(const QString& gear); + void ambientLightingChanged(int colorValue); + void speedChanged(int speed); + void batteryPercentageChanged(int batteryPercentage); + void chargingStateChanged(bool state); + +private: + QString _currentGear = "P"; + int _speed = 0; + int _ambientLighting = 0; + int _batteryPercentage = 100; + bool _chargingState = false; +}; diff --git a/apps/HeadUnit/Main.qml b/apps/HeadUnit/Main.qml index c961a77..b257906 100644 --- a/apps/HeadUnit/Main.qml +++ b/apps/HeadUnit/Main.qml @@ -7,14 +7,14 @@ import HeadUnit 1.0 Window { id: window + visible: true width: 1024 height: 600 - visible: true + title: qsTr("HeadUnit") color: "black" - property int colorValue: 180 - property color myColor: Qt.hsva(colorValue / 360, 1, 1, 1) - + property int ambientLighting: HeadUnit.ambientLighting + property color myColor: Qt.hsva(ambientLighting / 360, 1, 1, 1) MediaPlayer { id: mediaPlayer audioOutput: AudioOutput {id: audioOutput} @@ -123,8 +123,10 @@ Window { z:1 ColumnLayout { + id: gearColumn anchors.centerIn: parent spacing:0 + property string activeGear: "park" Rectangle { Layout.preferredWidth: 110 @@ -135,18 +137,17 @@ Window { id: drive height: 40 x: 40 - y: 20 + y: 15 source: "qrc:/shared/images/drive" fillMode: Image.PreserveAspectFit - // anchors.centerIn: parent smooth: true mipmap: true - + opacity: 0 } ColorOverlay { anchors.fill: drive source: drive - color: myColor + color: gearColumn.activeGear === "drive" ? myColor : Qt.darker(myColor, 2.5) smooth: true } //Glowing Effect @@ -173,6 +174,23 @@ Window { PropertyChanges { target: glowEffectD; radius: 0; spread: 0; opacity: 0; visible: false } } ] + Connections { + target: gearClient + onGearValueChanged: { + if (newGearValue == 3) { + glowEffectD.radius = 16; + glowEffectD.spread = 0.6; + glowEffectD.opacity = 0.5; + glowEffectD.visible = true; + } else { + glowEffectD.radius = 0; + glowEffectD.spread = 0; + glowEffectD.opacity = 0; + glowEffectD.visible = false; + } + } + } + transitions: [ Transition { NumberAnimation { @@ -187,6 +205,8 @@ Window { anchors.fill: parent onClicked: { console.log("D clicked") + gearColumn.activeGear = "drive" + someIP.set_gear_data(3); } } } @@ -199,19 +219,18 @@ Window { Image { id: neutral height: 40 - x: 40 - y: 20 + x: 38 + y: 22 source: "qrc:/shared/images/neutral" fillMode: Image.PreserveAspectFit - // anchors.centerIn: parent smooth: true mipmap: true - + opacity: 0 } ColorOverlay { anchors.fill: neutral source: neutral - color: myColor + color: gearColumn.activeGear === "neutral" ? myColor : Qt.darker(myColor, 2.5) smooth: true } //Glowing Effect @@ -238,6 +257,22 @@ Window { PropertyChanges { target: glowEffectN; radius: 0; spread: 0; opacity: 0; visible: false } } ] + Connections { + target: gearClient + onGearValueChanged: { + if (newGearValue == 2) { + glowEffectN.radius = 16; + glowEffectN.spread = 0.6; + glowEffectN.opacity = 0.5; + glowEffectN.visible = true; + } else { + glowEffectN.radius = 0; + glowEffectN.spread = 0; + glowEffectN.opacity = 0; + glowEffectN.visible = false; + } + } + } transitions: [ Transition { NumberAnimation { @@ -252,6 +287,8 @@ Window { anchors.fill: parent onClicked: { console.log("N clicked") + gearColumn.activeGear = "neutral" + someIP.set_gear_data(2); } } } @@ -265,18 +302,17 @@ Window { id: reverse height: 40 x: 40 - y: 30 + y: 35 source: "qrc:/shared/images/reverse" fillMode: Image.PreserveAspectFit - // anchors.centerIn: parent smooth: true mipmap: true - + opacity: 0 } ColorOverlay { anchors.fill: reverse source: reverse - color: myColor + color: gearColumn.activeGear === "reverse" ? myColor : Qt.darker(myColor, 2.5) smooth: true } //Glowing Effect @@ -303,6 +339,22 @@ Window { PropertyChanges { target: glowEffectR; radius: 0; spread: 0; opacity: 0; visible: false } } ] + Connections { + target: gearClient + onGearValueChanged: { + if (newGearValue == 1) { + glowEffectR.radius = 16; + glowEffectR.spread = 0.6; + glowEffectR.opacity = 0.5; + glowEffectR.visible = true; + } else { + glowEffectR.radius = 0; + glowEffectR.spread = 0; + glowEffectR.opacity = 0; + glowEffectR.visible = false; + } + } + } transitions: [ Transition { NumberAnimation { @@ -317,6 +369,8 @@ Window { anchors.fill: parent onClicked: { console.log("R clicked") + gearColumn.activeGear = "reverse" + someIP.set_gear_data(1); } } } @@ -329,18 +383,17 @@ Window { id: park height: 40 x: 40 - y: 35 + y: 43 source: "qrc:/shared/images/park" fillMode: Image.PreserveAspectFit - // anchors.centerIn: parent smooth: true mipmap: true - + opacity: 0 } ColorOverlay { anchors.fill: park source: park - color: myColor + color: gearColumn.activeGear === "park" ? myColor : Qt.darker(myColor, 2.5) smooth: true } //Glowing Effect @@ -367,6 +420,22 @@ Window { PropertyChanges { target: glowEffectP; radius: 0; spread: 0; opacity: 0; visible: false } } ] + Connections { + target: gearClient + onGearValueChanged: { + if (newGearValue == 0) { + glowEffectP.radius = 16; + glowEffectP.spread = 0.6; + glowEffectP.opacity = 0.5; + glowEffectP.visible = true; + } else { + glowEffectP.radius = 0; + glowEffectP.spread = 0; + glowEffectP.opacity = 0; + glowEffectP.visible = false; + } + } + } transitions: [ Transition { NumberAnimation { @@ -380,7 +449,9 @@ Window { id: mouseAreaP anchors.fill: parent onClicked: { - console.log("D clicked") + console.log("P clicked") + gearColumn.activeGear = "park" + someIP.set_gear_data(0); } } } @@ -404,6 +475,7 @@ Window { anchors.centerIn: parent smooth: true mipmap: true + opacity: 0 } ColorOverlay { anchors.fill: menuIcon @@ -492,26 +564,26 @@ Window { } } } - - Image { - id: gearHighlights - source: "qrc:/shared/images/gearlines" - anchors.left: parent.left - y: 50 - anchors.leftMargin: 5 - fillMode: Image.PreserveAspectFit - width: 110 - smooth: true - mipmap: true - z:2 - - } - ColorOverlay { - anchors.fill: gearHighlights - source: gearHighlights - color: myColor - smooth: true - z:2 + ColumnLayout{ + x: 25 + y: 165 + spacing: 110 + opacity: 0.7 + Rectangle{ + width:70 + height: 2 + color: myColor + } + Rectangle{ + width: 70 + height: 2 + color: myColor + } + Rectangle{ + width: 70 + height: 2 + color: myColor + } } Slider { @@ -573,7 +645,7 @@ Window { id: settings Settings { onColorValueChanged: (value) => { - colorValue = value + ambientLighting = value // Use the value here } } diff --git a/apps/HeadUnit/clients/HU_gear_client/gear_client.cpp b/apps/HeadUnit/clients/HU_gear_client/gear_client.cpp new file mode 100644 index 0000000..f6dee5a --- /dev/null +++ b/apps/HeadUnit/clients/HU_gear_client/gear_client.cpp @@ -0,0 +1,83 @@ +#include +#include +#include + +#include +#include + +#include +#include "../server.hpp" +#include "./gear_client.hpp" + +std::shared_ptr< vsomeip::application > app; +std::mutex mutex; +std::condition_variable condition; + +//sending the actual data (will be gear data) to server. +void run() { + std::unique_lock its_lock(mutex); + condition.wait(its_lock); + + std::shared_ptr< vsomeip::message > request; + request = vsomeip::runtime::get()->create_request(); + request->set_service(VEHICLE_SERVICE_ID); + request->set_instance(GEAR_INSTANCE_ID); + request->set_method(GEAR_SET_METHOD_ID); + +//sending actual data. changed into HU input value. + int value=0; + + while (1){ + // value += 1; + if (value != 5) + {std::cout << "Input number" << std::endl; + std::cin >> value;} + std::shared_ptr< vsomeip::payload > its_payload = vsomeip::runtime::get()->create_payload(); + std::vector its_payload_data( + reinterpret_cast(&value), + reinterpret_cast(&value) + sizeof(int) + ); + its_payload->set_data(its_payload_data); + request->set_payload(its_payload); + app->send(request); + std::this_thread::sleep_for(std::chrono::milliseconds(80)); + + } + std::cout << "CLIENT : DATA SENDED" << std::endl; +} + +// When response come, print the payload from server. +void on_message(const std::shared_ptr &_response) { + std::shared_ptr its_payload = _response->get_payload(); + vsomeip::length_t l = its_payload->get_length(); + + // Get payload + std::stringstream ss; + for (vsomeip::length_t i=0; iget_data()+i) << " "; + } + + std::cout << "CLIENT: Received message with Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_session() << "] " + << ss.str() << std::endl; +} + +void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) { + std::cout + << (_is_available ? "available." : "NOT available.") + << std::endl; +} + +int main() { + + app = vsomeip::runtime::get()->create_application("gear"); + app->init(); + app->register_availability_handler(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, on_availability); + std::this_thread::sleep_for(std::chrono::seconds(1)); + app->request_service(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID); + app->register_message_handler(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, JOY_GEAR_RESPONSE_MID, on_message); + std::thread sender(run); + app->start(); +} diff --git a/apps/HeadUnit/clients/HU_gear_client/gear_client.hpp b/apps/HeadUnit/clients/HU_gear_client/gear_client.hpp new file mode 100644 index 0000000..1e24653 --- /dev/null +++ b/apps/HeadUnit/clients/HU_gear_client/gear_client.hpp @@ -0,0 +1,34 @@ +#ifndef GEAR_CLIENT_HPP +# define GEAR_CLIENT_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../server.hpp" + +class gearClient { +public: + gearClient(bool _use_tcp); + + bool init(); + void start(); + void stop(); + +private: + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr& _response); + + std::shared_ptr app_; + bool use_tcp_; + + gearClient(void); + ~gearClient(void); +}; + +#endif \ No newline at end of file diff --git a/apps/HeadUnit/clients/J_gear_client/gear_client.cpp b/apps/HeadUnit/clients/J_gear_client/gear_client.cpp new file mode 100644 index 0000000..aaa94a1 --- /dev/null +++ b/apps/HeadUnit/clients/J_gear_client/gear_client.cpp @@ -0,0 +1,99 @@ +#include +#include +#include + +#include +#include +#include + +#include "../server.hpp" +#include "./gear_client.hpp" +std::shared_ptr< vsomeip::application > app; +std::mutex mutex; +std::condition_variable condition; + +//TODO: sending the actual data (will be gear data) to server. + +// VEHICLE_SERVICE_ID, etc IDs are defined in src/server.hpp + +// void run(int gearValue) { +void run() { + // on avaliability notify this thread that client is connected to server + std::unique_lock its_lock(mutex); + condition.wait(its_lock); + + //create request + std::shared_ptr< vsomeip::message > request; + request = vsomeip::runtime::get()->create_request(); + //basic setting + request->set_service(VEHICLE_SERVICE_ID); + request->set_instance(GEAR_INSTANCE_ID); + request->set_method(JOY_GEAR_SET_MID); + +//sending actual data. changed into HU input value. + int value=0; // <- real gear value should be on value variable + while (1){ + // std::cout << "Input number" << std::endl; + // std::cin >> value; + + std::shared_ptr< vsomeip::payload > its_payload = vsomeip::runtime::get()->create_payload(); + std::vector its_payload_data( + reinterpret_cast(&value), + reinterpret_cast(&value) + sizeof(int) + // reinterpret_cast(&gearValue), + // reinterpret_cast(&gearValue) + sizeof(int) + ); + its_payload->set_data(its_payload_data); + request->set_payload(its_payload); + app->send(request); + std::cout << "CLIENT : DATA SENDED" << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(1)); + + } +} +// PARKING 0 +// REVERSE 1 +// NEUTRAL 2 +// DRIVE 3 + +// When response come, print the payload from server. +void on_message(const std::shared_ptr &_response) { + std::shared_ptr payload = _response->get_payload(); + int received_value = 0; + + if (payload->get_length() >= sizeof(int)) { + received_value = *reinterpret_cast(payload->get_data()); + std::cout << "SERVER: Received int: " << received_value << std::endl; + } else { + std::cerr << "SERVER: Invalid payload size!" << std::endl; + return; + } + // +} + +// 서버랑 연결이 안되어있을때 전송을 할수도있어 +// vsomeip는 /tmp/vsomeip-100 103~~~ +// 얘가 소켓이 꼬여. 그래서 데이터 안가 제대로 연결이 됐어도 그래서 그냥 두는게 나을거같다. +void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) { + std::cout << "CLIENT: Service [" + << std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance + << "] is " + << (_is_available ? "available." : "NOT available.") + << std::endl; + if (_is_available) { + std::this_thread::sleep_for(std::chrono::seconds(3)); + condition.notify_one(); + } +} + +int main() { + app = vsomeip::runtime::get()->create_application("gear"); + app->init(); + app->register_availability_handler(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, on_availability); + std::this_thread::sleep_for(std::chrono::seconds(1)); + app->request_service(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID); + std::this_thread::sleep_for(std::chrono::seconds(1)); + app->register_message_handler(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, JOY_GEAR_SET_MID, on_message); + std::thread sender(run); + app->start(); +} diff --git a/apps/HeadUnit/clients/J_gear_client/gear_client.hpp b/apps/HeadUnit/clients/J_gear_client/gear_client.hpp new file mode 100644 index 0000000..1e24653 --- /dev/null +++ b/apps/HeadUnit/clients/J_gear_client/gear_client.hpp @@ -0,0 +1,34 @@ +#ifndef GEAR_CLIENT_HPP +# define GEAR_CLIENT_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../server.hpp" + +class gearClient { +public: + gearClient(bool _use_tcp); + + bool init(); + void start(); + void stop(); + +private: + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr& _response); + + std::shared_ptr app_; + bool use_tcp_; + + gearClient(void); + ~gearClient(void); +}; + +#endif \ No newline at end of file diff --git a/apps/HeadUnit/clients/ambient_sender/alsender.cpp b/apps/HeadUnit/clients/ambient_sender/alsender.cpp new file mode 100644 index 0000000..c6a0227 --- /dev/null +++ b/apps/HeadUnit/clients/ambient_sender/alsender.cpp @@ -0,0 +1,47 @@ +#include "./alsender.hpp" + +void Alsender::set_al_data(int al) { + std::cout << "[set al data function] value : "<< al << std::endl; + std::shared_ptr request; + + request = vsomeip::runtime::get()->create_request(); + request->set_service(VEHICLE_SERVICE_ID); + request->set_instance(AL_INSTANCE_ID); + request->set_method(AL_SET_METHOD_ID); + + std::shared_ptr< vsomeip::payload > its_payload = vsomeip::runtime::get()->create_payload(); + std::vector its_payload_data( + reinterpret_cast(&al), + reinterpret_cast(&al) + sizeof(int)); + + its_payload->set_data(its_payload_data); + request->set_payload(its_payload); + app->send(request); + std::cout << "HEAD UNIT : AL DATA SENDED" << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(1)); + return ; +} + +void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) { + std::cout << (_is_available ? "AL available." : "AL NOT available.") << std::endl; +} + +void Alsender::start() { + std::thread al_thread([this](){ + app->start();}); + al_thread.detach(); +} + +bool Alsender::init() { + if (!app->init()) + { + std::cerr << "Couldn't initialize application" << std::endl; + return false; + } + app->register_availability_handler(VEHICLE_SERVICE_ID, AL_INSTANCE_ID, on_availability); + std::this_thread::sleep_for(std::chrono::seconds(1)); + + app->request_service(VEHICLE_SERVICE_ID, AL_INSTANCE_ID); + this->start(); + return true; +} \ No newline at end of file diff --git a/apps/HeadUnit/clients/ambient_sender/alsender.hpp b/apps/HeadUnit/clients/ambient_sender/alsender.hpp new file mode 100644 index 0000000..50ea5b7 --- /dev/null +++ b/apps/HeadUnit/clients/ambient_sender/alsender.hpp @@ -0,0 +1,35 @@ +#ifndef ALSENDER_H +#define ALSENDER_H + +#include "../headers.hpp" +#include "../server.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +class Alsender : public QObject +{ + Q_OBJECT +public: + std::shared_ptr app; + bool init(); + void start(); + + explicit Alsender(QObject *parent = nullptr) : QObject(parent), app(vsomeip::runtime::get()->create_application("ambient")){ + } + // Q_INVOKABLE void set_gear_data(int gearValue); + Q_INVOKABLE void set_al_data(int); + // Q_INVOKABLE void send_gear_data(int); + +}; + +#endif // SOMEIP_H diff --git a/apps/HeadUnit/clients/battery_client/battery_client.cpp b/apps/HeadUnit/clients/battery_client/battery_client.cpp new file mode 100644 index 0000000..b384d7b --- /dev/null +++ b/apps/HeadUnit/clients/battery_client/battery_client.cpp @@ -0,0 +1,101 @@ +#include "./battery_client.hpp" + +BatteryClient::BatteryClient(QObject *parent) + : QObject(parent), + batteryValue(0), + app_(vsomeip::runtime::get()->create_application("battery")) +{ +} + +bool BatteryClient::init() +{ + if (!app_->init()) { + std::cerr << "Couldn't initialize application" << std::endl; + return false; + } + + // 상태 핸들러 등록 + app_->register_state_handler( + std::bind(&BatteryClient::on_state, this, std::placeholders::_1)); + + // 메시지 핸들러 등록 + app_->register_message_handler( + vsomeip::ANY_SERVICE, BATTERY_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&BatteryClient::on_message, this, std::placeholders::_1)); + + // 가용성 핸들러 등록 + app_->register_availability_handler(VEHICLE_SERVICE_ID, BATTERY_INSTANCE_ID, + std::bind(&BatteryClient::on_availability, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + + // 이벤트 구독 + std::set its_groups; + its_groups.insert(VEHICLE_EVENTGROUP_ID); + + app_->request_event( + VEHICLE_SERVICE_ID, + BATTERY_INSTANCE_ID, + BATTERY_EVENT_ID, + its_groups, + vsomeip::event_type_e::ET_FIELD); + + app_->subscribe(VEHICLE_SERVICE_ID, BATTERY_INSTANCE_ID, VEHICLE_EVENTGROUP_ID); + + return true; +} + +void BatteryClient::start() +{ + // 별도 스레드에서 실행 + std::thread vsomeip_thread([this]() { + app_->start(); + }); + vsomeip_thread.detach(); // 백그라운드 실행 +} + +// void BatteryClient::start() { +// app_->start(); +// } + +void BatteryClient::stop() +{ + app_->clear_all_handler(); + app_->unsubscribe(VEHICLE_SERVICE_ID, BATTERY_INSTANCE_ID, VEHICLE_EVENTGROUP_ID); + app_->release_event(VEHICLE_SERVICE_ID, BATTERY_INSTANCE_ID, BATTERY_EVENT_ID); + app_->release_service(VEHICLE_SERVICE_ID, BATTERY_INSTANCE_ID); + app_->stop(); +} + +void BatteryClient::on_state(vsomeip::state_type_e _state) +{ + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(VEHICLE_SERVICE_ID, BATTERY_INSTANCE_ID); + } +} + +void BatteryClient::on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) +{ + std::cout << "Service [" + << std::hex << std::setfill('0') << std::setw(4) << _service << "." + << std::setw(4) << _instance << "] is " + << (_is_available ? "available." : "NOT available.") << std::endl; +} + +void BatteryClient::on_message(const std::shared_ptr &_response) +{ + std::shared_ptr payload = _response->get_payload(); + int received_value = 0; + + if (payload->get_length() >= sizeof(int)) { + received_value = *reinterpret_cast(payload->get_data()); + std::cout << "SERVER: Received int: " << received_value << std::endl; + if (this->batteryValue != received_value) + { + this->batteryValue = received_value; + emit batteryValueChanged(received_value); + } + } else { + std::cerr << "SERVER: Invalid payload size!" << std::endl; + return; + } +} diff --git a/apps/HeadUnit/clients/battery_client/battery_client.hpp b/apps/HeadUnit/clients/battery_client/battery_client.hpp new file mode 100644 index 0000000..d6258dc --- /dev/null +++ b/apps/HeadUnit/clients/battery_client/battery_client.hpp @@ -0,0 +1,33 @@ +#ifndef BATTERY_CLIENTHPP +#define BATTERY_CLIENTHPP + +#include + +#include "../headers.hpp" +#include "../server.hpp" + +class BatteryClient : public QObject +{ + Q_OBJECT + +public: + explicit BatteryClient(QObject *parent = nullptr); + + bool init(); + void start(); + void stop(); + int batteryValue; + +signals: + void batteryValueChanged(int newBatteryValue); + +private: + + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr& _response); + + std::shared_ptr app_; +}; + +#endif // BATTERY_CLIENTHPP diff --git a/apps/HeadUnit/clients/gear_data_receiving_client/gear_client.cpp b/apps/HeadUnit/clients/gear_data_receiving_client/gear_client.cpp new file mode 100644 index 0000000..63405c3 --- /dev/null +++ b/apps/HeadUnit/clients/gear_data_receiving_client/gear_client.cpp @@ -0,0 +1,98 @@ +#include "./gear_client.hpp" + +GearClient::GearClient(QObject *parent) + : QObject(parent), + gearValue(0), + app_(vsomeip::runtime::get()->create_application("gear")) +{ +} + +bool GearClient::init() +{ + if (!app_->init()) + { + std::cerr << "Couldn't initialize application" << std::endl; + return false; + } + + // 상태 핸들러 등록 + app_->register_state_handler( + std::bind(&GearClient::on_state, this, std::placeholders::_1)); + + // 메시지 핸들러 등록 + app_->register_message_handler( + vsomeip::ANY_SERVICE, GEAR_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&GearClient::on_message, this, std::placeholders::_1)); + + // 가용성 핸들러 등록 + app_->register_availability_handler(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, + std::bind(&GearClient::on_availability, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + + // 이벤트 구독 + std::set its_groups; + its_groups.insert(VEHICLE_EVENTGROUP_ID); + + app_->request_event( + VEHICLE_SERVICE_ID, + GEAR_INSTANCE_ID, + GEAR_EVENT_ID, + its_groups, + vsomeip::event_type_e::ET_FIELD); + + app_->subscribe(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, VEHICLE_EVENTGROUP_ID); + + return true; +} + +void GearClient::start() +{ + // 별도 스레드에서 실행 + std::thread vsomeip_thread([this]() + { app_->start(); }); + vsomeip_thread.detach(); // 백그라운드 실행 +} + +// void GearClient::start() { +// app_->start(); +// } + +void GearClient::stop() +{ + app_->clear_all_handler(); + app_->unsubscribe(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, VEHICLE_EVENTGROUP_ID); + app_->release_event(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, GEAR_EVENT_ID); + app_->release_service(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID); + app_->stop(); +} + +void GearClient::on_state(vsomeip::state_type_e _state) +{ + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID); + } +} + +void GearClient::on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) +{ + std::cout << "Service [" + << std::hex << std::setfill('0') << std::setw(4) << _service << "." + << std::setw(4) << _instance << "] is " + << (_is_available ? "available." : "NOT available.") << std::endl; +} + +void GearClient::on_message(const std::shared_ptr &_request) +{ + std::shared_ptr payload = _request->get_payload(); + int received_value = 0; + + if (payload->get_length() >= sizeof(int)) { + received_value = *reinterpret_cast(payload->get_data()); + std::cout << "GEAR DATA RECEIVING CLIENT : Received int: " << received_value << std::endl; + this->gearValue = received_value; + emit gearValueChanged(received_value); + } else { + std::cerr << "GEAR DATA RECEIVING CLIENT : Invalid payload size!" << std::endl; + return; + } +} diff --git a/apps/HeadUnit/clients/gear_data_receiving_client/gear_client.hpp b/apps/HeadUnit/clients/gear_data_receiving_client/gear_client.hpp new file mode 100644 index 0000000..ae756b9 --- /dev/null +++ b/apps/HeadUnit/clients/gear_data_receiving_client/gear_client.hpp @@ -0,0 +1,31 @@ +#ifndef GEAR_CLIENT_HPP +#define GEAR_CLIENT_HPP + +#include + +#include "../headers.hpp" +#include "../server.hpp" + +class GearClient : public QObject +{ + Q_OBJECT +public: + explicit GearClient(QObject *parent = nullptr); + + bool init(); + void start(); + void stop(); + int gearValue; + +signals: + void gearValueChanged(int newGearValue); + +private: + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr& _response); + + std::shared_ptr app_; +}; + +#endif // GEAR_CLIENT_HPP diff --git a/apps/HeadUnit/clients/headers.hpp b/apps/HeadUnit/clients/headers.hpp new file mode 100644 index 0000000..d2ab20d --- /dev/null +++ b/apps/HeadUnit/clients/headers.hpp @@ -0,0 +1,28 @@ +#ifndef HEADERS_HPP +# define HEADERS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#endif \ No newline at end of file diff --git a/apps/HeadUnit/clients/server.hpp b/apps/HeadUnit/clients/server.hpp new file mode 100644 index 0000000..42f8433 --- /dev/null +++ b/apps/HeadUnit/clients/server.hpp @@ -0,0 +1,60 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef SERVER_HPP +#define SERVER_HPP + +//Vehicle value. speed & battery using same eventgroup id +#define VEHICLE_SERVICE_ID 0x1234 +#define VEHICLE_EVENTGROUP_ID 0x4465 + +//speed value +#define SPEED_INSTANCE_ID 0x2001 +#define SPEED_EVENT_ID 0x8779 + +//battery value +#define BATTERY_INSTANCE_ID 0x3001 +#define BATTERY_EVENT_ID 0x8780 + +// gear value +#define GEAR_INSTANCE_ID 0x4001 +#define GEAR_EVENT_ID 0x8781 + +// Ambient value +#define AL_INSTANCE_ID 0x5001 +#define AL_EVENT_ID 0x8782 + +#define SAMPLE_INSTANCE_ID 0x5678 + +// 공통 메서드 ID +#define GET_METHOD_ID 0x0001 +#define SET_METHOD_ID 0x0002 + +#define GEAR_SET_METHOD_ID 0x0421 +#define JOY_GEAR_SET_MID 0x0423 +#define JOY_GEAR_RESPONSE_MID 0x0425 + +#define AL_SET_METHOD_ID 0x0427 + +#endif // SERVER_HPP + +//previous + +// #define SAMPLE_SERVICE_ID 0x1234 +// #define SAMPLE_INSTANCE_ID 0x5678 +// #define SAMPLE_METHOD_ID 0x0421 +// #define SAMPLE_EVENTGROUP_ID 0x4465 + + +// #define SPEED_INSTANCE_ID 0x2001 +// #define BATTERY_INSTANCE_ID 0x3001 + + +// #define SAMPLE_EVENT_ID 0x8778 + +// #define SAMPLE_GET_METHOD_ID 0x0001 +// #define SAMPLE_SET_METHOD_ID 0x0002 + +// #endif // SERVER_HPP diff --git a/apps/HeadUnit/clients/speed_client/speed_client.cpp b/apps/HeadUnit/clients/speed_client/speed_client.cpp new file mode 100644 index 0000000..62753fd --- /dev/null +++ b/apps/HeadUnit/clients/speed_client/speed_client.cpp @@ -0,0 +1,99 @@ +#include "./speed_client.hpp" + +SpeedClient::SpeedClient(QObject *parent) + : QObject(parent), + speedValue(0.0), + app_(vsomeip::runtime::get()->create_application("speed")) +{ +} + +bool SpeedClient::init() +{ + if (!app_->init()) { + std::cerr << "speedclient : Couldn't initialize application" << std::endl; + return false; + } + + // 상태 핸들러 등록 + app_->register_state_handler( + std::bind(&SpeedClient::on_state, this, std::placeholders::_1)); + + // 메시지 핸들러 등록 + app_->register_message_handler( + vsomeip::ANY_SERVICE, SPEED_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&SpeedClient::on_message, this, std::placeholders::_1)); + + // 가용성 핸들러 등록 + app_->register_availability_handler(VEHICLE_SERVICE_ID, SPEED_INSTANCE_ID, + std::bind(&SpeedClient::on_availability, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + + // 이벤트 구독 + std::set its_groups; + its_groups.insert(VEHICLE_EVENTGROUP_ID); + app_->request_event( + VEHICLE_SERVICE_ID, + SPEED_INSTANCE_ID, + SPEED_EVENT_ID, + its_groups, + vsomeip::event_type_e::ET_FIELD); + app_->subscribe(VEHICLE_SERVICE_ID, SPEED_INSTANCE_ID, VEHICLE_EVENTGROUP_ID); + + return true; +} + +void SpeedClient::start() +{ + // 별도 스레드에서 실행 + std::thread vsomeip_thread([this]() + { app_->start(); }); + vsomeip_thread.detach(); // 백그라운드 실행 +} + +// void SpeedClient::start() { +// app_->start(); +// } + +void SpeedClient::stop() +{ + app_->clear_all_handler(); + app_->unsubscribe(VEHICLE_SERVICE_ID, SPEED_INSTANCE_ID, VEHICLE_EVENTGROUP_ID); + app_->release_event(VEHICLE_SERVICE_ID, SPEED_INSTANCE_ID, SPEED_EVENT_ID); + app_->release_service(VEHICLE_SERVICE_ID, SPEED_INSTANCE_ID); + app_->stop(); +} + +void SpeedClient::on_state(vsomeip::state_type_e _state) +{ + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(VEHICLE_SERVICE_ID, SPEED_INSTANCE_ID); + } +} + +void SpeedClient::on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) +{ + std::cout << "Service [" + << std::hex << std::setfill('0') << std::setw(4) << _service << "." + << std::setw(4) << _instance << "] is " + << (_is_available ? "available." : "NOT available.") << std::endl; +} + +void SpeedClient::on_message(const std::shared_ptr &_response) +{ + + std::shared_ptr its_payload = _response->get_payload(); + if (its_payload->get_length() == sizeof(float)) { // 페이로드 크기로 검증 + float received_speed = 0.0f; + + // 이터레이터로 시작 위치 가져오기 + auto it = its_payload->get_data(); // 시작 위치의 이터레이터 + std::copy(it, it + sizeof(float), reinterpret_cast(&received_speed)); + + // 변환된 값 출력 + // std::cout << "Received data: " << received_speed << " m/s" << std::endl; + this->speedValue = received_speed; + emit speedValueChanged(received_speed); + } else { + std::cerr << "Invalid data size received!" << std::endl; + } +} diff --git a/apps/HeadUnit/clients/speed_client/speed_client.hpp b/apps/HeadUnit/clients/speed_client/speed_client.hpp new file mode 100644 index 0000000..5b0838e --- /dev/null +++ b/apps/HeadUnit/clients/speed_client/speed_client.hpp @@ -0,0 +1,32 @@ +#ifndef SPEED_CLIENT_HPP +#define SPEED_CLIENT_HPP + +#include + +#include "../headers.hpp" +#include "../server.hpp" + +class SpeedClient : public QObject +{ + Q_OBJECT + +public: + explicit SpeedClient(QObject *parent = nullptr); + + bool init(); + void start(); + void stop(); + float speedValue; + +signals: + void speedValueChanged(float newSpeedValue); + +private: + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr& _response); + + std::shared_ptr app_; +}; + +#endif // speedClient_HPP diff --git a/apps/HeadUnit/main.cpp b/apps/HeadUnit/main.cpp index f6383c9..0df229c 100644 --- a/apps/HeadUnit/main.cpp +++ b/apps/HeadUnit/main.cpp @@ -3,37 +3,78 @@ #include #include #include - #include "modules/spotify/spotify.h" -#include "shared/utils/envmanager.h" +#include "shared/utils/someip.h" +// #include "shared/utils/envmanager.h" +#include "HeadUnit.h" + +#include +#include +#include +#include "./clients/speed_client/speed_client.hpp" +#include "./clients/battery_client/battery_client.hpp" +#include "./clients/gear_data_receiving_client/gear_client.hpp" +#include "./clients/ambient_sender/alsender.hpp" + int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL); QGuiApplication app(argc, argv); + QQmlApplicationEngine engine; + + HeadUnit controller; // todo fix the location - EnvManager::instance().loadEnvFile("/home/wonjeong/head-unit/apps/HeadUnit/.env"); + // EnvManager::instance().loadEnvFile("/home/wonjeong/head-unit/apps/HeadUnit/.env"); // Register the Spotify class to be used in QML // qmlRegisterType("com.spotify", 1, 0, "Spotify"); - - QQmlApplicationEngine engine; - Spotify spotify; engine.rootContext()->setContextProperty("spotify", &spotify); + BatteryClient batteryClient; + engine.rootContext()->setContextProperty("batteryClient", &batteryClient); + + GearClient gearClient; + engine.rootContext()->setContextProperty("gearClient", &gearClient); + + SpeedClient speedClient; + engine.rootContext()->setContextProperty("speedClient", &speedClient); + + if (batteryClient.init()) + batteryClient.start(); + if (speedClient.init()) + speedClient.start(); + if (gearClient.init()) + gearClient.start(); + + SomeIP someIP; + engine.rootContext()->setContextProperty("someIP", &someIP); + + someIP.init(); + + Alsender alClient; + engine.rootContext()->setContextProperty("alClient", &alClient); + + alClient.init(); + QObject::connect( &engine, &QQmlApplicationEngine::objectCreationFailed, &app, - []() { QCoreApplication::exit(-1); }, + [&controller, &speedClient,&batteryClient,&gearClient]() { QCoreApplication::exit(-1); + + }, Qt::QueuedConnection); + // engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml"))); engine.loadFromModule("HeadUnit", "Main"); + engine.rootContext()->setContextProperty("HeadUnit", &controller); + qDebug() << "Head Unit launched"; diff --git a/apps/HeadUnit/modules/home/Home.qml b/apps/HeadUnit/modules/home/Home.qml index 32ec069..bf10c10 100644 --- a/apps/HeadUnit/modules/home/Home.qml +++ b/apps/HeadUnit/modules/home/Home.qml @@ -6,8 +6,6 @@ import QtMultimedia Item{ id:home - width: parent.width - height: parent.height x: 0 y: 0 clip: false @@ -48,7 +46,7 @@ Item{ Text { id: speed - text: "100" + text: "0" color: myColor font { family: "Inter" @@ -57,6 +55,12 @@ Item{ italic: true } } + Connections { + target: speedClient + onSpeedValueChanged: { + speed.text = newSpeedValue + ""; + } + } Text { id: cms @@ -97,7 +101,7 @@ Item{ Text { id: battery - text: "100" + text: "" color: myColor Layout.rightMargin: -5 font { @@ -107,6 +111,12 @@ Item{ } Layout.alignment: Qt.AlignVCenter } + Connections { + target: batteryClient + onBatteryValueChanged: { + battery.text = newBatteryValue + ""; + } + } Text { id: percent diff --git a/apps/HeadUnit/resources.qrc b/apps/HeadUnit/resources.qrc index 4f6fb50..3cb8c4a 100644 --- a/apps/HeadUnit/resources.qrc +++ b/apps/HeadUnit/resources.qrc @@ -28,7 +28,6 @@ modules/home/images/pi_racer.png modules/home/images/battery_charging.png shared/images/line.png - shared/images/gears.png shared/images/frame.png shared/images/background.png modules/media/images/play2.png @@ -39,6 +38,5 @@ shared/images/R.png shared/images/N.png shared/images/D.png - shared/images/gearlines.png diff --git a/apps/HeadUnit/shared/utils/server.hpp b/apps/HeadUnit/shared/utils/server.hpp new file mode 100644 index 0000000..42f8433 --- /dev/null +++ b/apps/HeadUnit/shared/utils/server.hpp @@ -0,0 +1,60 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef SERVER_HPP +#define SERVER_HPP + +//Vehicle value. speed & battery using same eventgroup id +#define VEHICLE_SERVICE_ID 0x1234 +#define VEHICLE_EVENTGROUP_ID 0x4465 + +//speed value +#define SPEED_INSTANCE_ID 0x2001 +#define SPEED_EVENT_ID 0x8779 + +//battery value +#define BATTERY_INSTANCE_ID 0x3001 +#define BATTERY_EVENT_ID 0x8780 + +// gear value +#define GEAR_INSTANCE_ID 0x4001 +#define GEAR_EVENT_ID 0x8781 + +// Ambient value +#define AL_INSTANCE_ID 0x5001 +#define AL_EVENT_ID 0x8782 + +#define SAMPLE_INSTANCE_ID 0x5678 + +// 공통 메서드 ID +#define GET_METHOD_ID 0x0001 +#define SET_METHOD_ID 0x0002 + +#define GEAR_SET_METHOD_ID 0x0421 +#define JOY_GEAR_SET_MID 0x0423 +#define JOY_GEAR_RESPONSE_MID 0x0425 + +#define AL_SET_METHOD_ID 0x0427 + +#endif // SERVER_HPP + +//previous + +// #define SAMPLE_SERVICE_ID 0x1234 +// #define SAMPLE_INSTANCE_ID 0x5678 +// #define SAMPLE_METHOD_ID 0x0421 +// #define SAMPLE_EVENTGROUP_ID 0x4465 + + +// #define SPEED_INSTANCE_ID 0x2001 +// #define BATTERY_INSTANCE_ID 0x3001 + + +// #define SAMPLE_EVENT_ID 0x8778 + +// #define SAMPLE_GET_METHOD_ID 0x0001 +// #define SAMPLE_SET_METHOD_ID 0x0002 + +// #endif // SERVER_HPP diff --git a/apps/HeadUnit/shared/utils/someip.cpp b/apps/HeadUnit/shared/utils/someip.cpp new file mode 100644 index 0000000..81cce7d --- /dev/null +++ b/apps/HeadUnit/shared/utils/someip.cpp @@ -0,0 +1,48 @@ +#include "./someip.h" + +void SomeIP::set_gear_data(int gear) { + std::cout << "[set gear data function] value : "<< gear << std::endl; + std::shared_ptr request; + + request = vsomeip::runtime::get()->create_request(); + request->set_service(VEHICLE_SERVICE_ID); + request->set_instance(GEAR_INSTANCE_ID); + request->set_method(GEAR_SET_METHOD_ID); + + std::shared_ptr< vsomeip::payload > its_payload = vsomeip::runtime::get()->create_payload(); + std::vector its_payload_data( + reinterpret_cast(&gear), + reinterpret_cast(&gear) + sizeof(int)); + + + its_payload->set_data(its_payload_data); + request->set_payload(its_payload); + app->send(request); + std::cout << "HEAD UNIT : GEAR DATA SENDED" << std::endl; + std::this_thread::sleep_for(std::chrono::milliseconds(90)); + return ; +} + +void on_gear_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) { + std::cout << (_is_available ? "gear available." : "gear NOT available.") << std::endl; +} + +void SomeIP::start() { + std::thread someIP_thread([this](){ + app->start();}); + someIP_thread.detach(); +} + +bool SomeIP::init() { + if (!app->init()) + { + std::cerr << "Couldn't initialize application" << std::endl; + return false; + } + app->register_availability_handler(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, on_gear_availability); + std::this_thread::sleep_for(std::chrono::seconds(1)); + + app->request_service(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID); + this->start(); + return true; +} \ No newline at end of file diff --git a/apps/HeadUnit/shared/utils/someip.h b/apps/HeadUnit/shared/utils/someip.h new file mode 100644 index 0000000..5e43860 --- /dev/null +++ b/apps/HeadUnit/shared/utils/someip.h @@ -0,0 +1,34 @@ +#ifndef SOMEIP_H +#define SOMEIP_H + +#include "./server.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +class SomeIP : public QObject +{ + Q_OBJECT +public: + // SomeIP(); + std::shared_ptr app; + bool init(); + void start(); + + explicit SomeIP(QObject *parent = nullptr) : QObject(parent), app(vsomeip::runtime::get()->create_application("gear")){ + } + Q_INVOKABLE void set_gear_data(int gearValue); + // Q_INVOKABLE void send_gear_data(int); + +}; + +#endif // SOMEIP_H diff --git a/apps/HeadUnit/vsomeip.json b/apps/HeadUnit/vsomeip.json new file mode 100644 index 0000000..0de67a2 --- /dev/null +++ b/apps/HeadUnit/vsomeip.json @@ -0,0 +1,112 @@ +{ + "unicast": "127.0.0.1", + "logging": { + "level": "debug", + "console": "true", + "file": { "enable": "false", "path": "/var/log/vsomeip.log" }, + "dlt": "false" + }, + "applications": [ + { + "name": "speed", + "id": "0x4322", + "services": [ + { + "service": "0x1234", + "instance": "0x2001", + "eventgroups": ["0x4465"] + } + ] + }, + { + "name":"battery", + "id": "0x4323", + "services": [ + { + "service": "0x1234", + "instance": "0x3001", + "eventgroups": ["0x4465"] + } + ] + }, + { + "name": "gear", + "id": "0x4324", + "services": [ + { + "service": "0x1234", + "instance": "0x4001", + "eventgroups": ["0x4465"] + } + ] + }, + { + "name": "ambient", + "id": "0x4325", + "services": [ + { + "service": "0x1234", + "instance": "0x5001" + } + ] + } + ], + "services": [ + { + "service": "0x1234", + "instance": "0x2001", + "reliable": { "port": "30509", "enable-magic-cookies": "false" }, + "unreliable": "31000", + "eventgroups": [ + { + "eventgroup": "0x4465", + "events": ["0x8779"] + } + ] + }, + { + "service": "0x1234", + "instance": "0x3001", + "reliable": { "port": "30510", "enable-magic-cookies": "false" }, + "unreliable": "31001", + "eventgroups": [ + { + "eventgroup": "0x4465", + "events": ["0x8780"] + } + ] + }, + { + "service": "0x1234", + "instance": "0x4001", + "reliable": { "port": "30511", "enable-magic-cookies": "false" }, + "unreliable": "31002", + "eventgroups": [ + { + "eventgroup": "0x4465", + "events": ["0x8781"] + } + ] + }, + { + "service": "0x1234", + "instance": "0x5001", + "reliable": { "port": "30512", "enable-magic-cookies": "false" }, + "unreliable": "31003" + } + ], + "routing": "service-example", + "service-discovery": { + "enable": "true", + "multicast": "224.244.224.245", + "port": "30490", + "protocol": "udp", + "initial_delay_min": "10", + "initial_delay_max": "100", + "repetitions_base_delay": "100", + "repetitions_max": "3", + "ttl": "3", + "cyclic_offer_delay": "2000", + "request_response_delay": "1500" + } +} diff --git a/apps/InstrumentCluster/CMakeLists.txt b/apps/InstrumentCluster/CMakeLists.txt index 55e384d..b85bf65 100644 --- a/apps/InstrumentCluster/CMakeLists.txt +++ b/apps/InstrumentCluster/CMakeLists.txt @@ -3,13 +3,27 @@ cmake_minimum_required(VERSION 3.16) project(InstrumentCluster VERSION 0.1 LANGUAGES CXX) set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(VSOMEIP_CONFIG_FILES "./vsomeip.json") -find_package(Qt6 6.5 REQUIRED COMPONENTS Quick) +find_package(Qt6 6.5 REQUIRED COMPONENTS Quick WebEngineWidgets Qml) +find_package(vsomeip3 3.5.3 REQUIRED) +find_package( Boost 1.55 COMPONENTS system thread log REQUIRED) + + +include_directories( + ${Boost_INCLUDE_DIR} + ${VSOMEIP_INCLUDE_DIR} + ) qt_standard_project_setup(REQUIRES 6.5) qt_add_executable(instrument-cluster main.cpp + clients/ambient_receiver/al_receiver.cpp + clients/speed_client/speed_client.cpp + clients/battery_client/battery_client.cpp + clients/gear_data_receiving_client/gear_client.cpp + ${VSOMEIP_CONFIG_FILES} ) qt_add_qml_module(instrument-cluster @@ -22,7 +36,15 @@ qt_add_qml_module(instrument-cluster QML_FILES Battery.qml QML_FILES Gear.qml QML_FILES - SOURCES instrumentclustercontroller.h instrumentclustercontroller.cpp + SOURCES + instrumentclustercontroller.h + instrumentclustercontroller.cpp + clients/ambient_receiver/al_receiver.hpp + clients/speed_client/speed_client.hpp + clients/battery_client/battery_client.hpp + clients/gear_data_receiving_client/gear_client.hpp + clients/server.hpp + ) qt_add_resources(instrument-cluster "resources" @@ -44,7 +66,13 @@ set_target_properties(instrument-cluster PROPERTIES ) target_link_libraries(instrument-cluster - PRIVATE Qt6::Quick + PRIVATE + vsomeip3 + ${Boost_LIBRARIES} + Qt6::Quick + Qt6::WebEngineWidgets + Qt6::Qml + ) include(GNUInstallDirs) diff --git a/apps/InstrumentCluster/clients/HU_gear_client/gear_client.cpp b/apps/InstrumentCluster/clients/HU_gear_client/gear_client.cpp new file mode 100644 index 0000000..1262cdf --- /dev/null +++ b/apps/InstrumentCluster/clients/HU_gear_client/gear_client.cpp @@ -0,0 +1,83 @@ +#include +#include +#include + +#include +#include + +#include +#include "../server.hpp" +#include "./gear_client.hpp" + +std::shared_ptr< vsomeip::application > app; +std::mutex mutex; +std::condition_variable condition; + +//sending the actual data (will be gear data) to server. +void run() { + std::unique_lock its_lock(mutex); + condition.wait(its_lock); + + std::shared_ptr< vsomeip::message > request; + request = vsomeip::runtime::get()->create_request(); + request->set_service(VEHICLE_SERVICE_ID); + request->set_instance(GEAR_INSTANCE_ID); + request->set_method(GEAR_SET_METHOD_ID); + +//sending actual data. changed into HU input value. + int value=0; + + while (1){ + // value += 1; + if (value != 5) + {std::cout << "Input number" << std::endl; + std::cin >> value;} + std::shared_ptr< vsomeip::payload > its_payload = vsomeip::runtime::get()->create_payload(); + std::vector its_payload_data( + reinterpret_cast(&value), + reinterpret_cast(&value) + sizeof(int) + ); + its_payload->set_data(its_payload_data); + request->set_payload(its_payload); + app->send(request); + std::this_thread::sleep_for(std::chrono::seconds(1)); + + } + std::cout << "CLIENT : DATA SENDED" << std::endl; +} + +// When response come, print the payload from server. +void on_message(const std::shared_ptr &_response) { + std::shared_ptr its_payload = _response->get_payload(); + vsomeip::length_t l = its_payload->get_length(); + + // Get payload + std::stringstream ss; + for (vsomeip::length_t i=0; iget_data()+i) << " "; + } + + std::cout << "CLIENT: Received message with Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_session() << "] " + << ss.str() << std::endl; +} + +void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) { + std::cout + << (_is_available ? "available." : "NOT available.") + << std::endl; +} + +int main() { + + app = vsomeip::runtime::get()->create_application("gear"); + app->init(); + app->register_availability_handler(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, on_availability); + std::this_thread::sleep_for(std::chrono::seconds(1)); + app->request_service(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID); + app->register_message_handler(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, JOY_GEAR_RESPONSE_MID, on_message); + std::thread sender(run); + app->start(); +} diff --git a/apps/InstrumentCluster/clients/HU_gear_client/gear_client.hpp b/apps/InstrumentCluster/clients/HU_gear_client/gear_client.hpp new file mode 100644 index 0000000..1e24653 --- /dev/null +++ b/apps/InstrumentCluster/clients/HU_gear_client/gear_client.hpp @@ -0,0 +1,34 @@ +#ifndef GEAR_CLIENT_HPP +# define GEAR_CLIENT_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../server.hpp" + +class gearClient { +public: + gearClient(bool _use_tcp); + + bool init(); + void start(); + void stop(); + +private: + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr& _response); + + std::shared_ptr app_; + bool use_tcp_; + + gearClient(void); + ~gearClient(void); +}; + +#endif \ No newline at end of file diff --git a/apps/InstrumentCluster/clients/J_gear_client/gear_client.cpp b/apps/InstrumentCluster/clients/J_gear_client/gear_client.cpp new file mode 100644 index 0000000..aaa94a1 --- /dev/null +++ b/apps/InstrumentCluster/clients/J_gear_client/gear_client.cpp @@ -0,0 +1,99 @@ +#include +#include +#include + +#include +#include +#include + +#include "../server.hpp" +#include "./gear_client.hpp" +std::shared_ptr< vsomeip::application > app; +std::mutex mutex; +std::condition_variable condition; + +//TODO: sending the actual data (will be gear data) to server. + +// VEHICLE_SERVICE_ID, etc IDs are defined in src/server.hpp + +// void run(int gearValue) { +void run() { + // on avaliability notify this thread that client is connected to server + std::unique_lock its_lock(mutex); + condition.wait(its_lock); + + //create request + std::shared_ptr< vsomeip::message > request; + request = vsomeip::runtime::get()->create_request(); + //basic setting + request->set_service(VEHICLE_SERVICE_ID); + request->set_instance(GEAR_INSTANCE_ID); + request->set_method(JOY_GEAR_SET_MID); + +//sending actual data. changed into HU input value. + int value=0; // <- real gear value should be on value variable + while (1){ + // std::cout << "Input number" << std::endl; + // std::cin >> value; + + std::shared_ptr< vsomeip::payload > its_payload = vsomeip::runtime::get()->create_payload(); + std::vector its_payload_data( + reinterpret_cast(&value), + reinterpret_cast(&value) + sizeof(int) + // reinterpret_cast(&gearValue), + // reinterpret_cast(&gearValue) + sizeof(int) + ); + its_payload->set_data(its_payload_data); + request->set_payload(its_payload); + app->send(request); + std::cout << "CLIENT : DATA SENDED" << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(1)); + + } +} +// PARKING 0 +// REVERSE 1 +// NEUTRAL 2 +// DRIVE 3 + +// When response come, print the payload from server. +void on_message(const std::shared_ptr &_response) { + std::shared_ptr payload = _response->get_payload(); + int received_value = 0; + + if (payload->get_length() >= sizeof(int)) { + received_value = *reinterpret_cast(payload->get_data()); + std::cout << "SERVER: Received int: " << received_value << std::endl; + } else { + std::cerr << "SERVER: Invalid payload size!" << std::endl; + return; + } + // +} + +// 서버랑 연결이 안되어있을때 전송을 할수도있어 +// vsomeip는 /tmp/vsomeip-100 103~~~ +// 얘가 소켓이 꼬여. 그래서 데이터 안가 제대로 연결이 됐어도 그래서 그냥 두는게 나을거같다. +void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) { + std::cout << "CLIENT: Service [" + << std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance + << "] is " + << (_is_available ? "available." : "NOT available.") + << std::endl; + if (_is_available) { + std::this_thread::sleep_for(std::chrono::seconds(3)); + condition.notify_one(); + } +} + +int main() { + app = vsomeip::runtime::get()->create_application("gear"); + app->init(); + app->register_availability_handler(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, on_availability); + std::this_thread::sleep_for(std::chrono::seconds(1)); + app->request_service(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID); + std::this_thread::sleep_for(std::chrono::seconds(1)); + app->register_message_handler(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, JOY_GEAR_SET_MID, on_message); + std::thread sender(run); + app->start(); +} diff --git a/apps/InstrumentCluster/clients/J_gear_client/gear_client.hpp b/apps/InstrumentCluster/clients/J_gear_client/gear_client.hpp new file mode 100644 index 0000000..1e24653 --- /dev/null +++ b/apps/InstrumentCluster/clients/J_gear_client/gear_client.hpp @@ -0,0 +1,34 @@ +#ifndef GEAR_CLIENT_HPP +# define GEAR_CLIENT_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../server.hpp" + +class gearClient { +public: + gearClient(bool _use_tcp); + + bool init(); + void start(); + void stop(); + +private: + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr& _response); + + std::shared_ptr app_; + bool use_tcp_; + + gearClient(void); + ~gearClient(void); +}; + +#endif \ No newline at end of file diff --git a/apps/InstrumentCluster/clients/ambient_receiver/al_receiver.cpp b/apps/InstrumentCluster/clients/ambient_receiver/al_receiver.cpp new file mode 100644 index 0000000..f28e5b6 --- /dev/null +++ b/apps/InstrumentCluster/clients/ambient_receiver/al_receiver.cpp @@ -0,0 +1,60 @@ +#include "../headers.hpp" +#include "../server.hpp" +#include "./al_receiver.hpp" +//받은 int값을 처리. +// std::shared_ptr app; + +void AlClient::on_message(const std::shared_ptr &_request) { + std::shared_ptr payload = _request->get_payload(); + int received_value = 0; + + if (payload->get_length() >= sizeof(int)) { + received_value = *reinterpret_cast(payload->get_data()); + std::cout << "SERVER: Received int: " << received_value << std::endl; + } else { + std::cerr << "SERVER: Invalid payload size!" << std::endl; + return; + } + this->alValue = received_value; +} + +void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) { + std::cout << (_is_available ? "AL receiver available." : "AL receiver NOT available.") << std::endl; +} + +void AlClient::start() { + std::thread al_thread([this](){ + app->start();}); + al_thread.detach(); +} + +bool AlClient::init() { + if (!app->init()) + { + std::cerr << "Couldn't initialize application" << std::endl; + return false; + } + app->register_availability_handler(VEHICLE_SERVICE_ID, AL_INSTANCE_ID, on_availability); + std::this_thread::sleep_for(std::chrono::seconds(1)); + + app->request_service(VEHICLE_SERVICE_ID, AL_INSTANCE_ID); + this->start(); + return true; +} + +// int main() { +// app = vsomeip::runtime::get()->create_application("ambient"); +// app->init(); +// std::this_thread::sleep_for(std::chrono::seconds(2)); +// app->register_message_handler(VEHICLE_SERVICE_ID, AL_INSTANCE_ID, AL_SET_METHOD_ID, on_message); +// app->offer_service(VEHICLE_SERVICE_ID, AL_INSTANCE_ID); +// app->start(); +// } +// void AlClient::start() { +// app = vsomeip::runtime::get()->create_application("ambient"); +// app->init(); +// std::this_thread::sleep_for(std::chrono::seconds(2)); +// app->register_message_handler(VEHICLE_SERVICE_ID, AL_INSTANCE_ID, AL_SET_METHOD_ID, on_message); +// app->offer_service(VEHICLE_SERVICE_ID, AL_INSTANCE_ID); +// app->start(); +// } \ No newline at end of file diff --git a/apps/InstrumentCluster/clients/ambient_receiver/al_receiver.hpp b/apps/InstrumentCluster/clients/ambient_receiver/al_receiver.hpp new file mode 100644 index 0000000..831e7f7 --- /dev/null +++ b/apps/InstrumentCluster/clients/ambient_receiver/al_receiver.hpp @@ -0,0 +1,35 @@ +#ifndef AL_RECEIVER_HPP +# define AL_RECEIVER_HPP + +#include "../server.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class AlClient : public QObject +{ + Q_OBJECT +public : + // AlClient(void); + // ~AlClient(void); + int alValue; + std::shared_ptr app; + bool init(); + void start(); + void on_message(const std::shared_ptr &_request); + explicit AlClient(QObject *parent = nullptr) : QObject(parent), app(vsomeip::runtime::get()->create_application("ambient")){ + } + // Q_INVOKABLE void set_al_data(int); +}; + +#endif diff --git a/apps/InstrumentCluster/clients/battery_client/battery_client.cpp b/apps/InstrumentCluster/clients/battery_client/battery_client.cpp new file mode 100644 index 0000000..b384d7b --- /dev/null +++ b/apps/InstrumentCluster/clients/battery_client/battery_client.cpp @@ -0,0 +1,101 @@ +#include "./battery_client.hpp" + +BatteryClient::BatteryClient(QObject *parent) + : QObject(parent), + batteryValue(0), + app_(vsomeip::runtime::get()->create_application("battery")) +{ +} + +bool BatteryClient::init() +{ + if (!app_->init()) { + std::cerr << "Couldn't initialize application" << std::endl; + return false; + } + + // 상태 핸들러 등록 + app_->register_state_handler( + std::bind(&BatteryClient::on_state, this, std::placeholders::_1)); + + // 메시지 핸들러 등록 + app_->register_message_handler( + vsomeip::ANY_SERVICE, BATTERY_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&BatteryClient::on_message, this, std::placeholders::_1)); + + // 가용성 핸들러 등록 + app_->register_availability_handler(VEHICLE_SERVICE_ID, BATTERY_INSTANCE_ID, + std::bind(&BatteryClient::on_availability, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + + // 이벤트 구독 + std::set its_groups; + its_groups.insert(VEHICLE_EVENTGROUP_ID); + + app_->request_event( + VEHICLE_SERVICE_ID, + BATTERY_INSTANCE_ID, + BATTERY_EVENT_ID, + its_groups, + vsomeip::event_type_e::ET_FIELD); + + app_->subscribe(VEHICLE_SERVICE_ID, BATTERY_INSTANCE_ID, VEHICLE_EVENTGROUP_ID); + + return true; +} + +void BatteryClient::start() +{ + // 별도 스레드에서 실행 + std::thread vsomeip_thread([this]() { + app_->start(); + }); + vsomeip_thread.detach(); // 백그라운드 실행 +} + +// void BatteryClient::start() { +// app_->start(); +// } + +void BatteryClient::stop() +{ + app_->clear_all_handler(); + app_->unsubscribe(VEHICLE_SERVICE_ID, BATTERY_INSTANCE_ID, VEHICLE_EVENTGROUP_ID); + app_->release_event(VEHICLE_SERVICE_ID, BATTERY_INSTANCE_ID, BATTERY_EVENT_ID); + app_->release_service(VEHICLE_SERVICE_ID, BATTERY_INSTANCE_ID); + app_->stop(); +} + +void BatteryClient::on_state(vsomeip::state_type_e _state) +{ + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(VEHICLE_SERVICE_ID, BATTERY_INSTANCE_ID); + } +} + +void BatteryClient::on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) +{ + std::cout << "Service [" + << std::hex << std::setfill('0') << std::setw(4) << _service << "." + << std::setw(4) << _instance << "] is " + << (_is_available ? "available." : "NOT available.") << std::endl; +} + +void BatteryClient::on_message(const std::shared_ptr &_response) +{ + std::shared_ptr payload = _response->get_payload(); + int received_value = 0; + + if (payload->get_length() >= sizeof(int)) { + received_value = *reinterpret_cast(payload->get_data()); + std::cout << "SERVER: Received int: " << received_value << std::endl; + if (this->batteryValue != received_value) + { + this->batteryValue = received_value; + emit batteryValueChanged(received_value); + } + } else { + std::cerr << "SERVER: Invalid payload size!" << std::endl; + return; + } +} diff --git a/apps/InstrumentCluster/clients/battery_client/battery_client.hpp b/apps/InstrumentCluster/clients/battery_client/battery_client.hpp new file mode 100644 index 0000000..d6258dc --- /dev/null +++ b/apps/InstrumentCluster/clients/battery_client/battery_client.hpp @@ -0,0 +1,33 @@ +#ifndef BATTERY_CLIENTHPP +#define BATTERY_CLIENTHPP + +#include + +#include "../headers.hpp" +#include "../server.hpp" + +class BatteryClient : public QObject +{ + Q_OBJECT + +public: + explicit BatteryClient(QObject *parent = nullptr); + + bool init(); + void start(); + void stop(); + int batteryValue; + +signals: + void batteryValueChanged(int newBatteryValue); + +private: + + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr& _response); + + std::shared_ptr app_; +}; + +#endif // BATTERY_CLIENTHPP diff --git a/apps/InstrumentCluster/clients/gear_data_receiving_client/gear_client.cpp b/apps/InstrumentCluster/clients/gear_data_receiving_client/gear_client.cpp new file mode 100644 index 0000000..63405c3 --- /dev/null +++ b/apps/InstrumentCluster/clients/gear_data_receiving_client/gear_client.cpp @@ -0,0 +1,98 @@ +#include "./gear_client.hpp" + +GearClient::GearClient(QObject *parent) + : QObject(parent), + gearValue(0), + app_(vsomeip::runtime::get()->create_application("gear")) +{ +} + +bool GearClient::init() +{ + if (!app_->init()) + { + std::cerr << "Couldn't initialize application" << std::endl; + return false; + } + + // 상태 핸들러 등록 + app_->register_state_handler( + std::bind(&GearClient::on_state, this, std::placeholders::_1)); + + // 메시지 핸들러 등록 + app_->register_message_handler( + vsomeip::ANY_SERVICE, GEAR_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&GearClient::on_message, this, std::placeholders::_1)); + + // 가용성 핸들러 등록 + app_->register_availability_handler(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, + std::bind(&GearClient::on_availability, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + + // 이벤트 구독 + std::set its_groups; + its_groups.insert(VEHICLE_EVENTGROUP_ID); + + app_->request_event( + VEHICLE_SERVICE_ID, + GEAR_INSTANCE_ID, + GEAR_EVENT_ID, + its_groups, + vsomeip::event_type_e::ET_FIELD); + + app_->subscribe(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, VEHICLE_EVENTGROUP_ID); + + return true; +} + +void GearClient::start() +{ + // 별도 스레드에서 실행 + std::thread vsomeip_thread([this]() + { app_->start(); }); + vsomeip_thread.detach(); // 백그라운드 실행 +} + +// void GearClient::start() { +// app_->start(); +// } + +void GearClient::stop() +{ + app_->clear_all_handler(); + app_->unsubscribe(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, VEHICLE_EVENTGROUP_ID); + app_->release_event(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, GEAR_EVENT_ID); + app_->release_service(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID); + app_->stop(); +} + +void GearClient::on_state(vsomeip::state_type_e _state) +{ + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID); + } +} + +void GearClient::on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) +{ + std::cout << "Service [" + << std::hex << std::setfill('0') << std::setw(4) << _service << "." + << std::setw(4) << _instance << "] is " + << (_is_available ? "available." : "NOT available.") << std::endl; +} + +void GearClient::on_message(const std::shared_ptr &_request) +{ + std::shared_ptr payload = _request->get_payload(); + int received_value = 0; + + if (payload->get_length() >= sizeof(int)) { + received_value = *reinterpret_cast(payload->get_data()); + std::cout << "GEAR DATA RECEIVING CLIENT : Received int: " << received_value << std::endl; + this->gearValue = received_value; + emit gearValueChanged(received_value); + } else { + std::cerr << "GEAR DATA RECEIVING CLIENT : Invalid payload size!" << std::endl; + return; + } +} diff --git a/apps/InstrumentCluster/clients/gear_data_receiving_client/gear_client.hpp b/apps/InstrumentCluster/clients/gear_data_receiving_client/gear_client.hpp new file mode 100644 index 0000000..ae756b9 --- /dev/null +++ b/apps/InstrumentCluster/clients/gear_data_receiving_client/gear_client.hpp @@ -0,0 +1,31 @@ +#ifndef GEAR_CLIENT_HPP +#define GEAR_CLIENT_HPP + +#include + +#include "../headers.hpp" +#include "../server.hpp" + +class GearClient : public QObject +{ + Q_OBJECT +public: + explicit GearClient(QObject *parent = nullptr); + + bool init(); + void start(); + void stop(); + int gearValue; + +signals: + void gearValueChanged(int newGearValue); + +private: + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr& _response); + + std::shared_ptr app_; +}; + +#endif // GEAR_CLIENT_HPP diff --git a/apps/InstrumentCluster/clients/headers.hpp b/apps/InstrumentCluster/clients/headers.hpp new file mode 100644 index 0000000..d2ab20d --- /dev/null +++ b/apps/InstrumentCluster/clients/headers.hpp @@ -0,0 +1,28 @@ +#ifndef HEADERS_HPP +# define HEADERS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#endif \ No newline at end of file diff --git a/apps/InstrumentCluster/clients/server.hpp b/apps/InstrumentCluster/clients/server.hpp new file mode 100644 index 0000000..42f8433 --- /dev/null +++ b/apps/InstrumentCluster/clients/server.hpp @@ -0,0 +1,60 @@ +// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef SERVER_HPP +#define SERVER_HPP + +//Vehicle value. speed & battery using same eventgroup id +#define VEHICLE_SERVICE_ID 0x1234 +#define VEHICLE_EVENTGROUP_ID 0x4465 + +//speed value +#define SPEED_INSTANCE_ID 0x2001 +#define SPEED_EVENT_ID 0x8779 + +//battery value +#define BATTERY_INSTANCE_ID 0x3001 +#define BATTERY_EVENT_ID 0x8780 + +// gear value +#define GEAR_INSTANCE_ID 0x4001 +#define GEAR_EVENT_ID 0x8781 + +// Ambient value +#define AL_INSTANCE_ID 0x5001 +#define AL_EVENT_ID 0x8782 + +#define SAMPLE_INSTANCE_ID 0x5678 + +// 공통 메서드 ID +#define GET_METHOD_ID 0x0001 +#define SET_METHOD_ID 0x0002 + +#define GEAR_SET_METHOD_ID 0x0421 +#define JOY_GEAR_SET_MID 0x0423 +#define JOY_GEAR_RESPONSE_MID 0x0425 + +#define AL_SET_METHOD_ID 0x0427 + +#endif // SERVER_HPP + +//previous + +// #define SAMPLE_SERVICE_ID 0x1234 +// #define SAMPLE_INSTANCE_ID 0x5678 +// #define SAMPLE_METHOD_ID 0x0421 +// #define SAMPLE_EVENTGROUP_ID 0x4465 + + +// #define SPEED_INSTANCE_ID 0x2001 +// #define BATTERY_INSTANCE_ID 0x3001 + + +// #define SAMPLE_EVENT_ID 0x8778 + +// #define SAMPLE_GET_METHOD_ID 0x0001 +// #define SAMPLE_SET_METHOD_ID 0x0002 + +// #endif // SERVER_HPP diff --git a/apps/InstrumentCluster/clients/speed_client/speed_client.cpp b/apps/InstrumentCluster/clients/speed_client/speed_client.cpp new file mode 100644 index 0000000..7501e09 --- /dev/null +++ b/apps/InstrumentCluster/clients/speed_client/speed_client.cpp @@ -0,0 +1,99 @@ +#include "./speed_client.hpp" + +SpeedClient::SpeedClient(QObject *parent) + : QObject(parent), + speedValue(0.0), + app_(vsomeip::runtime::get()->create_application("speed")) +{ +} + +bool SpeedClient::init() +{ + if (!app_->init()) { + std::cerr << "Couldn't initialize application" << std::endl; + return false; + } + + // 상태 핸들러 등록 + app_->register_state_handler( + std::bind(&SpeedClient::on_state, this, std::placeholders::_1)); + + // 메시지 핸들러 등록 + app_->register_message_handler( + vsomeip::ANY_SERVICE, SPEED_INSTANCE_ID, vsomeip::ANY_METHOD, + std::bind(&SpeedClient::on_message, this, std::placeholders::_1)); + + // 가용성 핸들러 등록 + app_->register_availability_handler(VEHICLE_SERVICE_ID, SPEED_INSTANCE_ID, + std::bind(&SpeedClient::on_availability, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + + // 이벤트 구독 + std::set its_groups; + its_groups.insert(VEHICLE_EVENTGROUP_ID); + app_->request_event( + VEHICLE_SERVICE_ID, + SPEED_INSTANCE_ID, + SPEED_EVENT_ID, + its_groups, + vsomeip::event_type_e::ET_FIELD); + app_->subscribe(VEHICLE_SERVICE_ID, SPEED_INSTANCE_ID, VEHICLE_EVENTGROUP_ID); + + return true; +} + +void SpeedClient::start() +{ + // 별도 스레드에서 실행 + std::thread vsomeip_thread([this]() + { app_->start(); }); + vsomeip_thread.detach(); // 백그라운드 실행 +} + +// void SpeedClient::start() { +// app_->start(); +// } + +void SpeedClient::stop() +{ + app_->clear_all_handler(); + app_->unsubscribe(VEHICLE_SERVICE_ID, SPEED_INSTANCE_ID, VEHICLE_EVENTGROUP_ID); + app_->release_event(VEHICLE_SERVICE_ID, SPEED_INSTANCE_ID, SPEED_EVENT_ID); + app_->release_service(VEHICLE_SERVICE_ID, SPEED_INSTANCE_ID); + app_->stop(); +} + +void SpeedClient::on_state(vsomeip::state_type_e _state) +{ + if (_state == vsomeip::state_type_e::ST_REGISTERED) { + app_->request_service(VEHICLE_SERVICE_ID, SPEED_INSTANCE_ID); + } +} + +void SpeedClient::on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) +{ + std::cout << "Service [" + << std::hex << std::setfill('0') << std::setw(4) << _service << "." + << std::setw(4) << _instance << "] is " + << (_is_available ? "available." : "NOT available.") << std::endl; +} + +void SpeedClient::on_message(const std::shared_ptr &_response) +{ + + std::shared_ptr its_payload = _response->get_payload(); + if (its_payload->get_length() == sizeof(float)) { // 페이로드 크기로 검증 + float received_speed = 0.0f; + + // 이터레이터로 시작 위치 가져오기 + auto it = its_payload->get_data(); // 시작 위치의 이터레이터 + std::copy(it, it + sizeof(float), reinterpret_cast(&received_speed)); + + // 변환된 값 출력 + std::cout << "Received data: " << received_speed << " m/s" << std::endl; + this->speedValue = received_speed; + emit speedValueChanged(received_speed); + } else { + std::cerr << "Invalid data size received!" << std::endl; + } +} diff --git a/apps/InstrumentCluster/clients/speed_client/speed_client.hpp b/apps/InstrumentCluster/clients/speed_client/speed_client.hpp new file mode 100644 index 0000000..5b0838e --- /dev/null +++ b/apps/InstrumentCluster/clients/speed_client/speed_client.hpp @@ -0,0 +1,32 @@ +#ifndef SPEED_CLIENT_HPP +#define SPEED_CLIENT_HPP + +#include + +#include "../headers.hpp" +#include "../server.hpp" + +class SpeedClient : public QObject +{ + Q_OBJECT + +public: + explicit SpeedClient(QObject *parent = nullptr); + + bool init(); + void start(); + void stop(); + float speedValue; + +signals: + void speedValueChanged(float newSpeedValue); + +private: + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr& _response); + + std::shared_ptr app_; +}; + +#endif // speedClient_HPP diff --git a/apps/InstrumentCluster/instrumentclustercontroller.h b/apps/InstrumentCluster/instrumentclustercontroller.h index 9448690..e31cf3f 100644 --- a/apps/InstrumentCluster/instrumentclustercontroller.h +++ b/apps/InstrumentCluster/instrumentclustercontroller.h @@ -2,6 +2,10 @@ #define INSTRUMENTCLUSTERCONTROLLER_H #include +#include "./clients/speed_client/speed_client.hpp" +#include "./clients/battery_client/battery_client.hpp" +#include "./clients/gear_data_receiving_client/gear_client.hpp" +#include "./clients/ambient_receiver/al_receiver.hpp" class InstrumentClusterController : public QObject { @@ -33,10 +37,13 @@ class InstrumentClusterController : public QObject void speedChanged(int speed); void batteryPercentageChanged(int batteryPercentage); void chargingStateChanged(bool state); - -private: + + + private: QString _currentGear = "P"; + //TODO: Qstring to int. QString _ambientLighting = "#000000"; + int _speed = 0; int _batteryPercentage = 100; bool _chargingState = false; diff --git a/apps/InstrumentCluster/main.cpp b/apps/InstrumentCluster/main.cpp index 06f9ea1..a4baaf0 100644 --- a/apps/InstrumentCluster/main.cpp +++ b/apps/InstrumentCluster/main.cpp @@ -5,18 +5,45 @@ // for test #include +// #include +#include +#include "./clients/speed_client/speed_client.hpp" +#include "./clients/battery_client/battery_client.hpp" +#include "./clients/gear_data_receiving_client/gear_client.hpp" +#include "./clients/ambient_receiver/al_receiver.hpp" -#include "instrumentclustercontroller.h" +#include "instrumentclustercontroller.h" +//TODO: 2025-02-20. For ambient light, send/recive data type change required. int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; InstrumentClusterController controller; - engine.rootContext()->setContextProperty("instrumentClusterController", &controller); + BatteryClient batteryClient; + engine.rootContext()->setContextProperty("batteryClient", &batteryClient); + + GearClient gearClient; + engine.rootContext()->setContextProperty("gearClient", &gearClient); + + SpeedClient speedClient; + engine.rootContext()->setContextProperty("speedClient", &speedClient); + + AlClient ambientClient; + engine.rootContext()->setContextProperty("ambientClient", &ambientClient); + + if (batteryClient.init()) + batteryClient.start(); + if (speedClient.init()) + speedClient.start(); + if (gearClient.init()) + gearClient.start(); + if (ambientClient.init()) + ambientClient.start(); + QObject::connect( &engine, &QQmlApplicationEngine::objectCreationFailed, @@ -26,29 +53,39 @@ int main(int argc, char *argv[]) engine.loadFromModule("InstrumentCluster", "Main"); qDebug() << "Instrument Cluster launched"; + + // alClient.start(); // test code QTimer *timer = new QTimer(&controller); - QObject::connect(timer, &QTimer::timeout, [&controller]() { - static QStringList gears = {"P", "R", "N", "D"}; - static int gearIndex = 0; - controller.setCurrentGear(gears[gearIndex]); - gearIndex = (gearIndex + 1) % gears.size(); - + QObject::connect(timer, &QTimer::timeout, [&controller, &speedClient,&batteryClient,&gearClient, &ambientClient]() { + //Speed static int speed = 0; - speed = (speed + 10) % 310; + speed = speedClient.speedValue; controller.setSpeed(speed); + //Battery static int batteryPercentage = 100; - batteryPercentage = (batteryPercentage - 10) < 0 ? 100 : batteryPercentage - 10; + batteryPercentage = batteryClient.batteryValue; controller.setBatteryPercentage(batteryPercentage); static int chargingState = false; chargingState = !chargingState; controller.setChargingState(chargingState); + //Gear + static QStringList gears = {"P", "R", "N", "D"}; + static int gearIndex = 0; + gearIndex = gearClient.gearValue; // Drive = 3, NEUTRAL=2, REVERSE=1, PARKING=0 + + controller.setCurrentGear(gears[gearIndex]); + gearIndex = (gearIndex + 1) % gears.size(); + + // Ambient Light static QStringList colors = {"#4deeea", "#74ee15", "#ffe700", "#f000ff", "#001eff"}; static int colorIndex = 0; + colorIndex = ambientClient.alValue; // <- set colorIndex to received value + controller.setAmbientLighting(colors[colorIndex]); colorIndex = (colorIndex + 1) % colors.size(); }); diff --git a/apps/InstrumentCluster/vsomeip.json b/apps/InstrumentCluster/vsomeip.json new file mode 100644 index 0000000..0de67a2 --- /dev/null +++ b/apps/InstrumentCluster/vsomeip.json @@ -0,0 +1,112 @@ +{ + "unicast": "127.0.0.1", + "logging": { + "level": "debug", + "console": "true", + "file": { "enable": "false", "path": "/var/log/vsomeip.log" }, + "dlt": "false" + }, + "applications": [ + { + "name": "speed", + "id": "0x4322", + "services": [ + { + "service": "0x1234", + "instance": "0x2001", + "eventgroups": ["0x4465"] + } + ] + }, + { + "name":"battery", + "id": "0x4323", + "services": [ + { + "service": "0x1234", + "instance": "0x3001", + "eventgroups": ["0x4465"] + } + ] + }, + { + "name": "gear", + "id": "0x4324", + "services": [ + { + "service": "0x1234", + "instance": "0x4001", + "eventgroups": ["0x4465"] + } + ] + }, + { + "name": "ambient", + "id": "0x4325", + "services": [ + { + "service": "0x1234", + "instance": "0x5001" + } + ] + } + ], + "services": [ + { + "service": "0x1234", + "instance": "0x2001", + "reliable": { "port": "30509", "enable-magic-cookies": "false" }, + "unreliable": "31000", + "eventgroups": [ + { + "eventgroup": "0x4465", + "events": ["0x8779"] + } + ] + }, + { + "service": "0x1234", + "instance": "0x3001", + "reliable": { "port": "30510", "enable-magic-cookies": "false" }, + "unreliable": "31001", + "eventgroups": [ + { + "eventgroup": "0x4465", + "events": ["0x8780"] + } + ] + }, + { + "service": "0x1234", + "instance": "0x4001", + "reliable": { "port": "30511", "enable-magic-cookies": "false" }, + "unreliable": "31002", + "eventgroups": [ + { + "eventgroup": "0x4465", + "events": ["0x8781"] + } + ] + }, + { + "service": "0x1234", + "instance": "0x5001", + "reliable": { "port": "30512", "enable-magic-cookies": "false" }, + "unreliable": "31003" + } + ], + "routing": "service-example", + "service-discovery": { + "enable": "true", + "multicast": "224.244.224.245", + "port": "30490", + "protocol": "udp", + "initial_delay_min": "10", + "initial_delay_max": "100", + "repetitions_base_delay": "100", + "repetitions_max": "3", + "ttl": "3", + "cyclic_offer_delay": "2000", + "request_response_delay": "1500" + } +} diff --git a/apps/ServiceManager/CMakeLists.txt b/apps/ServiceManager/CMakeLists.txt index 2913a4c..260f471 100644 --- a/apps/ServiceManager/CMakeLists.txt +++ b/apps/ServiceManager/CMakeLists.txt @@ -3,56 +3,66 @@ cmake_minimum_required (VERSION 3.13) set (CMAKE_CXX_FLAGS "-g -std=c++0x") set(EXAMPLE_CONFIG_FILES - "../config/vsomeip.json" + # "/home/frederik/Qt/Projects/DES_Head_Unit/apps/ServiceManager/config/vsomeip.json" + ./config/vsomeip.json ) -find_package (vsomeip3 3.4.10 REQUIRED) +find_package (vsomeip3 3.5.3 REQUIRED) find_package( Boost 1.55 COMPONENTS system thread log REQUIRED ) + include_directories ( ${Boost_INCLUDE_DIR} ${VSOMEIP_INCLUDE_DIRS} ) # Server binary file -add_executable(server-draft - ../src/main.cpp - ../src/service-main.cpp - ../src/service_base/service-base.cpp - ../src/speed-src/speed/speed.cpp - ../src/speed-src/speed/canreceiver.cpp - ../src/battery-src/battery/battery.cpp - ../src/gear-src/gear/gear.cpp +add_executable(server + ./src/main.cpp + ./src/service-main.cpp + ./src/service_base/service-base.cpp + ./src/speed-src/speed/speed.cpp + ./src/speed-src/speed/canreceiver.cpp + ./src/battery-src/battery/battery.cpp + ./src/gear-src/gear/gear.cpp + ./config/vsomeip.json ${EXAMPLE_CONFIG_FILES} ) -target_link_libraries(server-draft vsomeip3 ${Boost_LIBRARIES}) +target_link_libraries(server vsomeip3 ${Boost_LIBRARIES}) -# add_executable(service-example ../src/main.cpp ../src/service-main.cpp ../src/service-example.cpp ../src/canreceiver.cpp ${EXAMPLE_CONFIG_FILES}) -# target_link_libraries(service-example vsomeip3 ${Boost_LIBRARIES}) +# # add_executable(service-example ../src/main.cpp ../src/service-main.cpp ../src/service-example.cpp ../src/canreceiver.cpp ${EXAMPLE_CONFIG_FILES}) +# # target_link_libraries(service-example vsomeip3 ${Boost_LIBRARIES}) -# speed receiving client -add_executable(speed_client ../src/speed-src/speed_client/client-main.cpp ../src/speed-src/speed_client/client-example.cpp ${EXAMPLE_CONFIG_FILES}) -target_link_libraries(speed_client vsomeip3 ${Boost_LIBRARIES}) +# # speed receiving client +# add_executable(speed_client ../src/speed-src/speed_client/client-main.cpp ../src/speed-src/speed_client/client-example.cpp ${EXAMPLE_CONFIG_FILES}) +# target_link_libraries(speed_client vsomeip3 ${Boost_LIBRARIES}) -# battery receiving client -add_executable(battery_client ../src/battery-src/battery_client/client-main.cpp ../src/battery-src/battery_client/client-example.cpp ${EXAMPLE_CONFIG_FILES}) -target_link_libraries(battery_client vsomeip3 ${Boost_LIBRARIES}) +# # battery receiving client +# add_executable(battery_client ../src/battery-src/battery_client/client-main.cpp ../src/battery-src/battery_client/client-example.cpp ${EXAMPLE_CONFIG_FILES}) +# target_link_libraries(battery_client vsomeip3 ${Boost_LIBRARIES}) -# joystick input -add_executable(joystick-gear-client ../src/gear-src/J_gear_client/gear_client.cpp ${EXAMPLE_CONFIG_FILES}) -target_link_libraries(joystick-gear-client vsomeip3 ${Boost_LIBRARIES}) +# # joystick input +# add_executable(joystick-gear-client ../src/gear-src/J_gear_client/gear_client.cpp ${EXAMPLE_CONFIG_FILES}) +# target_link_libraries(joystick-gear-client vsomeip3 ${Boost_LIBRARIES}) -# HU input -add_executable(HU-gear-client ../src/gear-src/HU_gear_client/gear_client.cpp ${EXAMPLE_CONFIG_FILES}) -target_link_libraries(HU-gear-client vsomeip3 ${Boost_LIBRARIES}) +# # HU input +# add_executable(HU-gear-client ../src/gear-src/HU_gear_client/gear_client.cpp ${EXAMPLE_CONFIG_FILES}) +# target_link_libraries(HU-gear-client vsomeip3 ${Boost_LIBRARIES}) # gear client -add_executable(gear_client - ../src/gear-src/gear_data_receiving_client/client-main.cpp - ../src/gear-src/gear_data_receiving_client/client-example.cpp - ${EXAMPLE_CONFIG_FILES} - ) -target_link_libraries(gear_client vsomeip3 ${Boost_LIBRARIES}) +# add_executable(gear_client +# ../src/gear-src/gear_data_receiving_client/client-main.cpp +# ../src/gear-src/gear_data_receiving_client/client-example.cpp +# ${EXAMPLE_CONFIG_FILES} +# ) +# target_link_libraries(gear_client vsomeip3 ${Boost_LIBRARIES}) + +# add_executable(single_gear_client +# ../src/gear-src/integerate_client/client-main.cpp +# ../src/gear-src/integerate_client/client-example.cpp +# ${EXAMPLE_CONFIG_FILES} +# ) +# target_link_libraries(single_gear_client vsomeip3 ${Boost_LIBRARIES}) # Req/Res testing diff --git a/apps/ServiceManager/build.sh b/apps/ServiceManager/build.sh index b9360b8..5c7eabb 100755 --- a/apps/ServiceManager/build.sh +++ b/apps/ServiceManager/build.sh @@ -26,4 +26,4 @@ echo "CMake 빌드 완료!" # cmake -Bbuild -DCMAKE_INSTALL_PREFIX=../../install_folder -DCMAKE_PREFIX_PATH=../../install_folder . # cmake --build=build # LD_LIBRARY_PATH=../../install_folder/lib/:$PWD/build/ ./build/service-example -# LD_LIBRARY_PATH=../../install_folder/lib/:$PWD/build/ ./build/client-example \ No newline at end of file +# LD_LIBRARY_PATH=../../install_folder/lib/:$PWD/build/ ./build/client-example__ \ No newline at end of file diff --git a/apps/ServiceManager/config/vsomeip.json b/apps/ServiceManager/config/vsomeip.json index ef958ec..0de67a2 100644 --- a/apps/ServiceManager/config/vsomeip.json +++ b/apps/ServiceManager/config/vsomeip.json @@ -7,10 +7,6 @@ "dlt": "false" }, "applications": [ - { - "name": "server", - "id": "0x1235" - }, { "name": "speed", "id": "0x4322", @@ -32,6 +28,27 @@ "eventgroups": ["0x4465"] } ] + }, + { + "name": "gear", + "id": "0x4324", + "services": [ + { + "service": "0x1234", + "instance": "0x4001", + "eventgroups": ["0x4465"] + } + ] + }, + { + "name": "ambient", + "id": "0x4325", + "services": [ + { + "service": "0x1234", + "instance": "0x5001" + } + ] } ], "services": [ @@ -58,6 +75,24 @@ "events": ["0x8780"] } ] + }, + { + "service": "0x1234", + "instance": "0x4001", + "reliable": { "port": "30511", "enable-magic-cookies": "false" }, + "unreliable": "31002", + "eventgroups": [ + { + "eventgroup": "0x4465", + "events": ["0x8781"] + } + ] + }, + { + "service": "0x1234", + "instance": "0x5001", + "reliable": { "port": "30512", "enable-magic-cookies": "false" }, + "unreliable": "31003" } ], "routing": "service-example", diff --git a/apps/ServiceManager/src/battery-src/battery/battery.cpp b/apps/ServiceManager/src/battery-src/battery/battery.cpp index b32f589..6780650 100644 --- a/apps/ServiceManager/src/battery-src/battery/battery.cpp +++ b/apps/ServiceManager/src/battery-src/battery/battery.cpp @@ -12,7 +12,7 @@ batteryObject::batteryObject(uint32_t _cycle) : speedData(0), voltage(0), file(-1){ - battery_thread_ = std::thread(&batteryObject::getBatteryVoltage, this); + battery_thread_ = std::thread(&batteryObject::getBatteryData, this); if (!initI2C()) { std::cout << "Failed to initialize I2C interface."; } @@ -27,7 +27,7 @@ bool batteryObject::init() { return false; } //서비스에 따라서 service id 변경. - + std::cout << "SERVER : init" << std::endl; app_->register_state_handler( std::bind(&batteryObject::on_state, this, std::placeholders::_1)); @@ -192,31 +192,6 @@ void batteryObject::on_set(const std::shared_ptr &_message) { } -//TODO: change it into battery service code. -/* -void batteryObject::getBatteryVoltage() { - float filtered_speed = 0.0f; - float weight = 0.6; - - std::cout << "running : " << running_ << std::endl; - while (running_) { - std::unique_lock its_lock(can_mutex_); - while (!is_offered_ && running_) - battery_condition_.wait(its_lock); - while (is_offered_ && running_) - { - { - filtered_speed += 0.2; - this->speedData = filtered_speed; - } - std::this_thread::sleep_for(std::chrono::milliseconds(7)); - - } - } - -} -*/ - // Destructor: Cleans up the resources (closes the I2C file descriptor) bool batteryObject::initI2C() { @@ -263,15 +238,48 @@ uint16_t batteryObject::readRegister() { return readValue; } -void batteryObject::getBatteryVoltage() { +uint8_t batteryObject::getBatteryVoltage() { // The battery voltage is stored in register 0x02 - // uint16_t voltageRaw = readRegister(); + uint16_t voltageRaw = readRegister(); // int voltage = 11; - uint8_t u_voltage = 11; + // uint8_t u_voltage = 11; - this->voltage = u_voltage; + // this->voltage = u_voltage; - // uint8_t voltage = ((voltageRaw>>3)*4.0)/1000; + voltage = ((voltageRaw>>3)*4.0)/1000; std::cout << "Battery Voltage: " << this->voltage << std::endl; - // return voltage; -} \ No newline at end of file + return voltage; +} + +void batteryObject::getBatteryData() { + // The battery voltage is stored in register 0x02 + uint8_t battery_percent = 0; + int lowVoltage = 9; + float diffVoltage = 3.45; + + + std::cout << "running : " << running_ << std::endl; + while (running_) { + std::unique_lock its_lock(can_mutex_); + while (!is_offered_ && running_) + battery_condition_.wait(its_lock); + while (is_offered_ && running_) + { + { + uint8_t voltage = this->getBatteryVoltage(); + float battery_percent = (((voltage - lowVoltage) / diffVoltage) * 100); + if (battery_percent -100 > 0) + battery_percent = 100; + else if (battery_percent < 0) + battery_percent = 0; + this->voltage = battery_percent; + // filtered_speed += 0.2; + // this->speedData = filtered_speed; + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + } + } + +} + diff --git a/apps/ServiceManager/src/battery-src/battery/battery.hpp b/apps/ServiceManager/src/battery-src/battery/battery.hpp index cabbb51..b70e286 100644 --- a/apps/ServiceManager/src/battery-src/battery/battery.hpp +++ b/apps/ServiceManager/src/battery-src/battery/battery.hpp @@ -30,7 +30,9 @@ private : uint16_t readRegister(); // Method to read a value from a register // void getBatteryVoltage(); - void getBatteryVoltage(); + uint8_t getBatteryVoltage(); + void getBatteryData(); + void canDataReceive(); std::shared_ptr app_; diff --git a/apps/ServiceManager/src/battery-src/battery_client/client-example.cpp b/apps/ServiceManager/src/battery-src/battery_client/client-example.cpp index fe7fe05..91b9349 100644 --- a/apps/ServiceManager/src/battery-src/battery_client/client-example.cpp +++ b/apps/ServiceManager/src/battery-src/battery_client/client-example.cpp @@ -81,18 +81,15 @@ void client_sample::on_availability(vsomeip::service_t _service, vsomeip::instan } void client_sample::on_message(const std::shared_ptr& _response) { + std::shared_ptr payload = _response->get_payload(); + int received_value = 0; - std::shared_ptr its_payload = _response->get_payload(); - if (its_payload->get_length() == sizeof(float)) { // 페이로드 크기로 검증 - float received_speed = 0.0f; - - // 이터레이터로 시작 위치 가져오기 - auto it = its_payload->get_data(); // 시작 위치의 이터레이터 - std::copy(it, it + sizeof(float), reinterpret_cast(&received_speed)); - - // 변환된 값 출력 - std::cout << "Received data: " << received_speed << " m/s" << std::endl; + if (payload->get_length() >= sizeof(int)) { + received_value = *reinterpret_cast(payload->get_data()); + std::cout << "SERVER: Received int: " << received_value << std::endl; } else { - std::cerr << "Invalid data size received!" << std::endl; + std::cerr << "SERVER: Invalid payload size!" << std::endl; + return; } + } diff --git a/apps/ServiceManager/src/gear-src/HU_gear_client/HU_gear_client.cpp b/apps/ServiceManager/src/gear-src/HU_gear_client/HU_gear_client.cpp new file mode 100644 index 0000000..cc65afb --- /dev/null +++ b/apps/ServiceManager/src/gear-src/HU_gear_client/HU_gear_client.cpp @@ -0,0 +1,88 @@ +#include +#include +#include + +#include +#include + +#include +#include "../../server.hpp" + +std::shared_ptr< vsomeip::application > app; +std::mutex mutex; +std::condition_variable condition; + +//sending the actual data (will be gear data) to server. +void run() { + std::unique_lock its_lock(mutex); + condition.wait(its_lock); + + std::shared_ptr< vsomeip::message > request; + request = vsomeip::runtime::get()->create_request(); + request->set_service(VEHICLE_SERVICE_ID); + request->set_instance(GEAR_INSTANCE_ID); + request->set_method(GEAR_SET_METHOD_ID); + +//sending actual data. changed into HU input value. + int value=0; + + while (1){ + // value += 1; + if (value != 5) + {std::cout << "Input number" << std::endl; + std::cin >> value;} + std::shared_ptr< vsomeip::payload > its_payload = vsomeip::runtime::get()->create_payload(); + std::vector its_payload_data( + reinterpret_cast(&value), + reinterpret_cast(&value) + sizeof(int) + ); + its_payload->set_data(its_payload_data); + request->set_payload(its_payload); + app->send(request); + std::this_thread::sleep_for(std::chrono::seconds(1)); + + } + std::cout << "CLIENT : DATA SENDED" << std::endl; +} + +// When response come, print the payload from server. +void on_message(const std::shared_ptr &_response) { + std::shared_ptr its_payload = _response->get_payload(); + vsomeip::length_t l = its_payload->get_length(); + + // Get payload + std::stringstream ss; + for (vsomeip::length_t i=0; iget_data()+i) << " "; + } + + std::cout << "CLIENT: Received message with Client/Session [" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_client() << "/" + << std::setw(4) << std::setfill('0') << std::hex << _response->get_session() << "] " + << ss.str() << std::endl; +} + +void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) { + std::cout << "CLIENT: Service [" + << std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance + << "] is " + << (_is_available ? "available." : "NOT available.") + << std::endl; + if (_is_available) { + std::this_thread::sleep_for(std::chrono::seconds(3)); + condition.notify_one(); + } +} + +int main() { + + app = vsomeip::runtime::get()->create_application("gear"); + app->init(); + app->register_availability_handler(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, on_availability); + std::this_thread::sleep_for(std::chrono::seconds(1)); + app->request_service(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID); + app->register_message_handler(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, JOY_GEAR_RESPONSE_MID, on_message); + std::thread sender(run); + app->start(); +} diff --git a/apps/ServiceManager/src/gear-src/HU_gear_client/HU_gear_client.hpp b/apps/ServiceManager/src/gear-src/HU_gear_client/HU_gear_client.hpp new file mode 100644 index 0000000..1e24653 --- /dev/null +++ b/apps/ServiceManager/src/gear-src/HU_gear_client/HU_gear_client.hpp @@ -0,0 +1,34 @@ +#ifndef GEAR_CLIENT_HPP +# define GEAR_CLIENT_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../server.hpp" + +class gearClient { +public: + gearClient(bool _use_tcp); + + bool init(); + void start(); + void stop(); + +private: + void on_state(vsomeip::state_type_e _state); + void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available); + void on_message(const std::shared_ptr& _response); + + std::shared_ptr app_; + bool use_tcp_; + + gearClient(void); + ~gearClient(void); +}; + +#endif \ No newline at end of file diff --git a/apps/ServiceManager/src/gear-src/J_gear_client/gear_client.cpp b/apps/ServiceManager/src/gear-src/J_gear_client/gear_client.cpp index 8d1b531..6881eb2 100644 --- a/apps/ServiceManager/src/gear-src/J_gear_client/gear_client.cpp +++ b/apps/ServiceManager/src/gear-src/J_gear_client/gear_client.cpp @@ -33,15 +33,13 @@ void run() { //sending actual data. changed into HU input value. int value=0; // <- real gear value should be on value variable while (1){ - // std::cout << "Input number" << std::endl; - // std::cin >> value; + std::cout << "Input number" << std::endl; + std::cin >> value; std::shared_ptr< vsomeip::payload > its_payload = vsomeip::runtime::get()->create_payload(); std::vector its_payload_data( reinterpret_cast(&value), reinterpret_cast(&value) + sizeof(int) - // reinterpret_cast(&gearValue), - // reinterpret_cast(&gearValue) + sizeof(int) ); its_payload->set_data(its_payload_data); request->set_payload(its_payload); diff --git a/apps/ServiceManager/src/gear-src/gear_data_receiving_client/client-example.cpp b/apps/ServiceManager/src/gear-src/gear_data_receiving_client/client-example.cpp index 1924520..05c804f 100644 --- a/apps/ServiceManager/src/gear-src/gear_data_receiving_client/client-example.cpp +++ b/apps/ServiceManager/src/gear-src/gear_data_receiving_client/client-example.cpp @@ -77,9 +77,9 @@ void client_sample::on_message(const std::shared_ptr &_request if (payload->get_length() >= sizeof(int)) { received_value = *reinterpret_cast(payload->get_data()); - std::cout << "GEAR DATA RECEIVING CLIENT : Received int: " << received_value << std::endl; + std::cout << "@@@@GEAR DATA RECEIVING CLIENT : Received int: " << received_value << std::endl; } else { - std::cerr << "GEAR DATA RECEIVING CLIENT : Invalid payload size!" << std::endl; + std::cerr << "@@@@GEAR DATA RECEIVING CLIENT : Invalid payload size!" << std::endl; return; } // this->gearValue = received_value; diff --git a/apps/ServiceManager/src/main.cpp b/apps/ServiceManager/src/main.cpp index 2ef2e78..d9afbea 100644 --- a/apps/ServiceManager/src/main.cpp +++ b/apps/ServiceManager/src/main.cpp @@ -37,7 +37,7 @@ int main(int argc, char **argv) { speedProcessInit(); exit(0); // speedProcessInit()이 종료되면, 자식 프로세스 종료 } - + sleep(2); if (speed_pid != 0) battery_pid = fork(); @@ -46,7 +46,7 @@ int main(int argc, char **argv) { batteryProcessInit(); exit(0); // batteryProcessInit()이 종료되면, 자식 프로세스 종료 } - + sleep(2); if (speed_pid != 0 && battery_pid != 0) { gear_pid = fork(); //gear 처리 프로세스 실행. diff --git a/apps/ServiceManager/src/service-main.cpp b/apps/ServiceManager/src/service-main.cpp index dd0cadd..57ae727 100644 --- a/apps/ServiceManager/src/service-main.cpp +++ b/apps/ServiceManager/src/service-main.cpp @@ -56,6 +56,7 @@ int batteryProcessInit() { #endif if (batteryInit.init()) { + std::cout << "Battery Process Started" << std::endl; batteryInit.start(); #ifdef VSOMEIP_ENABLE_SIGNAL_HANDLING batteryInit.stop(); diff --git a/apps/ServiceManager/src/speed-src/speed/canreceiver.cpp b/apps/ServiceManager/src/speed-src/speed/canreceiver.cpp index 42acef5..abfeb36 100644 --- a/apps/ServiceManager/src/speed-src/speed/canreceiver.cpp +++ b/apps/ServiceManager/src/speed-src/speed/canreceiver.cpp @@ -1,76 +1,144 @@ #include "./canreceiver.hpp" #include "../../headers.hpp" -// Constructor: Opens and binds the CAN socket to the specified interface -CANReceiver::CANReceiver(const std::string& interface_name) : socket_fd(-1) { - openSocket(interface_name); -} +#include "canreceiver.hpp" -// Destructor: Closes the CAN socket -CANReceiver::~CANReceiver() { - if (socket_fd != -1) { - close(socket_fd); - std::cout << "CAN socket closed." << std::endl; - } -} +// // Constructor: Opens and binds the CAN socket to the specified interface +CANReceiver::CANReceiver(){} +CANReceiver::~CANReceiver(){} + +// int CANReceiver::get(void) +// { +// // open_port("can0"); // Open the CAN port with the name "can0" +// // read_port(); // Read data from the CAN port + +// // return 0; + +// int s; +// struct sockaddr_can addr; +// struct ifreq ifr; +// struct can_frame frame; + +// // CAN 소켓 생성 +// if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { +// perror("CAN socket"); +// return 1; +// } + +// // CAN 인터페이스(can0) 설정 +// strcpy(ifr.ifr_name, "can0"); +// if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { +// perror("ioctl"); +// close(s); +// return 1; +// } + +// // 소켓을 인터페이스에 바인딩 +// addr.can_family = AF_CAN; +// addr.can_ifindex = ifr.ifr_ifindex; + +// if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { +// perror("bind"); +// close(s); +// return 1; +// } + +// std::cout << "CAN 소켓이 can0 인터페이스에 연결되었습니다.\n"; + +// // 데이터 수신 루프 +// while (true) { +// int nbytes = read(s, &frame, sizeof(struct can_frame)); + +// if (nbytes < 0) { +// perror("CAN read"); +// continue; +// } + +// // CAN 데이터 출력 +// std::cout << "CAN ID: 0x" << std::hex << frame.can_id << std::dec; +// std::cout << " DLC: " << static_cast(frame.can_dlc) << " Data: "; -// Opens a CAN socket and binds it to the given interface -void CANReceiver::openSocket(const std::string& interface_name) { - // Open the CAN_RAW socket - socket_fd = socket(PF_CAN, SOCK_RAW, CAN_RAW); - if (socket_fd < 0) { - perror("Error while opening CAN socket"); - throw std::runtime_error("Failed to open CAN socket"); +// for (int i = 0; i < frame.can_dlc; i++) +// printf("%02X ", frame.data[i]); + +// std::cout << std::endl; +// } + +// close(s); +// return 0; +// } +int CANReceiver::get(void) +{ + int s; + struct sockaddr_can addr; + struct ifreq ifr; + struct can_frame frame; + + + const float wheelDiameter = 6.7; // cm + const float pi = 3.14159; + const float wheelCircumference = wheelDiameter * pi; + const unsigned int numSlots = 20; // number of slots of the disk used for the speedsensor + const unsigned int scaleFactor = 10000; + const unsigned long scaledDistancePerPulse = (unsigned long)(wheelCircumference / numSlots * scaleFactor); + const unsigned int convertToPerSecFactor = 10; + const unsigned int sizeOfUnsignedLong = sizeof(unsigned long); + + // CAN 소켓 생성 + if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { + perror("CAN socket"); + return -1; } - // Get the interface index for the specified CAN interface - std::strncpy(ifr.ifr_name, interface_name.c_str(), IFNAMSIZ - 1); - if (ioctl(socket_fd, SIOCGIFINDEX, &ifr) < 0) { - perror("Error finding CAN interface"); - close(socket_fd); // Ensure socket is closed before throwing - throw std::runtime_error("Failed to find CAN interface"); + // CAN 인터페이스(can0) 설정 + strcpy(ifr.ifr_name, "can0"); + if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { + perror("ioctl"); + close(s); + return -1; } + // 소켓을 인터페이스에 바인딩 addr.can_family = AF_CAN; addr.can_ifindex = ifr.ifr_ifindex; - // Bind the socket to the CAN interface - if (bind(socket_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { - perror("Error in binding CAN socket"); - close(socket_fd); // Ensure socket is closed before throwing - throw std::runtime_error("Failed to bind CAN socket"); + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("bind"); + close(s); + return -1; } - std::cout << "CAN socket bound to interface: " << interface_name << std::endl; -} + std::cout << "CAN 소켓이 can0 인터페이스에 연결되었습니다.\n"; + + // 데이터 수신 (1회 읽기) + int nbytes = read(s, &frame, sizeof(struct can_frame)); -// Check if a CAN frame is available (read from socket) -bool CANReceiver::canRead() { - int nbytes = read(socket_fd, &frame, sizeof(struct can_frame)); if (nbytes < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - return false; // No data available, not an error - } - perror("Error reading CAN frame"); - return false; + perror("CAN read"); + close(s); + return -1; } - if (nbytes < sizeof(struct can_frame)) { - std::cerr << "Incomplete CAN frame" << std::endl; - return false; - } - return true; -} -// Extract speed from the received CAN frame -float CANReceiver::getSpeed() { - return calculateSpeed(&frame); -} + // CAN 데이터 출력 + std::cout << "CAN ID: 0x" << std::hex << frame.can_id << std::dec; + std::cout << " DLC: " << static_cast(frame.can_dlc) << " Data: "; + + for (int i = 0; i < frame.can_dlc; i++) + printf("%02X ", frame.data[i]); + std::cout << std::endl; + + // 데이터(int형)로 변환 + float value = 0; + int new_value = 0; + if(frame.can_dlc >= 4) { + memcpy(&value, frame.data, sizeof(float)); + std::cout << "수신한 int 값: " << value << std::endl; + } else { + std::cerr << "CAN 데이터 길이(DLC)가 4바이트 미만입니다." << std::endl; + close(s); + return -1; + } -// Calculate speed from the first two bytes of the CAN frame data -float CANReceiver::calculateSpeed(const struct can_frame* frame) { - // Interpret speed as a signed 16-bit integer - float speed = static_cast((frame->data[0] << 8) | frame->data[1]); - // float speed = 120; - std::cout << "Speed: " << speed << std::endl << std::flush; - return speed; + close(s); + return value; // 정수값 반환 } diff --git a/apps/ServiceManager/src/speed-src/speed/canreceiver.hpp b/apps/ServiceManager/src/speed-src/speed/canreceiver.hpp index f660bb0..de97a92 100644 --- a/apps/ServiceManager/src/speed-src/speed/canreceiver.hpp +++ b/apps/ServiceManager/src/speed-src/speed/canreceiver.hpp @@ -1,25 +1,53 @@ +// #ifndef CANRECEIVER_HPP +// #define CANRECEIVER_HPP + + +// // CANReceiver class for handling CAN communication +// class CANReceiver { + // public: + // CANReceiver(const std::string& interface_name); // Constructor + // ~CANReceiver(); // Destructor + + // bool canRead(); // Check if CAN frame is available + // float getSpeed(); // Get speed from the CAN frame + + // private: + // int socket_fd; // File descriptor for the CAN socket + // struct sockaddr_can addr; // CAN address + // struct ifreq ifr; // Interface request structure + // struct can_frame frame; // CAN frame structure + + // float calculateSpeed(const struct can_frame* frame) const ; // Calculate speed from CAN frame data + // void openSocket(const std::string& interface_name); // Open and bind CAN socket + // }; + +// #endif // CANRECEIVER_HPP #ifndef CANRECEIVER_HPP #define CANRECEIVER_HPP #include "../../headers.hpp" +#include +#include +#include +#include +#include +#include +#include +#include -// CANReceiver class for handling CAN communication class CANReceiver { -public: - CANReceiver(const std::string& interface_name); // Constructor - ~CANReceiver(); // Destructor - - bool canRead(); // Check if CAN frame is available - float getSpeed(); // Get speed from the CAN frame - private: - int socket_fd; // File descriptor for the CAN socket - struct sockaddr_can addr; // CAN address - struct ifreq ifr; // Interface request structure - struct can_frame frame; // CAN frame structure + int socket_fd; + struct sockaddr_can addr; + struct ifreq ifr; + struct can_frame frame; + +public: + + CANReceiver(); + ~CANReceiver(); - float calculateSpeed(const struct can_frame* frame); // Calculate speed from CAN frame data - void openSocket(const std::string& interface_name); // Open and bind CAN socket + int get(); }; #endif // CANRECEIVER_HPP diff --git a/apps/ServiceManager/src/speed-src/speed/speed.cpp b/apps/ServiceManager/src/speed-src/speed/speed.cpp index 1826e62..4b281c5 100644 --- a/apps/ServiceManager/src/speed-src/speed/speed.cpp +++ b/apps/ServiceManager/src/speed-src/speed/speed.cpp @@ -171,6 +171,8 @@ void speedObject::canDataReceive() { std::cout << "can Data Receive started" << std::endl; float filtered_speed = 0.0f; float weight = 0.6; + CANReceiver receiver; + // CANReceiver receiver("can0"); while (running_) { std::unique_lock its_lock(can_mutex_); @@ -178,12 +180,37 @@ void speedObject::canDataReceive() { CAN_condition_.wait(its_lock); while (is_offered_ && running_) { - { - filtered_speed += 0.1; + { + filtered_speed = receiver.get(); + // receiver.canRead(); + // filtered_speed = receiver.getSpeed(); + // filtered_speed = (1-weight)*filtered_speed + (weight)*canData.getSpeed(); this->speedData = filtered_speed; + std::cout << "[Speed server] in can data receive loop : filtered_speed : " << filtered_speed << std::endl; + // if (filtered_speed >= 100.0f) + // filtered_speed = 0.0f; + // filtered_speed += 0.1; + // this->speedData = filtered_speed; } - std::this_thread::sleep_for(std::chrono::milliseconds(7)); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); } } + + // while (running_) { + // std::unique_lock its_lock(can_mutex_); + // while (!is_offered_ && running_) + // CAN_condition_.wait(its_lock); + // while (is_offered_ && running_) + // { + // { + // if (filtered_speed >= 100.0f) + // filtered_speed = 0.0f; + // filtered_speed += 0.1; + // this->speedData = filtered_speed; + // } + // std::this_thread::sleep_for(std::chrono::milliseconds(300)); + + // } + // } } diff --git a/apps/ServiceManager/src/speed-src/speed/speed.hpp b/apps/ServiceManager/src/speed-src/speed/speed.hpp index 1c8dc9a..fbd94ea 100644 --- a/apps/ServiceManager/src/speed-src/speed/speed.hpp +++ b/apps/ServiceManager/src/speed-src/speed/speed.hpp @@ -2,6 +2,7 @@ # define SPEED_HPP #include "../../service_base/service-base.hpp" +#include "./canreceiver.hpp" class speedObject : public service_sample { diff --git a/apps/VehicleController/CMakeLists.txt b/apps/VehicleController/CMakeLists.txt index 0581f25..83abe23 100644 --- a/apps/VehicleController/CMakeLists.txt +++ b/apps/VehicleController/CMakeLists.txt @@ -6,15 +6,26 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/..) +# set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/..) + +set(EXAMPLE_CONFIG_FILES + ./vsomeip.json +) + find_package(pigpio REQUIRED) +find_package(vsomeip3 3.5.3 REQUIRED) +find_package( Boost 1.55 COMPONENTS system thread log REQUIRED ) + include_directories( ./Adafruit_PCA9685 ./Gamepad ./PiRacer ${pigpio_INCLUDE_DIRS} + ${Boost_INCLUDE_DIR} + ${VSOMEIP_INCLUDE_DIRS} + ) set(PIRACER_SRC @@ -31,6 +42,8 @@ add_executable(vehicle-controller main.cpp ${PIRACER_SRC} ${GAMEPAD_SRC} + ${EXAMPLE_CONFIG_FILES} + ) -target_link_libraries(vehicle-controller ${pigpio_LIBRARY}) +target_link_libraries(vehicle-controller ${pigpio_LIBRARY} ${Boost_LIBRARIES}) diff --git a/apps/VehicleController/Gamepad/ShanwanGamepad.cpp b/apps/VehicleController/Gamepad/ShanwanGamepad.cpp index ce75d91..91ce780 100644 --- a/apps/VehicleController/Gamepad/ShanwanGamepad.cpp +++ b/apps/VehicleController/Gamepad/ShanwanGamepad.cpp @@ -21,7 +21,7 @@ ShanWanGamepadInput ShanWanGamepad::read_data() { if (0 <= button_number) gamepad_input.button = true; if (0 <= axis_number) - gamepad_input.analog_stick = ture; + gamepad_input.analog_stick = true; // Joysticks if (axis_number == 0) diff --git a/apps/VehicleController/main.cpp b/apps/VehicleController/main.cpp index 7c732e9..b1a413e 100644 --- a/apps/VehicleController/main.cpp +++ b/apps/VehicleController/main.cpp @@ -1,5 +1,15 @@ -#include "PiRacer/PiRacer.hpp" -#include "Gamepad/ShanwanGamepad.hpp" +#include "./PiRacer/PiRacer.hpp" +#include "./Gamepad/ShanwanGamepad.hpp" +#include "../ServiceManager/src/server.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include /** * A : DRIVE @@ -15,6 +25,79 @@ enum Gear { DRIVE }; +Gear gear = PARKING; +PiRacer racer; + +std::shared_ptr app; +std::mutex mutex; +std::condition_variable condition; + +// sending the actual data (will be gear data) to server. +// void send_gear_data(int data) { +// std::unique_lock its_lock(mutex); +// condition.wait(its_lock); + +// std::shared_ptr request; +// request = vsomeip::runtime::get()->create_request(); +// request->set_service(VEHICLE_SERVICE_ID); +// request->set_instance(GEAR_INSTANCE_ID); +// request->set_method(JOY_GEAR_SET_MID); + +// std::shared_ptr its_payload = vsomeip::runtime::get()->create_payload(); +// std::vector its_payload_data( +// reinterpret_cast(&data), +// reinterpret_cast(&data) + sizeof(int)); +// its_payload->set_data(its_payload_data); +// request->set_payload(its_payload); +// app->send(request); +// std::cout << "CLIENT : DATA SENDED" << std::endl; +// std::this_thread::sleep_for(std::chrono::seconds(1)); +// } + +void set_gear(ShanWanGamepadInput input, int received_value) { + if (input.button_a || received_value == 3) + gear = DRIVE; + else if (input.button_b || received_value == 2) + gear = NEUTRAL; + else if (input.button_x || received_value == 1) + gear = REVERSE; + else if (input.button_y || received_value == 0) + gear = PARKING; + + if (gear == PARKING || gear == NEUTRAL){ + racer.setSteeringPercent(0); + racer.setThrottlePercent(0); + } +} + +// When response come, print the payload from server. +void on_message(const std::shared_ptr &_response) { + std::shared_ptr payload = _response->get_payload(); + int received_value = 0; + + if (payload->get_length() >= sizeof(int)) { + received_value = *reinterpret_cast(payload->get_data()); + // set_gear(0, received_value); + std::cout << "SERVER: Received int: " << received_value << std::endl; + } + else { + std::cerr << "SERVER: Invalid payload size!" << std::endl; + return; + } +} + +void init_vSOMEIP() { + // app = vsomeip::runtime::get()->create_application("gear"); + // app->init(); + // // app->register_availability_handler(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, on_availability); + // std::this_thread::sleep_for(std::chrono::seconds(1)); + // app->request_service(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID); + // std::this_thread::sleep_for(std::chrono::seconds(1)); + // app->register_message_handler(VEHICLE_SERVICE_ID, GEAR_INSTANCE_ID, JOY_GEAR_SET_MID, on_message); + // std::thread sender(send_gear_data); + // app->start(); +} + int main() { atexit(gpioTerminate); @@ -23,9 +106,8 @@ int main() { return 1; } - PiRacer racer; + init_vSOMEIP(); ShanWanGamepad gamepad; - Gear gear = PARKING; float steering = 0; float throttle = 0; @@ -34,14 +116,8 @@ int main() { ShanWanGamepadInput input = gamepad.read_data(); if (input.button) { - if (input.button_a) - gear = DRIVE; - else if (input.button_b) - gear = NEUTRAL; - else if (input.button_x) - gear = REVERSE; - else if (input.button_y) - gear = PARKING; + set_gear(input, -1); + // send_gear_data(gear); } else { if (gear == PARKING || gear == NEUTRAL) @@ -60,7 +136,4 @@ int main() { racer.setThrottlePercent(throttle); } } - - return 0; } - diff --git a/apps/VehicleController/vsomeip.json b/apps/VehicleController/vsomeip.json new file mode 100644 index 0000000..0de67a2 --- /dev/null +++ b/apps/VehicleController/vsomeip.json @@ -0,0 +1,112 @@ +{ + "unicast": "127.0.0.1", + "logging": { + "level": "debug", + "console": "true", + "file": { "enable": "false", "path": "/var/log/vsomeip.log" }, + "dlt": "false" + }, + "applications": [ + { + "name": "speed", + "id": "0x4322", + "services": [ + { + "service": "0x1234", + "instance": "0x2001", + "eventgroups": ["0x4465"] + } + ] + }, + { + "name":"battery", + "id": "0x4323", + "services": [ + { + "service": "0x1234", + "instance": "0x3001", + "eventgroups": ["0x4465"] + } + ] + }, + { + "name": "gear", + "id": "0x4324", + "services": [ + { + "service": "0x1234", + "instance": "0x4001", + "eventgroups": ["0x4465"] + } + ] + }, + { + "name": "ambient", + "id": "0x4325", + "services": [ + { + "service": "0x1234", + "instance": "0x5001" + } + ] + } + ], + "services": [ + { + "service": "0x1234", + "instance": "0x2001", + "reliable": { "port": "30509", "enable-magic-cookies": "false" }, + "unreliable": "31000", + "eventgroups": [ + { + "eventgroup": "0x4465", + "events": ["0x8779"] + } + ] + }, + { + "service": "0x1234", + "instance": "0x3001", + "reliable": { "port": "30510", "enable-magic-cookies": "false" }, + "unreliable": "31001", + "eventgroups": [ + { + "eventgroup": "0x4465", + "events": ["0x8780"] + } + ] + }, + { + "service": "0x1234", + "instance": "0x4001", + "reliable": { "port": "30511", "enable-magic-cookies": "false" }, + "unreliable": "31002", + "eventgroups": [ + { + "eventgroup": "0x4465", + "events": ["0x8781"] + } + ] + }, + { + "service": "0x1234", + "instance": "0x5001", + "reliable": { "port": "30512", "enable-magic-cookies": "false" }, + "unreliable": "31003" + } + ], + "routing": "service-example", + "service-discovery": { + "enable": "true", + "multicast": "224.244.224.245", + "port": "30490", + "protocol": "udp", + "initial_delay_min": "10", + "initial_delay_max": "100", + "repetitions_base_delay": "100", + "repetitions_max": "3", + "ttl": "3", + "cyclic_offer_delay": "2000", + "request_response_delay": "1500" + } +} diff --git a/speed_sensor/speed_sensor.ino b/speed_sensor/speed_sensor.ino index 3a5bebd..b6df930 100644 --- a/speed_sensor/speed_sensor.ino +++ b/speed_sensor/speed_sensor.ino @@ -2,60 +2,57 @@ #include "mcp2515_can.h" #define sensor 3 -const int SPI_CS_PIN = 9; // default is 9 -mcp2515_can CAN(SPI_CS_PIN); // Set CS pin - +const int SPI_CS_PIN = 9; +mcp2515_can CAN(SPI_CS_PIN); volatile unsigned int pulseCount = 0; -unsigned long currentMillis = 0; -unsigned long lastMillis = 0; -const long interval = 100; -unsigned char data[8]; +unsigned long currentMillis, previousMillis = 0; +const unsigned long interval = 1000; // 1초 단위 측정 (필요에 따라 조정 가능) + +void countPulses() { + pulseCount++; +} void setup() { - SERIAL_PORT_MONITOR.begin(115200); + Serial.begin(115200); - // init can bus : baudrate = 500k always keep it same to the Rpi CAN interface + // CAN 초기화 while (CAN_OK != CAN.begin(CAN_500KBPS)) { - SERIAL_PORT_MONITOR.println("CAN init fail, retry..."); - delay(100); + Serial.println("CAN init fail, retry..."); + delay(100); } - SERIAL_PORT_MONITOR.println("CAN init ok!"); + Serial.println("CAN init ok!"); + // 센서 핀 설정 pinMode(sensor, INPUT); attachInterrupt(digitalPinToInterrupt(sensor), countPulses, RISING); } void loop() { - - currentMillis = millis(); - - if (currentMillis - lastMillis >= interval) { - - lastMillis = currentMillis; - - float rpm = getRPM(); + static unsigned long previousMillis = 0; + unsigned long currentMillis = millis(); + + const int wheelHoles = 20; + static unsigned int pulseSnapshot = 0; + + if (currentMillis - pulseSnapshot >= 1000) { // 1초마다 RPM 계산 + noInterrupts(); // 인터럽트 임시 중지 + unsigned int pulses = pulseCount; + pulseCount = 0; // 펄스 카운트 초기화 + interrupts(); // 인터럽트 재개 + + float rotations = pulses / (float)wheelHoles; + float rpm = rotations * 60.0; // rotations per second (1초 주기) + + Serial.print("RPM: "); Serial.println(rpm); - pulseCount = 0; - memcpy(data, &rpm, sizeof(rpm)); - CAN.sendMsgBuf(0x7, 0, 4, data); // Send the data on the CAN bus + // CAN으로 전송 + byte data[4]; + memcpy(data, &rpm, sizeof(float)); + CAN.sendMsgBuf(0x7, 0, sizeof(float), data); + Serial.println("CAN BUS sendMsgBuf ok!"); - SERIAL_PORT_MONITOR.println("CAN BUS sendMsgBuf ok!"); // Print a success message + pulseSnapshot = currentMillis; } } - -void countPulses() { - pulseCount++; -} - -float getRPM() { - int wheelHoles = 20; // Number of holes in the wheel - float seconds = interval / 1000.0; // Convert interval from milliseconds to seconds - - float rotations = (float)pulseCount / wheelHoles; // Calculate number of rotations - float rotationsPerSecond = rotations / seconds; // Calculate rotations per second - float rpm = rotationsPerSecond * 60; // Convert to RPM - - return rpm; -}