2 * Copyright (c) 2013, TOYOTA MOTOR CORPORATION.
4 * This program is licensed under the terms and conditions of the
5 * Apache License, version 2.0. The full text of the Apache License is at
6 * http://www.apache.org/licenses/LICENSE-2.0
10 * @brief Regulation controller
22 #include <sys/ioctl.h>
26 #include <wayland-client.h>
27 #include <ico_window_mgr-client-protocol.h>
28 #include <dbus/dbus.h>
31 #include "ico_syc_apc.h"
32 #include "ico_syc_apc_private.h"
34 /*==============================================================================*/
36 /*==============================================================================*/
37 /* callback function */
38 static ico_apc_regulation_cb_t regulation_cb = NULL;
39 static void *regulation_cb_user_data = NULL;
41 /* Ecore/D-Bus static valiables */
42 static Ecore_Timer *vehicle_timer = NULL;
43 static DBusConnection *dbus_connection = NULL;
44 static ico_apc_reguration_control_t control[ICO_UXF_CATEGORY_MAX];
46 /* vehicle information */
47 static const struct _vehicle_info_property {
48 int key; /* Vehicle Information key */
49 char *property; /* D-Bus property name */
50 char *path; /* D-Bus path name */
51 char *interface; /* D-Bus interface name */
53 { ICO_SYC_VEHICLEINFO_VEHICLE_SPEED, "VehicleSpeed",
54 "/org/automotive/runningstatus/vehicleSpeed", "org.automotive.vehicleSpeed" },
55 { ICO_SYC_VEHICLEINFO_SHIFT_POSITION, "ShiftPosition",
56 "/org/automotive/runningstatus/transmission", "org.automotive.transmission" },
57 { ICO_SYC_VEHICLEINFO_TURN_SIGNAL, "TurnSignal",
58 "/org/automotive/runningstatus/turnSignal", "org.automotive.turnSignal" },
59 { 0, "\0", "\0", "\0" }
62 /* Vehicle information data */
63 static struct _vehicle_info_data {
64 int key; /* Vehicle Information key */
65 DBusPendingCall *pending;
69 } vehicle_data[ICO_UXF_REGULATION_VIC_MAX];
71 /* system configuration */
72 static Ico_Uxf_Sys_Config *confsys = NULL;
74 static Ico_Uxf_conf_category *category;
76 /*==============================================================================*/
77 /* define static function prototype */
78 /*==============================================================================*/
79 static int request_vehicle_info(void);
80 static int get_vehicle_info(void);
81 static Eina_Bool rule_engine_wake(void *user_data);
83 /*--------------------------------------------------------------------------*/
85 * @brief request_vehicle_info: request to AMB(static function)
89 * @retval ICO_SYC_EOK success
90 * @retval ICO_SYC_EIO error(D-Bus send error)
92 /*--------------------------------------------------------------------------*/
94 request_vehicle_info(void)
96 DBusMessage *dbus_message = NULL;
98 int ret = ICO_SYC_EOK;
100 for (idx = 0; vehicle_info[idx].key; idx++) {
102 /* set vehicle info key */
103 vehicle_data[idx].key = vehicle_info[idx].key;
105 if (vehicle_data[idx].pending) {
106 apfw_trace("request_vehicle_info: (%s) not complite",
107 vehicle_info[idx].property);
111 if (vehicle_info[idx].path[0] == 0) {
112 /* currently not support this vehicle information */
116 /* Create send message */
117 dbus_message = dbus_message_new_method_call(DBUS_SERVICE, vehicle_info[idx].path,
118 DBUS_INTERFACE, DBUS_METHOD);
119 if (! dbus_message) {
120 apfw_warn("request_vehicle_info: ERROR dbus_message_new_method_call" );
123 /* Set parameters into message */
124 else if (! dbus_message_append_args(
126 DBUS_TYPE_STRING, &vehicle_info[idx].interface,
127 DBUS_TYPE_STRING, &vehicle_info[idx].property,
128 DBUS_TYPE_INVALID)) {
129 apfw_warn("request_vehicle_info: ERROR dbus_message_append_args" );
132 /* Set destination */
133 else if (! dbus_message_set_destination(dbus_message, DBUS_SERVICE)) {
134 apfw_warn("request_vehicle_info: ERROR dbus_message_set_destination" );
138 else if (! dbus_connection_send_with_reply(
139 dbus_connection, dbus_message,
140 &vehicle_data[idx].pending, 200)) {
141 apfw_warn("request_vehicle_info: ERROR dbus_connection_send" );
142 vehicle_data[idx].pending = NULL;
146 /* Release message */
147 dbus_message_unref(dbus_message);
151 /* dispatch if data queue exist */
153 dbus_connection_read_write_dispatch(dbus_connection, 0);
154 } while (dbus_connection_get_dispatch_status(dbus_connection)
155 == DBUS_DISPATCH_DATA_REMAINS);
160 /*--------------------------------------------------------------------------*/
162 * @brief get_vehicle_info: get vercle information from AMB(static function)
165 * @return always ICO_SYC_EOK(success)
167 /*--------------------------------------------------------------------------*/
169 get_vehicle_info(void)
171 DBusMessage *dbus_message = NULL;
172 DBusMessageIter iter_head;
173 DBusMessageIter iter;
184 /* dispatch if data queue exist */
186 dbus_connection_read_write_dispatch(dbus_connection, 0);
187 } while (dbus_connection_get_dispatch_status(dbus_connection)
188 == DBUS_DISPATCH_DATA_REMAINS);
190 /* analize reply datas */
191 for (idx = 0; vehicle_info[idx].key; idx++) {
192 if (! vehicle_data[idx].pending) {
195 if (! dbus_pending_call_get_completed(vehicle_data[idx].pending)) {
196 apfw_trace("get_vehicle_info: (%s) NOT complite",
197 vehicle_info[idx].property);
201 dbus_message = dbus_pending_call_steal_reply(vehicle_data[idx].pending);
202 if (! dbus_message) {
203 apfw_trace("get_vehicle_info: (%s) NO reply", vehicle_info[idx].property);
207 if (dbus_message_get_type(dbus_message) == DBUS_MESSAGE_TYPE_ERROR) {
208 dbus_message_unref(dbus_message);
209 dbus_pending_call_unref(vehicle_data[idx].pending);
210 vehicle_data[idx].pending = NULL;
211 vehicle_data[idx].errcount ++;
212 if (vehicle_data[idx].errcount <= 5) {
213 apfw_trace("get_vehicle_info: (%s) reply error", vehicle_info[idx].property);
218 dbus_message_iter_init(dbus_message, &iter_head);
219 dbus_message_iter_recurse(&iter_head, &iter);
221 type = dbus_message_iter_get_arg_type(&iter);
223 case DBUS_TYPE_INT32:
224 dbus_message_iter_get_basic(&iter, &i32);
225 vehicle_data[idx].val = (double)i32;
227 case DBUS_TYPE_INT16:
228 dbus_message_iter_get_basic(&iter, &i16);
229 vehicle_data[idx].val = (double)i16;
231 case DBUS_TYPE_UINT32:
232 dbus_message_iter_get_basic(&iter, &u32);
233 vehicle_data[idx].val = (double)u32;
235 case DBUS_TYPE_UINT16:
236 dbus_message_iter_get_basic(&iter, &u16);
237 vehicle_data[idx].val = (double)u16;
239 case DBUS_TYPE_BOOLEAN:
240 dbus_message_iter_get_basic(&iter, &b);
241 if (b) vehicle_data[idx].val = (double)1.0;
242 else vehicle_data[idx].val = (double)0.0;
245 dbus_message_iter_get_basic(&iter, &u8);
246 vehicle_data[idx].val = (double)u8;
248 case DBUS_TYPE_DOUBLE:
249 dbus_message_iter_get_basic(&iter, &d64);
250 vehicle_data[idx].val = (double)d64;
253 apfw_warn("get_vehicle_info: (%s) illegal data type(0x%02x)",
254 vehicle_info[idx].property, ((int)type) & 0x0ff);
257 /* free message and pending */
258 dbus_message_unref(dbus_message);
259 dbus_pending_call_unref(vehicle_data[idx].pending);
260 vehicle_data[idx].pending = NULL;
265 /*--------------------------------------------------------------------------*/
267 * @brief rule_engine_wake: judge a run regulation state(static function)
269 * @param[in] user_data user data(unused)
270 * @return always ECORE_CALLBACK_RENEW(periodic timer)
272 /*--------------------------------------------------------------------------*/
274 rule_engine_wake(void *user_data)
277 ico_apc_reguration_control_t wkcontrol[ICO_UXF_CATEGORY_MAX];
278 ico_apc_reguration_control_t change;
279 double VehicleSpeed = 0.0;
280 int ShiftPosition = 0;
283 memset(wkcontrol, 0, sizeof(ico_apc_reguration_control_t) * ncategory);
285 /* get reply (vehicle ifno) */
288 /* get vehicle info values */
289 for (idx = 0; vehicle_data[idx].key; idx++) {
290 if (vehicle_data[idx].key == ICO_SYC_VEHICLEINFO_VEHICLE_SPEED) {
291 VehicleSpeed = (double)vehicle_data[idx].val;
293 else if (vehicle_data[idx].key == ICO_SYC_VEHICLEINFO_SHIFT_POSITION) {
294 ShiftPosition = (int)vehicle_data[idx].val;
296 else if (vehicle_data[idx].key == ICO_SYC_VEHICLEINFO_TURN_SIGNAL) {
297 Blinker = (int)vehicle_data[idx].val;
301 /* Make control code */
302 memcpy(wkcontrol, control, sizeof(ico_apc_reguration_control_t) * ncategory);
304 /* Check Vehicle Speed */
305 for (idx = 0; idx < ncategory; idx++) {
306 switch (category[idx].view) {
307 case ICO_UXF_POLICY_ALWAYS:
308 wkcontrol[idx].display = ICO_SYC_APC_REGULATION_NOREGULATION;
310 case ICO_UXF_POLICY_RUNNING:
311 if (VehicleSpeed >= ICO_SYC_APC_REGULATION_SPEED_RUNNING)
312 wkcontrol[idx].display = ICO_SYC_APC_REGULATION_NOREGULATION;
314 wkcontrol[idx].display = ICO_SYC_APC_REGULATION_REGULATION;
316 case ICO_UXF_POLICY_PARKED:
317 if (VehicleSpeed >= ICO_SYC_APC_REGULATION_SPEED_RUNNING)
318 wkcontrol[idx].display = ICO_SYC_APC_REGULATION_REGULATION;
320 wkcontrol[idx].display = ICO_SYC_APC_REGULATION_NOREGULATION;
322 case ICO_UXF_POLICY_SHIFT_PARKING:
323 if ((VehicleSpeed < ICO_SYC_APC_REGULATION_SPEED_RUNNING) &&
324 (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_PARKING))
325 wkcontrol[idx].display = ICO_SYC_APC_REGULATION_REGULATION;
327 wkcontrol[idx].display = ICO_SYC_APC_REGULATION_NOREGULATION;
329 case ICO_UXF_POLICY_SHIFT_REVERSES:
330 if (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_REVERSES)
331 wkcontrol[idx].display = ICO_SYC_APC_REGULATION_NOREGULATION;
333 wkcontrol[idx].display = ICO_SYC_APC_REGULATION_REGULATION;
335 case ICO_UXF_POLICY_BLINKER_LEFT:
336 if ((Blinker != ICO_SYC_APC_REGULATION_BLINKER_LEFT) ||
337 (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_PARKING) ||
338 (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_REVERSES))
339 wkcontrol[idx].display = ICO_SYC_APC_REGULATION_REGULATION;
341 wkcontrol[idx].display = ICO_SYC_APC_REGULATION_NOREGULATION;
343 case ICO_UXF_POLICY_BLINKER_RIGHT:
344 if ((Blinker != ICO_SYC_APC_REGULATION_BLINKER_RIGHT) ||
345 (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_PARKING) ||
346 (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_REVERSES))
347 wkcontrol[idx].display = ICO_SYC_APC_REGULATION_REGULATION;
349 wkcontrol[idx].display = ICO_SYC_APC_REGULATION_NOREGULATION;
352 apfw_trace("rule_engine_wake: category(%d) has unknown view(%d)",
353 idx, category[idx].view);
357 switch (category[idx].sound) {
358 case ICO_UXF_POLICY_ALWAYS:
359 wkcontrol[idx].sound = ICO_SYC_APC_REGULATION_NOREGULATION;
361 case ICO_UXF_POLICY_RUNNING:
362 if (VehicleSpeed >= ICO_SYC_APC_REGULATION_SPEED_RUNNING)
363 wkcontrol[idx].sound = ICO_SYC_APC_REGULATION_NOREGULATION;
365 wkcontrol[idx].sound = ICO_SYC_APC_REGULATION_REGULATION;
367 case ICO_UXF_POLICY_PARKED:
368 if (VehicleSpeed >= ICO_SYC_APC_REGULATION_SPEED_RUNNING)
369 wkcontrol[idx].sound = ICO_SYC_APC_REGULATION_REGULATION;
371 wkcontrol[idx].sound = ICO_SYC_APC_REGULATION_NOREGULATION;
373 case ICO_UXF_POLICY_SHIFT_PARKING:
374 if (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_PARKING)
375 wkcontrol[idx].sound = ICO_SYC_APC_REGULATION_NOREGULATION;
377 wkcontrol[idx].sound = ICO_SYC_APC_REGULATION_REGULATION;
379 case ICO_UXF_POLICY_SHIFT_REVERSES:
380 if (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_REVERSES)
381 wkcontrol[idx].sound = ICO_SYC_APC_REGULATION_NOREGULATION;
383 wkcontrol[idx].sound = ICO_SYC_APC_REGULATION_REGULATION;
385 case ICO_UXF_POLICY_BLINKER_LEFT:
386 if ((Blinker != ICO_SYC_APC_REGULATION_BLINKER_LEFT) ||
387 (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_PARKING) ||
388 (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_REVERSES))
389 wkcontrol[idx].sound = ICO_SYC_APC_REGULATION_REGULATION;
391 wkcontrol[idx].sound = ICO_SYC_APC_REGULATION_NOREGULATION;
393 case ICO_UXF_POLICY_BLINKER_RIGHT:
394 if ((Blinker != ICO_SYC_APC_REGULATION_BLINKER_RIGHT) ||
395 (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_PARKING) ||
396 (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_REVERSES))
397 wkcontrol[idx].sound = ICO_SYC_APC_REGULATION_REGULATION;
399 wkcontrol[idx].sound = ICO_SYC_APC_REGULATION_NOREGULATION;
402 apfw_trace("rule_engine_wake: category(%d) has unknown sound(%d)",
403 idx, category[idx].sound);
407 switch (category[idx].input) {
408 case ICO_UXF_POLICY_ALWAYS:
409 wkcontrol[idx].input = ICO_SYC_APC_REGULATION_NOREGULATION;
411 case ICO_UXF_POLICY_RUNNING:
412 if (VehicleSpeed >= ICO_SYC_APC_REGULATION_SPEED_RUNNING)
413 wkcontrol[idx].input = ICO_SYC_APC_REGULATION_NOREGULATION;
415 wkcontrol[idx].input = ICO_SYC_APC_REGULATION_REGULATION;
417 case ICO_UXF_POLICY_PARKED:
418 if (VehicleSpeed >= ICO_SYC_APC_REGULATION_SPEED_RUNNING)
419 wkcontrol[idx].input = ICO_SYC_APC_REGULATION_REGULATION;
421 wkcontrol[idx].input = ICO_SYC_APC_REGULATION_NOREGULATION;
423 case ICO_UXF_POLICY_SHIFT_PARKING:
424 if (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_PARKING)
425 wkcontrol[idx].input = ICO_SYC_APC_REGULATION_NOREGULATION;
427 wkcontrol[idx].input = ICO_SYC_APC_REGULATION_REGULATION;
429 case ICO_UXF_POLICY_SHIFT_REVERSES:
430 if (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_REVERSES)
431 wkcontrol[idx].input = ICO_SYC_APC_REGULATION_NOREGULATION;
433 wkcontrol[idx].input = ICO_SYC_APC_REGULATION_REGULATION;
435 case ICO_UXF_POLICY_BLINKER_LEFT:
436 if ((Blinker != ICO_SYC_APC_REGULATION_BLINKER_LEFT) ||
437 (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_PARKING) ||
438 (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_REVERSES))
439 wkcontrol[idx].input = ICO_SYC_APC_REGULATION_REGULATION;
441 wkcontrol[idx].input = ICO_SYC_APC_REGULATION_NOREGULATION;
443 case ICO_UXF_POLICY_BLINKER_RIGHT:
444 if ((Blinker != ICO_SYC_APC_REGULATION_BLINKER_RIGHT) ||
445 (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_PARKING) ||
446 (ShiftPosition == ICO_SYC_APC_REGULATION_SHIFT_REVERSES))
447 wkcontrol[idx].input = ICO_SYC_APC_REGULATION_REGULATION;
449 wkcontrol[idx].input = ICO_SYC_APC_REGULATION_NOREGULATION;
452 apfw_trace("rule_engine_wake: category(%d) has unknown input(%d)",
453 idx, category[idx].input);
458 for (idx = 0; idx < ncategory; idx++) {
459 if ((control[idx].display != wkcontrol[idx].display) ||
460 (control[idx].sound != wkcontrol[idx].sound) ||
461 (control[idx].input != wkcontrol[idx].input)) {
462 apfw_trace("rule_engine_wake: Category.%d view.%d>%d sound.%d>%d inp.%d>%d",
463 idx, control[idx].display, wkcontrol[idx].display,
464 control[idx].sound, wkcontrol[idx].sound,
465 control[idx].input, wkcontrol[idx].input);
468 if (control[idx].display != wkcontrol[idx].display)
469 change.display = wkcontrol[idx].display;
471 change.display = ICO_SYC_APC_REGULATION_NOCHANGE;
472 if (control[idx].sound != wkcontrol[idx].sound)
473 change.sound = wkcontrol[idx].sound;
475 change.sound = ICO_SYC_APC_REGULATION_NOCHANGE;
476 if (control[idx].input != wkcontrol[idx].input)
477 change.input = wkcontrol[idx].input;
479 change.input = ICO_SYC_APC_REGULATION_NOCHANGE;
481 (*regulation_cb)(idx, change, regulation_cb_user_data);
483 control[idx].display = wkcontrol[idx].display;
484 control[idx].sound = wkcontrol[idx].sound;
485 control[idx].input = wkcontrol[idx].input;
488 /* send request to AMB */
489 request_vehicle_info();
491 return ECORE_CALLBACK_RENEW;
494 /*--------------------------------------------------------------------------*/
496 * @brief ico_syc_apc_regulation_init: initialize regulation control
500 * @retval ICO_SYC_EOK success
501 * @retval ICO_SYC_EIO error(D-Bus initialize error)
503 /*--------------------------------------------------------------------------*/
505 ico_syc_apc_regulation_init(void)
508 DBusError dbus_error;
510 apfw_trace("ico_syc_apc_regulation_init: Enter");
512 /* get configurations */
513 confsys = (Ico_Uxf_Sys_Config *)ico_uxf_getSysConfig();
516 apfw_trace("ico_syc_apc_regulation_init: Leave(can not read configuration)");
519 ncategory = confsys->categoryNum;
520 category = confsys->category;
522 memset(vehicle_data, 0, sizeof(vehicle_data));
523 memset(control, 0, sizeof(control));
524 for (i = 0; i <ncategory; i++) {
525 control[i].display = ICO_SYC_APC_REGULATION_NOREGULATION;
526 control[i].sound = ICO_SYC_APC_REGULATION_NOREGULATION;
527 control[i].input = ICO_SYC_APC_REGULATION_NOREGULATION;
530 /* Reset D-Bus error */
531 dbus_error_init(&dbus_error);
533 /* Get D-Bus connection */
534 dbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error);
535 if (! dbus_connection){
536 apfw_warn("ico_syc_apc_regulation_init: Leave(ERROR dbus_bus_get)" );
540 /* send request to AMB */
541 request_vehicle_info();
543 vehicle_timer = ecore_timer_add(0.1, rule_engine_wake, NULL);
544 if (! vehicle_timer) {
545 apfw_error("ico_syc_apc_regulation_init: Leave(Can not create Ecore timer)");
548 apfw_trace("ico_syc_apc_regulation_init: Leave(EOK)");
553 /*--------------------------------------------------------------------------*/
555 * @brief ico_syc_apc_regulation_term: terminate regulation control
558 * @return always ICO_SYC_EOK(success)
560 /*--------------------------------------------------------------------------*/
562 ico_syc_apc_regulation_term(void)
564 apfw_trace("ico_syc_apc_regulation_term: Enter");
567 apfw_trace("ico_syc_apc_regulation_term: Leave(not initialized)");
570 ecore_timer_del(vehicle_timer);
574 apfw_trace("ico_syc_apc_regulation_term: Leave(EOK)");
578 /*--------------------------------------------------------------------------*/
580 * @brief ico_syc_apc_regulation_listener: set regulation control listener
582 * @param[in] func listener function
583 * @param[in] user_data user data
586 /*--------------------------------------------------------------------------*/
588 ico_syc_apc_regulation_listener(ico_apc_regulation_cb_t func, void *user_data)
592 regulation_cb = func;
593 regulation_cb_user_data = user_data;
596 for (idx = 0; idx < ncategory; idx++) {
597 (*regulation_cb)(idx, control[idx], regulation_cb_user_data);
602 /*--------------------------------------------------------------------------*/
604 * @brief ico_syc_apc_regulation_app_visible: get display regulation status
606 * @param[in] category category Id
608 * @retval TRUE The application of this category can use the display
609 * @retval FALSE The application of this category can not use the display
611 /*--------------------------------------------------------------------------*/
613 ico_syc_apc_regulation_app_visible(const int category)
615 if ((category < 0) || (category >= ICO_UXF_CATEGORY_MAX)) {
616 apfw_warn("ico_syc_apc_regulation_app_visible: Illegal category(%d)", category);
619 if (control[category].display == ICO_SYC_APC_REGULATION_NOREGULATION) {
625 /*--------------------------------------------------------------------------*/
627 * @brief ico_syc_apc_regulation_app_sound: get sound reguration status
629 * @param[in] category category Id
631 * @retval TRUE The application of this category can use the sound output
632 * @retval FALSE The application of this category can not use the sound output
634 /*--------------------------------------------------------------------------*/
636 ico_syc_apc_regulation_app_sound(const int category)
638 if ((category < 0) || (category >= ICO_UXF_CATEGORY_MAX)) {
639 apfw_warn("ico_syc_apc_regulation_app_sound: Illegal category(%d)", category);
642 if (control[category].sound == ICO_SYC_APC_REGULATION_NOREGULATION) {
648 /*--------------------------------------------------------------------------*/
650 * @brief ico_syc_apc_regulation_app_input: get input switch reguration status
652 * @param[in] category category Id
654 * @retval TRUE The application of this category is available with an input
655 * @retval FALSE The application of this category is not available with an input
657 /*--------------------------------------------------------------------------*/
659 ico_syc_apc_regulation_app_input(const int category)
661 if ((category < 0) || (category >= ICO_UXF_CATEGORY_MAX)) {
662 apfw_warn("ico_syc_apc_regulation_app_input: Illegal category(%d)", category);
665 if (control[category].input == ICO_SYC_APC_REGULATION_NOREGULATION) {