The Initial Haptic (drv2605l) HAL for RPI3 81/140081/11 accepted/tizen/4.0/unified/20170829.020552 accepted/tizen/unified/20170808.171436 submit/tizen/20170808.025339 submit/tizen_4.0/20170828.100004 submit/tizen_4.0/20170828.110004
authorscott park <scott.park@dignsys.com>
Sat, 22 Jul 2017 11:30:21 +0000 (20:30 +0900)
committerpr.jung <pr.jung@samsung.com>
Thu, 3 Aug 2017 06:30:40 +0000 (15:30 +0900)
Implemented using PIO (Peripheral-io)
- open_device, close_device, vibrate_monotone, stop_device

Change-Id: Ifc26d9f1397bd38f92b2dccb3916ed1316dfd9bc
Signed-off-by: scott park <scott.park@dignsys.com>
CMakeLists.txt
packaging/feedbackd.spec
src/haptic/gpio_haptic.c [new file with mode: 0755]

index 0f39f17..00813c1 100755 (executable)
@@ -19,6 +19,7 @@ SET(SRCS
        src/haptic/external.c
        src/haptic/emulator.c
        src/haptic/circle.c
+       src/haptic/gpio_haptic.c
 )
 IF(STANDARD_MIX STREQUAL on)
        SET(SRCS ${SRCS} src/haptic/standard-mix.c)
@@ -37,6 +38,7 @@ SET(PKG_MODULES
        capi-base-common
        gio-2.0
        capi-system-info
+       capi-system-peripheral-io
 )
 
 INCLUDE(FindPkgConfig)
index 32b5c45..5e4ca81 100644 (file)
@@ -24,6 +24,7 @@ BuildRequires:  pkgconfig(dbus-1)
 BuildRequires:  pkgconfig(gio-2.0)
 BuildRequires:  pkgconfig(glib-2.0)
 BuildRequires:  pkgconfig(capi-system-info)
+BuildRequires:  pkgconfig(capi-system-peripheral-io)
 
 Requires(post): /usr/bin/vconftool
 
