1 // Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
2 // This Source Code Form is subject to the terms of the Mozilla Public
3 // License, v. 2.0. If a copy of the MPL was not distributed with this
4 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 #ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
6 #include <csignal>
7 #endif
8 #include <chrono>
9 #include <condition_variable>
10 #include <iomanip>
11 #include <iostream>
12 #include <sstream>
13 #include <thread>
14 #include <mutex>
15 
16 #include <vsomeip/vsomeip.hpp>
17 
18 #include "sample-ids.hpp"
19 
20 class service_sample {
21 public:
service_sample(bool _use_tcp,uint32_t _cycle)22     service_sample(bool _use_tcp, uint32_t _cycle) :
23             app_(vsomeip::runtime::get()->create_application()),
24             is_registered_(false),
25             use_tcp_(_use_tcp),
26             cycle_(_cycle),
27             blocked_(false),
28             running_(true),
29             is_offered_(false),
30             offer_thread_(std::bind(&service_sample::run, this)),
31             notify_thread_(std::bind(&service_sample::notify, this)) {
32     }
33 
init()34     bool init() {
35         std::lock_guard<std::mutex> its_lock(mutex_);
36 
37         if (!app_->init()) {
38             std::cerr << "Couldn't initialize application" << std::endl;
39             return false;
40         }
41         app_->register_state_handler(
42                 std::bind(&service_sample::on_state, this,
43                         std::placeholders::_1));
44 
45         app_->register_message_handler(
46                 SAMPLE_SERVICE_ID,
47                 SAMPLE_INSTANCE_ID,
48                 SAMPLE_GET_METHOD_ID,
49                 std::bind(&service_sample::on_get, this,
50                           std::placeholders::_1));
51 
52         app_->register_message_handler(
53                 SAMPLE_SERVICE_ID,
54                 SAMPLE_INSTANCE_ID,
55                 SAMPLE_SET_METHOD_ID,
56                 std::bind(&service_sample::on_set, this,
57                           std::placeholders::_1));
58 
59         std::set<vsomeip::eventgroup_t> its_groups;
60         its_groups.insert(SAMPLE_EVENTGROUP_ID);
61         app_->offer_event(
62                 SAMPLE_SERVICE_ID,
63                 SAMPLE_INSTANCE_ID,
64                 SAMPLE_EVENT_ID,
65                 its_groups,
66                 vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(),
67                 false, true, nullptr, vsomeip::reliability_type_e::RT_UNKNOWN);
68         {
69             std::lock_guard<std::mutex> its_lock(payload_mutex_);
70             payload_ = vsomeip::runtime::get()->create_payload();
71         }
72 
73         blocked_ = true;
74         condition_.notify_one();
75         return true;
76     }
77 
start()78     void start() {
79         app_->start();
80     }
81 
82 #ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
83     /*
84      * Handle signal to shutdown
85      */
stop()86     void stop() {
87         running_ = false;
88         blocked_ = true;
89         condition_.notify_one();
90         notify_condition_.notify_one();
91         app_->clear_all_handler();
92         stop_offer();
93         offer_thread_.join();
94         notify_thread_.join();
95         app_->stop();
96     }
97 #endif
98 
offer()99     void offer() {
100         std::lock_guard<std::mutex> its_lock(notify_mutex_);
101         app_->offer_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
102         is_offered_ = true;
103         notify_condition_.notify_one();
104     }
105 
stop_offer()106     void stop_offer() {
107         app_->stop_offer_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
108         is_offered_ = false;
109     }
110 
on_state(vsomeip::state_type_e _state)111     void on_state(vsomeip::state_type_e _state) {
112         std::cout << "Application " << app_->get_name() << " is "
113         << (_state == vsomeip::state_type_e::ST_REGISTERED ?
114                 "registered." : "deregistered.") << std::endl;
115 
116         if (_state == vsomeip::state_type_e::ST_REGISTERED) {
117             if (!is_registered_) {
118                 is_registered_ = true;
119             }
120         } else {
121             is_registered_ = false;
122         }
123     }
124 
on_get(const std::shared_ptr<vsomeip::message> & _message)125     void on_get(const std::shared_ptr<vsomeip::message> &_message) {
126         std::shared_ptr<vsomeip::message> its_response
127             = vsomeip::runtime::get()->create_response(_message);
128         {
129             std::lock_guard<std::mutex> its_lock(payload_mutex_);
130             its_response->set_payload(payload_);
131         }
132         app_->send(its_response);
133     }
134 
on_set(const std::shared_ptr<vsomeip::message> & _message)135     void on_set(const std::shared_ptr<vsomeip::message> &_message) {
136         std::shared_ptr<vsomeip::message> its_response
137             = vsomeip::runtime::get()->create_response(_message);
138         {
139             std::lock_guard<std::mutex> its_lock(payload_mutex_);
140             payload_ = _message->get_payload();
141             its_response->set_payload(payload_);
142         }
143 
144         app_->send(its_response);
145         app_->notify(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID,
146                      SAMPLE_EVENT_ID, payload_);
147     }
148 
run()149     void run() {
150         std::unique_lock<std::mutex> its_lock(mutex_);
151         while (!blocked_)
152             condition_.wait(its_lock);
153 
154         bool is_offer(true);
155         while (running_) {
156             if (is_offer)
157                 offer();
158             else
159                 stop_offer();
160 
161             for (int i = 0; i < 10 && running_; i++)
162                 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
163 
164             is_offer = !is_offer;
165         }
166     }
167 
notify()168     void notify() {
169         std::shared_ptr<vsomeip::message> its_message
170             = vsomeip::runtime::get()->create_request(use_tcp_);
171 
172         its_message->set_service(SAMPLE_SERVICE_ID);
173         its_message->set_instance(SAMPLE_INSTANCE_ID);
174         its_message->set_method(SAMPLE_SET_METHOD_ID);
175 
176         vsomeip::byte_t its_data[10];
177         uint32_t its_size = 1;
178 
179         while (running_) {
180             std::unique_lock<std::mutex> its_lock(notify_mutex_);
181             while (!is_offered_ && running_)
182                 notify_condition_.wait(its_lock);
183             while (is_offered_ && running_) {
184                 if (its_size == sizeof(its_data))
185                     its_size = 1;
186 
187                 for (uint32_t i = 0; i < its_size; ++i)
188                     its_data[i] = static_cast<uint8_t>(i);
189 
190                 {
191                     std::lock_guard<std::mutex> its_lock(payload_mutex_);
192                     payload_->set_data(its_data, its_size);
193 
194                     std::cout << "Setting event (Length=" << std::dec << its_size << ")." << std::endl;
195                     app_->notify(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENT_ID, payload_);
196                 }
197 
198                 its_size++;
199 
200                 std::this_thread::sleep_for(std::chrono::milliseconds(cycle_));
201             }
202         }
203     }
204 
205 private:
206     std::shared_ptr<vsomeip::application> app_;
207     bool is_registered_;
208     bool use_tcp_;
209     uint32_t cycle_;
210 
211     std::mutex mutex_;
212     std::condition_variable condition_;
213     bool blocked_;
214     bool running_;
215 
216     std::mutex notify_mutex_;
217     std::condition_variable notify_condition_;
218     bool is_offered_;
219 
220     std::mutex payload_mutex_;
221     std::shared_ptr<vsomeip::payload> payload_;
222 
223     // blocked_ / is_offered_ must be initialized before starting the threads!
224     std::thread offer_thread_;
225     std::thread notify_thread_;
226 };
227 
228 #ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
229     service_sample *its_sample_ptr(nullptr);
handle_signal(int _signal)230     void handle_signal(int _signal) {
231         if (its_sample_ptr != nullptr &&
232                 (_signal == SIGINT || _signal == SIGTERM))
233             its_sample_ptr->stop();
234     }
235 #endif
236 
main(int argc,char ** argv)237 int main(int argc, char **argv) {
238     bool use_tcp = false;
239     uint32_t cycle = 1000; // default 1s
240 
241     std::string tcp_enable("--tcp");
242     std::string udp_enable("--udp");
243     std::string cycle_arg("--cycle");
244 
245     for (int i = 1; i < argc; i++) {
246         if (tcp_enable == argv[i]) {
247             use_tcp = true;
248             break;
249         }
250         if (udp_enable == argv[i]) {
251             use_tcp = false;
252             break;
253         }
254 
255         if (cycle_arg == argv[i] && i + 1 < argc) {
256             i++;
257             std::stringstream converter;
258             converter << argv[i];
259             converter >> cycle;
260         }
261     }
262 
263     service_sample its_sample(use_tcp, cycle);
264 #ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
265     its_sample_ptr = &its_sample;
266     signal(SIGINT, handle_signal);
267     signal(SIGTERM, handle_signal);
268 #endif
269     if (its_sample.init()) {
270         its_sample.start();
271         return 0;
272     } else {
273         return 1;
274     }
275 }
276