haptic: apply next HAL architecture (hal api + backend) 24/251424/1
authorYunmi Ha <yunmi.ha@samsung.com>
Wed, 13 Jan 2021 12:14:04 +0000 (21:14 +0900)
committerYunmi Ha <yunmi.ha@samsung.com>
Wed, 13 Jan 2021 12:14:04 +0000 (21:14 +0900)
Change-Id: I2fdf1c8a5c244d40836df1962c82cf467dd7dc83
Signed-off-by: Yunmi Ha <yunmi.ha@samsung.com>
CMakeLists.txt
hw/haptic/CMakeLists.txt [new file with mode: 0644]
hw/haptic/gpio.c [new file with mode: 0644]
packaging/device-manager-plugin-rpi3.spec

index 5a00adc..1b5e0d2 100644 (file)
@@ -12,3 +12,4 @@ ADD_SUBDIRECTORY(hw/touchscreen)
 ADD_SUBDIRECTORY(hw/thermal)
 ADD_SUBDIRECTORY(hw/usb_cfs_client)
 ADD_SUBDIRECTORY(hw/usb_gadget)
+ADD_SUBDIRECTORY(hw/haptic)
diff --git a/hw/haptic/CMakeLists.txt b/hw/haptic/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f8fac63
--- /dev/null
@@ -0,0 +1,25 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(hal-backend-device-haptic C)
+
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+
+INCLUDE_DIRECTORIES(../common)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(haptic_pkgs REQUIRED
+               dlog
+               glib-2.0
+               libsyscommon
+               capi-system-peripheral-io)
+
+FOREACH(flag ${haptic_pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+
+ADD_LIBRARY(${PROJECT_NAME} MODULE gpio.c)
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${haptic_pkgs_LDFLAGS})
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /hal/lib COMPONENT RuntimeLibraries)
diff --git a/hw/haptic/gpio.c b/hw/haptic/gpio.c
new file mode 100644 (file)
index 0000000..20123fc
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * 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 <peripheral_io.h>
+#include <libsyscommon/list.h>
+#include <hal/device/hal-haptic-interface.h>
+
+#include "common.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
+
+#define MAX_LEVEL              2
+#define MAX_INTENSITY  10000
+
+static peripheral_i2c_h device_handle = NULL;
+
+static GList *handle_list;
+static int unique_number;
+
+static bool state = false;
+static guint stop_timer = 0;
+
+static int gpio_haptic_stop_device(int handle);
+
+static bool find_from_list(int handle)
+{
+       GList *elem;
+
+       elem = SYS_G_LIST_FIND(handle_list, (gpointer)(long)handle);
+       if (elem)
+               return true;
+
+       return false;
+}
+
+static gboolean 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 G_SOURCE_REMOVE;
+
+       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 = 0;
+       return G_SOURCE_REMOVE;
+}
+
+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 *handle)
+{
+       int n;
+       bool found = false;
+       GList *elem;
+
+       if (!handle)
+               return -EINVAL;
+
+       /* if it is the first element */
+       n = SYS_G_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 = SYS_G_LIST_FIND(handle_list, (gpointer)(long)unique_number);
+               if (!elem)
+                       found = true;
+       }
+
+       /* add info to local list */
+       SYS_G_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);
+
+       _D("Handle(%d) is closed and timer deleted.", handle);
+       SYS_G_LIST_REMOVE(handle_list, (gpointer)(long)handle);
+
+       /* if it is the last element */
+       n = SYS_G_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 frequency, int overdrive, int level, int intensity, int priority)
+{
+       bool found;
+       int feedback;
+       int max_level;
+
+       if (level <= 0)
+               return -EINVAL;
+
+       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);
+
+       max_level = (level <= MAX_LEVEL)? MAX_LEVEL: level;
+       if (intensity)
+               feedback = ((level/max_level) * intensity) / 100;
+       else
+               feedback = ((level/max_level) * MAX_INTENSITY) / 100;
+
+       /* 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)feedback);
+
+       /* register timer */
+       if (duration) {
+         //stop_timer = ecore_timer_add(duration/1000.f, gpio_haptic_timer_cb, (void *)(long)handle);
+         stop_timer = g_timeout_add(duration, gpio_haptic_timer_cb, (void *)(long)handle);
+               if (!stop_timer)
+                       _E("Failed to add timer callback.");
+       }
+       _D("Device handle(%d) %dms", handle, duration);
+
+       return 0;
+}
+
+static int gpio_haptic_stop_device(int 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;
+               }
+       }
+
+       /*  stop playing */
+       peripheral_i2c_write_register_byte(device_handle, DRV2605L_REGISTER_MODE, MODE_INTERNAL_TRIGGER);
+
+       if (stop_timer) {
+               //ecore_timer_del(stop_timer);
+               g_source_remove(stop_timer);
+               stop_timer = 0;
+       }
+
+       return 0;
+}
+
+static bool is_valid(void)
+{
+       uint8_t result;
+       peripheral_i2c_h handle;
+
+       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;
+       }
+
+       state = true;
+       _I("Support gpio haptic device.");
+       return true;
+}
+
+static int haptic_init(void **data)
+{
+    hal_backend_haptic_funcs *haptic_funcs;
+
+    haptic_funcs = calloc(1, sizeof(hal_backend_haptic_funcs));
+    if (!haptic_funcs)
+        return -ENOMEM;
+
+    haptic_funcs->get_device_count = gpio_haptic_get_device_count;
+    haptic_funcs->open_device = gpio_haptic_open_device;
+    haptic_funcs->close_device = gpio_haptic_close_device;
+    haptic_funcs->vibrate_monotone = gpio_haptic_vibrate_monotone;
+    haptic_funcs->stop_device = gpio_haptic_stop_device;
+    haptic_funcs->is_valid = is_valid;
+
+    *data = (void *)haptic_funcs;
+
+    return 0;
+}
+
+static int haptic_exit(void *data)
+{
+    if (!data)
+        return -EINVAL;
+
+    free(data);
+    return 0;
+}
+
+
+hal_backend EXPORT hal_backend_device_haptic_data = {
+       .name = "haptic",
+       .vendor = "RPI",
+       .abi_version = HAL_ABI_VERSION_TIZEN_6_5,
+       .init = haptic_init,
+       .exit = haptic_exit,
+};
index 90d6f62..d56fa12 100644 (file)
@@ -16,6 +16,7 @@ BuildRequires:  pkgconfig(libudev)
 BuildRequires:  pkgconfig(capi-system-peripheral-io)
 BuildRequires:  pkgconfig(hal-api-common)
 BuildRequires:  pkgconfig(hal-api-device)
+BuildRequires:  pkgconfig(libsyscommon)
 
 %description
 Device manager plugin Raspberry Pi 3