diff --git a/src/haptic/gpio_haptic.c b/src/haptic/gpio_haptic.c
new file mode 100755 (executable)
index 0000000..a634f6c
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * feedbackd
+ *
+ * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <glib.h>
+#include <Ecore.h>
+
+#include "core/log.h"
+#include "haptic.h"
+#include "peripheral_io.h"
+#include "peripheral_internal.h"
+#include "standard-vibcore.h"
+
+#define GPIO_I2C_BUS_INDEX             1
+#define MAX_HAPIC                              1
+#define DRV2605L_DEFAULT_ADDR  0x5A
+
+#define START_CMD_CODE 1
+#define STOP_CMD_CODE  0
+
+#define DRV2605L_REGISTER_STATUS       0x00
+#define DRV2605L_REGISTER_MODE         0x01
+#define DRV2605L_REGISTER_RTPINPUT     0x02
+#define DRV2605L_REGISTER_LIBRARY      0x03
+#define DRV2605L_REGISTER_WAVESEQ1     0x04
+#define DRV2605L_REGISTER_WAVESEQ2     0x05
+#define DRV2605L_REGISTER_WAVESEQ3     0x06
+#define DRV2605L_REGISTER_WAVESEQ4     0x07
+#define DRV2605L_REGISTER_WAVESEQ5     0x08
+#define DRV2605L_REGISTER_WAVESEQ6     0x09
+#define DRV2605L_REGISTER_WAVESEQ7     0x0A
+#define DRV2605L_REGISTER_WAVESEQ8     0x0B
+#define DRV2605L_REGISTER_GO           0x0C
+
+/**
+ * Mode register
+ */
+#define MODE_INTERNAL_TRIGGER          0
+#define MODE_EXTERNAL_TRIGGER_EDGE     1
+#define MODE_EXTERNAL_TRIGGER_LEVEL    2
+#define MODE_PWM_INPUT_ANALOG_INPUT    3
+#define MODE_AUDIO_TO_VIBE                     4
+#define MODE_REALTIME_PLAYBACK         5
+#define MODE_DIAGNOSTICS                       6
+#define MODE_AUTO_CALIBRATION          7
+/**
+ * Library register
+ */
+#define EMPTY_LIBRARY          0
+#define TS2200_LIBRARY_A       1
+#define TS2200_LIBRARY_B       2
+#define TS2200_LIBRARY_C       3
+#define TS2200_LIBRARY_D       4
+#define TS2200_LIBRARY_E       5
+#define LRA_LIBRARY_E          6
+#define TS2200_LIBRARY_F       7
+
+static peripheral_i2c_h device_handle = NULL;
+
+static dd_list *handle_list;
+static int unique_number;
+
+static bool state = false;
+//static bool is_playing = false;
+static Ecore_Timer *stop_timer = NULL;
+
+static int gpio_haptic_stop_device(int handle);
+
+static bool find_from_list(int handle)
+{
+       dd_list *elem;
+
+       elem = DD_LIST_FIND(handle_list, (gpointer)(long)handle);
+       if (elem)
+               return true;
+
+       return false;
+}
+
+/* START: Haptic Module APIs */
+static Eina_Bool gpio_haptic_timer_cb(void *data)
+{
+       int handle = (int)(long)data;
+       bool found;
+
+       _I("stop vibration by timer");
+
+       found = find_from_list(handle);
+       if (!found)
+               return ECORE_CALLBACK_CANCEL;
+
+       if (device_handle == NULL) {
+               if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &device_handle) < PERIPHERAL_ERROR_NONE) {
+                       _E("Failed to open I2C");
+                       return -EIO;
+               }
+       }
+
+       /*  stop playing */
+       peripheral_i2c_write_register_byte(device_handle, DRV2605L_REGISTER_MODE, MODE_INTERNAL_TRIGGER);
+
+       stop_timer = NULL;
+       return ECORE_CALLBACK_CANCEL;
+}
+
+static int gpio_haptic_get_device_count(int *count)
+{
+       _I("HAL: The max number of DRV2605L is %d", (int)MAX_HAPIC);
+       if (count)
+               *count = MAX_HAPIC;
+
+       return 0;
+}
+
+/**
+ * Only one handle
+ * return  device_handle
+ */
+static int gpio_haptic_open_device(int device_index, int *handle)
+{
+       int n;
+       bool found = false;
+       dd_list *elem;
+
+       if (!handle)
+               return -EINVAL;
+
+       /* if it is the first element */
+       n = DD_LIST_LENGTH(handle_list);
+       if (n == 0) {
+               _I("Peripheral Device Open");
+               if (device_handle == NULL) {
+                       if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &device_handle) < PERIPHERAL_ERROR_NONE) {
+                               _E("Failed to open I2C");
+                               return -EIO;
+                       }
+               }
+       }
+
+       if (unique_number == INT_MAX)
+               unique_number = 0;
+
+       while (found != true) {
+               ++unique_number;
+               elem = DD_LIST_FIND(handle_list, (gpointer)(long)unique_number);
+               if (!elem)
+                       found = true;
+       }
+
+       /* add info to local list */
+       DD_LIST_APPEND(handle_list, (gpointer)(long)unique_number);
+
+       *handle = unique_number;
+       return 0;
+}
+
+static int gpio_haptic_close_device(int handle)
+{
+       int r, n;
+       bool found;
+
+       found = find_from_list(handle);
+       if (!found)
+               return -EINVAL;
+
+       if (device_handle == NULL) {
+               if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &device_handle) < PERIPHERAL_ERROR_NONE) {
+                       _E("Failed to open I2C");
+                       return -EIO;
+               }
+       }
+
+       /* stop vibration */
+       r = gpio_haptic_stop_device(handle);
+       if (r < 0)
+               _I("already stopped or failed to stop effect : %d", r);
+
+       /* unregister existing timer */
+       if (r >= 0) {
+               if (stop_timer) {
+                       ecore_timer_del(stop_timer);
+                       stop_timer = NULL;
+               }
+       }
+
+       standard_vibrate_close();
+
+       _D("handle %d is closed and timer deleted", handle);
+       DD_LIST_REMOVE(handle_list, (gpointer)(long)handle);
+
+       /* if it is the last element */
+       n = DD_LIST_LENGTH(handle_list);
+       if (n == 0) {
+               _I("Peripheral Device Close");
+               if (device_handle != NULL) {
+                       if (peripheral_i2c_close(device_handle) < PERIPHERAL_ERROR_NONE) {
+                               _E("Failed to close peripheral I2C");
+                               return -EIO;
+                       }
+                       device_handle = NULL;
+               }
+       }
+       return 0;
+}
+
+static int gpio_haptic_vibrate_monotone(int handle, int duration, int level, int priority, int *e_handle)
+{
+       bool found;
+
+       found = find_from_list(handle);
+       if (!found)
+               return -EINVAL;
+
+       if (device_handle == NULL) {
+               if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &device_handle) < PERIPHERAL_ERROR_NONE) {
+                       _E("Failed to open I2C");
+                       return -EIO;
+               }
+       }
+
+       /* Zero(0) is the infinitely vibration value */
+       if (duration == HAPTIC_MODULE_DURATION_UNLIMITED)
+               duration = 0;
+
+       if (stop_timer)
+               gpio_haptic_stop_device(handle);
+
+       /* play vibration */
+       peripheral_i2c_write_register_byte(device_handle, DRV2605L_REGISTER_LIBRARY, TS2200_LIBRARY_A);
+       /* continuously vibrate*/
+       peripheral_i2c_write_register_byte(device_handle, DRV2605L_REGISTER_MODE, MODE_REALTIME_PLAYBACK);
+       peripheral_i2c_write_register_byte(device_handle, DRV2605L_REGISTER_RTPINPUT, (uint8_t)level);
+
+       /* register timer */
+       if (duration) {
+         stop_timer = ecore_timer_add(duration/1000.f, gpio_haptic_timer_cb, (void *)(long)handle);
+               if (!stop_timer)
+                       _E("Failed to add timer callback");
+       }
+       _D("device handle %d %dms", handle, duration);
+
+       if (e_handle)
+               *e_handle = handle;
+
+       return 0;
+}
+
+static int gpio_haptic_stop_device(int handle)
+{
+       bool found;
+
+       found = find_from_list(handle);
+       if (!found)
+               return -EINVAL;
+
+       if (cur_h_data.handle > 0 && cur_h_data.handle != handle) {
+               _E("Only same handle can stop current vibration");
+               return -EPERM;
+       }
+
+       /* Remove duration_timer for vibrate_effect */
+       standard_vibrate_close();
+
+       if (device_handle == NULL) {
+               if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &device_handle) < PERIPHERAL_ERROR_NONE) {
+                       _E("Failed to open I2C");
+                       return -EIO;
+               }
+       }
+
+       /*  stop playing */
+       peripheral_i2c_write_register_byte(device_handle, DRV2605L_REGISTER_MODE, MODE_INTERNAL_TRIGGER);
+
+       if (stop_timer) {
+               ecore_timer_del(stop_timer);
+               stop_timer = NULL;
+       }
+
+       return 0;
+}
+
+static int gpio_haptic_get_device_state(int index, int *effect_state)
+{
+       if (!effect_state)
+               return -EINVAL;
+
+       *effect_state = state;
+       return 0;
+}
+
+static int gpio_haptic_vibrate_buffer(int handle, const unsigned char *vibe_buffer, int iteration, int feedback, int priority, int *effect_handle)
+{
+       _E("Not support feature");
+       return -EACCES;
+}
+
+static int gpio_haptic_create_effect(unsigned char *vibe_buffer, int max_bufsize, haptic_module_effect_element *elem_arr, int max_elemcnt)
+{
+       _E("Not support feature");
+       return -EACCES;
+}
+
+static int gpio_haptic_get_buffer_duration(int handle, const unsigned char *vibe_buffer, int *buffer_duration)
+{
+       _E("Not support feature");
+       return -EACCES;
+}
+
+static int gpio_haptic_convert_binary(const unsigned char *vibe_buffer, int max_bufsize, const char *file_path)
+{
+       _E("Not support feature");
+       return -EACCES;
+}
+/* END: Haptic Module APIs */
+
+static const struct haptic_plugin_ops default_plugin = {
+       .get_device_count               = gpio_haptic_get_device_count,
+       .open_device                    = gpio_haptic_open_device,
+       .close_device                   = gpio_haptic_close_device,
+       .vibrate_monotone               = gpio_haptic_vibrate_monotone,
+       .vibrate_buffer                 = gpio_haptic_vibrate_buffer,
+       .vibrate_effect                 = standard_vibrate_effect,
+       .is_supported                   = standard_is_supported,
+       .stop_device                    = gpio_haptic_stop_device,
+       .get_device_state               = gpio_haptic_get_device_state,
+       .create_effect                  = gpio_haptic_create_effect,
+       .get_buffer_duration            = gpio_haptic_get_buffer_duration,
+       .convert_binary                 = gpio_haptic_convert_binary,
+};
+
+static bool is_valid(void)
+{
+       uint8_t result;
+       peripheral_i2c_h handle;
+       int ret;
+
+       if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &handle) < PERIPHERAL_ERROR_NONE) {
+               _E("Failed to open I2C");
+               state = false;
+               return false;
+       }
+       if(peripheral_i2c_read_register_byte(handle, DRV2605L_REGISTER_STATUS, &result) < PERIPHERAL_ERROR_NONE) {
+               _E("Failed to read peripheral I2C");
+               if (peripheral_i2c_close(handle) < PERIPHERAL_ERROR_NONE)
+                       _E("Failed to close peripheral I2C");
+               state = false;
+               return false;
+       }
+       if (peripheral_i2c_close(handle) < PERIPHERAL_ERROR_NONE) {
+               _E("Failed to close peripheral I2C");
+               state = false;
+               return false;
+       }
+
+       ret = standard_config_parse();
+       if (ret < 0)
+               _E("failed to load standard vibration configuration file : %d", ret);
+
+       state = true;
+       _I("Support gpio haptic device");
+       return true;
+}
+
+static const struct haptic_plugin_ops *load(void)
+{
+       _I("gpio haptic device module loaded");
+       standard_set_vib_function(&gpio_haptic_vibrate_monotone);
+       return &default_plugin;
+}
+
+static const struct haptic_ops gpio_haptic_ops = {
+       .is_valid = is_valid,
+       .load    = load,
+};
+
+HAPTIC_OPS_REGISTER(&gpio_haptic_ops)