diff options
-rw-r--r-- | AUTHORS | 2 | ||||
-rwxr-xr-x | CMakeLists.txt | 26 | ||||
-rw-r--r-- | LICENSE.APLv2 | 202 | ||||
-rw-r--r-- | NOTICE | 7 | ||||
-rwxr-xr-x | include/haptic_module_log.h | 34 | ||||
-rw-r--r-- | packaging/haptic-module-tizen.spec | 46 | ||||
-rw-r--r-- | test/test.c | 117 | ||||
-rw-r--r-- | tizen/DEVICE/CMakeLists.txt | 30 | ||||
-rw-r--r-- | tizen/DEVICE/include/file.h | 75 | ||||
-rw-r--r-- | tizen/DEVICE/src/file.c | 460 | ||||
-rw-r--r-- | tizen/DEVICE/src/haptic.c | 622 | ||||
-rw-r--r-- | tizen/DEVICE/src/sysnoti.c | 163 | ||||
-rw-r--r-- | tizen/SIMULATOR/CMakeLists.txt | 27 | ||||
-rw-r--r-- | tizen/SIMULATOR/src/haptic.c | 312 |
14 files changed, 2123 insertions, 0 deletions
@@ -0,0 +1,2 @@ +Jiyoung Yun <jy910.yun at samsung dot com> +Jae-young Hwang <j-zero.hwang at samsung dot com> diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..bc6d74a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,26 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(haptic-module C) + +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) +SET(EXEC_PREFIX "\${prefix}") +SET(LIBDIR ${LIB_INSTALL_DIR}) +SET(INCLUDEDIR "\${prefix}/include/${PROJECT_NAME}") + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) + +FIND_PROGRAM(UNAME NAMES uname) +EXEC_PROGRAM("${UNAME}" ARGS "-m" OUTPUT_VARIABLE "ARCH") + +MESSAGE ("architecture name : ${ARCH}") +MESSAGE ("SIMULATOR: ${SIMULATOR}") +IF("${SIMULATOR}" MATCHES "yes") + SET(TIZEN_TARGET "SIMULATOR") +ELSEIF("${ARCH}" MATCHES "^arm.*") + SET(TIZEN_TARGET "DEVICE") +ELSEIF("${ARCH}" MATCHES ".*86.*") + SET(TIZEN_TARGET "DEVICE") +ELSE("${SIMULATOR}" MATCHES "yes") + MESSAGE(SEND_ERROR "Unknown architecture: ${ARCH}") +ENDIF("${SIMULATOR}" MATCHES "yes") + +ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/tizen/${TIZEN_TARGET}) diff --git a/LICENSE.APLv2 b/LICENSE.APLv2 new file mode 100644 index 0000000..c7f3cb1 --- /dev/null +++ b/LICENSE.APLv2 @@ -0,0 +1,202 @@ + License APLv2 + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + @@ -0,0 +1,7 @@ +Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Apache License, Version 2. +Please, see the LICENSE.APLv2 file for Apache License, Version 2 terms and conditions. + +IP Rights Notice: The feature implemented by this module may be intellectual property(ies) of +other entities. Tizen device manufacturers may be required to pay royalty to such entities to +enable the features on their devices diff --git a/include/haptic_module_log.h b/include/haptic_module_log.h new file mode 100755 index 0000000..87b27e5 --- /dev/null +++ b/include/haptic_module_log.h @@ -0,0 +1,34 @@ +/* + * haptic-module-tizen + * Copyright (c) 2012 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. + */ + + +#ifndef __HAPTIC_MODULE_LOG_H__ +#define __HAPTIC_MODULE_LOG_H__ + +#define FEATURE_HAPTIC_MODULE_DLOG + +#ifdef FEATURE_HAPTIC_MODULE_DLOG + #define LOG_TAG "HAPTIC_MODULE" + #include <dlog.h> + #define MODULE_LOG(fmt, args...) SLOGD(fmt, ##args) + #define MODULE_ERROR(fmt, args...) SLOGE(fmt, ##args) +#else + #define MODULE_LOG(x, ...) + #define MODULE_ERROR(x, ...) +#endif + +#endif //__HAPTIC_MODULE_LOG_H__ diff --git a/packaging/haptic-module-tizen.spec b/packaging/haptic-module-tizen.spec new file mode 100644 index 0000000..db4d6bc --- /dev/null +++ b/packaging/haptic-module-tizen.spec @@ -0,0 +1,46 @@ +#sbs-git:slp/pkgs/d/devman devman 0.1.6 5bf2e95e0bb15c43ff928f7375e1978b0accb0f8 +Name: haptic-module-tizen +Summary: Haptic Module library +Version: 0.1.0 +Release: 9 +Group: System/Libraries +License: APLv2 +Source0: %{name}-%{version}.tar.gz +BuildRequires: cmake +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(vconf) +BuildRequires: pkgconfig(haptic-plugin) +BuildRequires: pkgconfig(device-node) + +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description + +%prep +%setup -q + +%build +%if 0%{?simulator} +%cmake . -DSIMULATOR=yes +%else +%ifarch %{ix86} +CFLAGS=`echo %{optflags} |sed 's/\-fexceptions//g'` +%endif +%cmake . -DSIMULATOR=no +%endif +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +%make_install +mkdir -p %{buildroot}%{_datadir}/license +cp LICENSE.APLv2 %{buildroot}%{_datadir}/license/%{name} + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files +%{_libdir}/libhaptic-module.so +%{_datadir}/license/%{name} diff --git a/test/test.c b/test/test.c new file mode 100644 index 0000000..b8cb94e --- /dev/null +++ b/test/test.c @@ -0,0 +1,117 @@ +/* + * haptic-module-tizen + * Copyright (c) 2012 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <vconf.h> +#include <dlfcn.h> + +#include <haptic_plugin_intf.h> + +#define HAPTIC_MODULE_PATH "/usr/lib/libhaptic-module.so" + +static void *dlopen_handle; +static const haptic_plugin_interface *plugin_intf; + +int main () +{ + char *error = NULL; + + printf("start!\n"); + dlopen_handle = dlopen(HAPTIC_MODULE_PATH, RTLD_NOW); + if (!dlopen_handle) { + printf("fail dlopen\n"); + printf("%s\n", dlerror()); + return -1; + } + + const haptic_plugin_interface *(*get_haptic_plugin_interface) (); + get_haptic_plugin_interface = dlsym(dlopen_handle, "get_haptic_plugin_interface"); + + if ((error = dlerror()) != NULL) { + printf("dlsym error\n"); + printf("%s\n", error); + dlclose(dlopen_handle); + return -1; + } + + plugin_intf = get_haptic_plugin_interface(); + if (!plugin_intf) { + printf("plugin_intf error\n"); + dlclose(dlopen_handle); + return -1; + } + + while (1) + { + char input = -1; + int duration = -1; + int handle = -1; + int status = -1; + + printf ("============================================\n"); + printf ("haptic_internal_vibrate_monotone : a\n"); + printf ("hatpic_internal_stop_all_effects : b\n"); + printf ("Quit : z\n"); + printf ("============================================\n"); + + status = scanf ("%c", &input); + + switch (input) + { + case 'a' : + printf ("Handle : "); + status = scanf ("%d", &handle); + if (status < 0) + return status; + + printf ("Duration : "); + status = scanf ("%d", &duration); + if (status < 0) + return status; + + plugin_intf->haptic_internal_vibrate_monotone(handle, duration, HAPTIC_MODULE_FEEDBACK_MAX, HAPTIC_MODULE_PRIORITY_HIGH, &handle); + break; + + case 'b': + printf ("Handle : "); + status = scanf ("%d", &handle); + if (status < 0) + return status; + plugin_intf->haptic_internal_stop_all_effects(handle); + break; + + case 'c': + break; + + case 'z': + return 0; + } + } + + if (dlopen_handle) { + dlclose(dlopen_handle); + } + + return 0; +} diff --git a/tizen/DEVICE/CMakeLists.txt b/tizen/DEVICE/CMakeLists.txt new file mode 100644 index 0000000..8d68793 --- /dev/null +++ b/tizen/DEVICE/CMakeLists.txt @@ -0,0 +1,30 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +SET(SRCS + src/haptic.c + src/file.c + src/sysnoti.c) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) + +SET(DEPENDENTS "dlog vconf haptic-plugin device-node") + +INCLUDE(FindPkgConfig) +pkg_check_modules(rpkgs REQUIRED ${DEPENDENTS}) + +FOREACH(flag ${rpkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -g -fno-omit-frame-pointer") +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,--no-as-needed") + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"") +ADD_DEFINITIONS("-DENABLE_DLOG_OUT -DSLP_DEBUG") + +ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${rpkgs_LDFLAGS}) +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/tizen/DEVICE/include/file.h b/tizen/DEVICE/include/file.h new file mode 100644 index 0000000..798ad5d --- /dev/null +++ b/tizen/DEVICE/include/file.h @@ -0,0 +1,75 @@ +/* + * haptic-module-tizen + * Copyright (c) 2012 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. + */ + + +#ifndef __FILE_H__ +#define __FILE_H__ + +#define GCC_PACK __attribute__((packed)) + +/* little-endian form */ +#define mmioHeaderID(ch0,ch1,ch2,ch3) \ + ((unsigned int)(unsigned char)(ch0) | ((unsigned int)(unsigned char)(ch1) << 8) | \ + ((unsigned int)(unsigned char)(ch2) << 16) | ((unsigned int)(unsigned char)(ch3) << 24)) + +#define HEADER_ID mmioHeaderID('T','H','F','M') // 0x4D464854 +#define FMT_ID mmioHeaderID('f','m','t',' ') // 0x20746D66 +#define DATA_ID mmioHeaderID('d','a','t','a') // 0x61746164 + +typedef unsigned int ID; /* a four character code */ + +typedef struct _FormatChunk { + ID chunkID; /* chunk ID */ + int chunkSize; /* chunk Size */ + unsigned short wChannels; /* number of channels (Mono = 1, Stereo = 2, etc.) */ + unsigned short wBlockAlign; /* block size of data (wChannels*1byte) */ + unsigned int dwMagnitude; /* max magnitude */ + unsigned int dwDuration; /* duration */ +} GCC_PACK FormatChunk; + +typedef struct _DataChunk { + ID chunkID; + int chunkSize; + unsigned char pData[]; +} GCC_PACK DataChunk; + +typedef struct _HapticFile { + ID chunkID; /* chunk ID */ + int chunkSize; /* chunk Size */ + FormatChunk fmt; /* Format chunk */ + DataChunk data; /* Data chunk */ +} GCC_PACK HapticFile; + +typedef struct _HapticElement { + int duration; + int level; +} HapticElement; + +int GetHapticLevelMax(int *max); + +int InitializeBuffer(unsigned char *vibe_buffer, int max_bufsize); +int InsertElement(unsigned char *vibe_buffer, int max_bufsize, HapticElement *element); +int GetBufferSize(const unsigned char *vibe_buffer, int *size); +int GetBufferDuration(const unsigned char *vibe_buffer, int *duration); +int PlayOneshot(int handle, int duration, int level); +int PlayBuffer(int handle, const unsigned char *vibe_buffer, int iteration, int level); +int Stop(int handle); +int OpenDevice(int handle); +int CloseDevice(int handle); +int GetState(int handle, int *state); + +#endif // __FIEL_H__ diff --git a/tizen/DEVICE/src/file.c b/tizen/DEVICE/src/file.c new file mode 100644 index 0000000..1a6ae80 --- /dev/null +++ b/tizen/DEVICE/src/file.c @@ -0,0 +1,460 @@ +/* + * haptic-module-tizen + * Copyright (c) 2012 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <pthread.h> +#include <device-node.h> + +#include "file.h" +#include "haptic_module_log.h" + +#define BITPERMS 50 +#define MAX_LEVEL 255.0f +#define DEFAULT_EFFECT_HANDLE 0x02 + +#define STATE_PLAY 0 +#define STATE_STOP 1 + +#define PREDEF_HAPTIC "haptic" + +enum { + OPEN = 0, + CLOSE, + PLAY, + ONESHOT, + STOP, + LEVEL, +}; + +typedef struct { + int handle; + unsigned char **ppbuffer; + int channels; + int length; + int iteration; +} BUFFER; + +static pthread_t tid; +static BUFFER gbuffer; +static int stop; +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +static int _check_valid_haptic_format(HapticFile *file) +{ + if (file->chunkID != HEADER_ID) + return -1; + + if (file->fmt.chunkID != FMT_ID) + return -1; + + if (file->data.chunkID != DATA_ID) + return -1; + + return 0; +} + +static int __haptic_predefine_action(int handle, int prop, int val) +{ + char buf_pid[32]; + char buf_prop[32]; + char buf_handle[32]; + char buf_val[32]; + + snprintf(buf_pid, sizeof(buf_pid), "%d", getpid()); + snprintf(buf_prop, sizeof(buf_prop), "%d", prop); + snprintf(buf_handle, sizeof(buf_handle), "%d", handle); + snprintf(buf_val, sizeof(buf_val), "%d", val); + + MODULE_LOG("pid : %s(%d), prop : %s, handle : %s", buf_pid, pthread_self(), buf_prop, buf_handle); + return __haptic_call_predef_action(PREDEF_HAPTIC, 4, buf_pid, buf_prop, buf_handle, buf_val); +} + +static int _create_thread(void* data, void*(*func)(void*)) +{ + if (tid) { + MODULE_ERROR("pthread already created"); + return -1; + } + + if (pthread_create(&tid, NULL, func, data) != 0) { + MODULE_ERROR("pthread_create is failed : %s", strerror(errno)); + return -1; + } + + return 0; +} + +static int _cancel_thread(void) +{ + int *ptr; + int ret; + + if (!tid) { + MODULE_LOG("pthread not initialized"); + return 0; + } + + MODULE_LOG("cancel thread!!!"); + + stop = 1; + + while (pthread_mutex_trylock(&mutex) == EBUSY) { + usleep(100); + MODULE_LOG("Already locked.."); + } + + pthread_mutex_unlock(&mutex); + + if ((ret = pthread_cancel(tid)) < 0) { + MODULE_ERROR("pthread_cancel is failed : %s, ret(%d)", strerror(errno), ret); + return -1; + } + + if (pthread_join(tid, (void**)&ptr) < 0) { + MODULE_ERROR("pthread_join is failed : %s", strerror(errno)); + return -1; + } + + stop = 0; + + tid = 0; + if (ptr == PTHREAD_CANCELED) { + MODULE_LOG("pthread canceled"); + } else { + MODULE_LOG("pthread already finished"); + } + + return 0; +} + +static void __clean_up(void *arg) +{ + BUFFER *pbuffer = (BUFFER*)arg; + int i; + + MODULE_LOG("clean up handler!!! : %d", tid); + + for (i = 0; i < pbuffer->channels; ++i) { + free(pbuffer->ppbuffer[i]); + pbuffer->ppbuffer[i] = NULL; + } + + free(pbuffer->ppbuffer); + pbuffer->ppbuffer = NULL; + + pbuffer->channels = 0; + pbuffer->length = 0; + + if(stop){ + __haptic_predefine_action(gbuffer.handle, STOP, NULL); + pthread_mutex_unlock(&mutex); + } +} + +static void* __play_cb(void *arg) +{ + BUFFER *pbuffer = (BUFFER*)arg; + int i, j, k; + unsigned char ch; + unsigned char prev = -1; + + MODULE_LOG("Start thread"); + + pthread_cleanup_push(__clean_up, arg); + + /* Copy buffer from source buffer */ + for (i = 0; i < pbuffer->iteration; i++) { + for (j = 0; j < pbuffer->length; ++j) { + for (k = 0; k < pbuffer->channels; ++k) { + pthread_mutex_lock(&mutex); + if (stop) { + pthread_exit((void*)0); + } + ch = pbuffer->ppbuffer[k][j]; + if (ch != prev) { + __haptic_predefine_action(pbuffer->handle, LEVEL, ch); + prev = ch; + } + pthread_mutex_unlock(&mutex); + usleep(BITPERMS * 1000); + } + } + } + + pthread_mutex_lock(&mutex); + __haptic_predefine_action(gbuffer.handle, STOP, NULL); + pthread_mutex_unlock(&mutex); + + pthread_cleanup_pop(1); + pthread_exit((void *)0); +} + +int GetHapticLevelMax(int *max) +{ + int status; + status = device_get_property(DEVICE_TYPE_VIBRATOR, PROP_VIBRATOR_LEVEL_MAX, max); + if (status < 0) { + MODULE_ERROR("device_get_property fail : %d", status); + return -1; + } + return 0; +} + +int InitializeBuffer(unsigned char *vibe_buffer, int max_bufsize) +{ + HapticFile *pfile; + + if (max_bufsize < sizeof(HapticFile)) { + MODULE_ERROR("buffer lacks a memory : size(%d) minimum size(%d)", + max_bufsize, sizeof(HapticFile)); + return -1; + } + + memset(vibe_buffer, 0, sizeof(char)*max_bufsize); + + pfile = (HapticFile*)vibe_buffer; + + pfile->chunkID = HEADER_ID; + pfile->chunkSize = sizeof(HapticFile); + pfile->fmt.chunkID = FMT_ID; + pfile->fmt.chunkSize = sizeof(FormatChunk); + pfile->fmt.wChannels = 1; + pfile->fmt.wBlockAlign = 1; // wChannels*1byte + pfile->fmt.dwMagnitude = 99; + pfile->fmt.dwDuration = 0; + pfile->data.chunkID = DATA_ID; + pfile->data.chunkSize = sizeof(DataChunk); + return 0; +} + +int InsertElement(unsigned char *vibe_buffer, int max_bufsize, HapticElement *element) +{ + HapticFile *pfile; + int databuf; + int needbuf; + int duration; + unsigned char level; + int i; + + pfile = (HapticFile*)vibe_buffer; + if (_check_valid_haptic_format(pfile) < 0) { + MODULE_ERROR("this buffer is not HapticFormat"); + return -1; + } + + duration = element->duration/BITPERMS; + level = (unsigned char)((unsigned int)element->level*MAX_LEVEL/100); + + databuf = max_bufsize - sizeof(HapticFile); + needbuf = (pfile->fmt.dwDuration + duration)*pfile->fmt.wBlockAlign; + MODULE_LOG("Need buffer size : %d", needbuf); + + if (databuf < needbuf) { + MODULE_ERROR("buffer lacks a memory : data buf(%d), need buf(%d)", databuf, needbuf); + return -1; + } + + for (i = pfile->fmt.dwDuration; i < pfile->fmt.dwDuration+duration; i++) { + pfile->data.pData[i] = level; + } + + pfile->chunkSize = sizeof(HapticFile)+needbuf ; + pfile->fmt.dwDuration = pfile->fmt.dwDuration+duration; + pfile->data.chunkSize = sizeof(DataChunk)+needbuf; + return 0; +} + +int GetBufferSize(const unsigned char *vibe_buffer, int *size) +{ + HapticFile *pfile; + + pfile = (HapticFile*)vibe_buffer; + if (_check_valid_haptic_format(pfile) < 0) { + MODULE_ERROR("this buffer is not HapticFormat"); + return -1; + } + + *size = pfile->chunkSize; + return 0; +} + +int GetBufferDuration(const unsigned char *vibe_buffer, int *duration) +{ + HapticFile *pfile; + + pfile = (HapticFile*)vibe_buffer; + if (_check_valid_haptic_format(pfile) < 0) { + MODULE_ERROR("this buffer is not HapticFormat"); + return -1; + } + + *duration = pfile->fmt.dwDuration; + return 0; +} + +int PlayOneshot(int handle, int duration, int level) +{ + char buf_pid[32]; + char buf_prop[32]; + char buf_handle[32]; + char buf_duration[32]; + char buf_level[32]; + + if (_cancel_thread() < 0) { + MODULE_ERROR("_cancel_thread fail"); + return -1; + } + + snprintf(buf_pid, sizeof(buf_pid), "%d", getpid()); + snprintf(buf_prop, sizeof(buf_prop), "%d", ONESHOT); + snprintf(buf_handle, sizeof(buf_handle), "%d", handle); + snprintf(buf_duration, sizeof(buf_duration), "%d", duration); + snprintf(buf_level, sizeof(buf_level), "%d", level); + + MODULE_LOG("pid : %s, prop : %s, handle : %s", buf_pid, buf_prop, buf_handle); + return __haptic_call_predef_action(PREDEF_HAPTIC, 5, buf_pid, buf_prop, + buf_handle, buf_duration, buf_level); +} + +int PlayBuffer(int handle, const unsigned char *vibe_buffer, int iteration, int level) +{ + HapticFile *pfile; + unsigned char **ppbuffer; + unsigned int channels, length, align; + unsigned char data; + int i, j; + + pfile = (HapticFile*)vibe_buffer; + if (_check_valid_haptic_format(pfile) < 0) { + MODULE_ERROR("this buffer is not HapticFormat"); + return -1; + } + + /* Temporary code + This code does not support handle and multi channel concept. + Only this code adds to test for playing file. */ + + if (_cancel_thread() < 0) { + MODULE_ERROR("_cancel_thread fail"); + return -1; + } + + channels = pfile->fmt.wChannels; + align = pfile->fmt.wBlockAlign; + length = (pfile->data.chunkSize-8)/align; + MODULE_LOG("channels : %d, length : %d, align : %d, level : %d", channels, length, align, level); + + /* Create buffer */ + ppbuffer = (unsigned char**)malloc(sizeof(unsigned char*)*channels); + for (i = 0; i < channels; ++i) { + ppbuffer[i] = (unsigned char*)malloc(sizeof(unsigned char)*length); + memset(ppbuffer[i], 0, sizeof(unsigned char)*length); + } + + /* Copy buffer from source buffer */ + for (i = 0; i < length; ++i) { + for (j = 0; j < channels; ++j) { + data = (unsigned char)(pfile->data.pData[i*align+j]); + ppbuffer[j][i] = (unsigned char)(data*level/0xFF); + MODULE_LOG("ppbuffer[%2d][%2d] : data(%x) -> (%x)", j, i, data, ppbuffer[j][i]); + } + } + + gbuffer.handle = handle; + gbuffer.ppbuffer = ppbuffer; + gbuffer.channels = channels; + gbuffer.length = length; + gbuffer.iteration = iteration; + + __haptic_predefine_action(gbuffer.handle, PLAY, NULL); + + /* Start thread */ + if (_create_thread(&gbuffer, __play_cb) < 0) { + MODULE_ERROR("_create_thread fail"); + return -1; + } + + return 0; +} + +int Stop(int handle) +{ + char buf_pid[32]; + char buf_prop[32]; + char buf_handle[32]; + + if (_cancel_thread() < 0) { + MODULE_ERROR("_cancel_thread fail"); + return -1; + } + + snprintf(buf_pid, sizeof(buf_pid), "%d", getpid()); + snprintf(buf_prop, sizeof(buf_prop), "%d", STOP); + snprintf(buf_handle, sizeof(buf_handle), "%d", handle); + + MODULE_LOG("pid : %s, prop : %s, handle : %s", buf_pid, buf_prop, buf_handle); + return __haptic_call_predef_action(PREDEF_HAPTIC, 3, buf_pid, buf_prop, buf_handle); +} + +int OpenDevice(int handle) +{ + char buf_pid[32]; + char buf_prop[32]; + char buf_handle[32]; + + snprintf(buf_pid, sizeof(buf_pid), "%d", getpid()); + snprintf(buf_prop, sizeof(buf_prop), "%d", OPEN); + snprintf(buf_handle, sizeof(buf_handle), "%d", handle); + + MODULE_LOG("pid : %s, prop : %s, handle : %s", buf_pid, buf_prop, buf_handle); + return __haptic_call_predef_action(PREDEF_HAPTIC, 3, buf_pid, buf_prop, buf_handle); +} + +int CloseDevice(int handle) +{ + char buf_pid[32]; + char buf_prop[32]; + char buf_handle[32]; + + if (_cancel_thread() < 0) { + MODULE_ERROR("_cancel_thread fail"); + return -1; + } + + snprintf(buf_pid, sizeof(buf_pid), "%d", getpid()); + snprintf(buf_prop, sizeof(buf_prop), "%d", CLOSE); + snprintf(buf_handle, sizeof(buf_handle), "%d", handle); + + MODULE_LOG("pid : %s, prop : %s, handle : %s", buf_pid, buf_prop, buf_handle); + return __haptic_call_predef_action(PREDEF_HAPTIC, 3, buf_pid, buf_prop, buf_handle); +} + +int GetState(int handle, int *state) +{ + if (gbuffer.handle == handle) { + *state = STATE_PLAY; + return 0; + } + + *state = STATE_STOP; + return 0; +} diff --git a/tizen/DEVICE/src/haptic.c b/tizen/DEVICE/src/haptic.c new file mode 100644 index 0000000..e7605de --- /dev/null +++ b/tizen/DEVICE/src/haptic.c @@ -0,0 +1,622 @@ +/* + * haptic-module-tizen + * Copyright (c) 2012 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <assert.h> +#include <time.h> +#include <vconf.h> + +#include <haptic_plugin_intf.h> +#include "haptic_module_log.h" +#include "file.h" + +#ifndef EXTAPI +#define EXTAPI __attribute__ ((visibility("default"))) +#endif + +#define DEFAULT_EFFECT_HANDLE 0xFFFF +#define DEFAULT_MOTOR_COUNT 1 +#define HAPTIC_PLAY_FILE_EXT ".tht" + +/* START of Static Function Section */ +static int __to_level(int feedback, int *type) +{ + static int max = -1; + int t; + + if (max == -1) { + int status = GetHapticLevelMax(&max); + if (status < 0) { + MODULE_ERROR("GetHapticLevelMax fail : %d", status); + return HAPTIC_MODULE_OPERATION_FAILED; + } + } + + t = feedback * max / HAPTIC_MODULE_FEEDBACK_MAX; + MODULE_LOG("feedback value is changed : %d -> %d", feedback, t); + + if (type) + *type = t; + + return 0; +} + +static void __trim_name(const char *file_name, char *vibe_buffer, int size) +{ + int length; + + assert(file_name); + assert(vibe_buffer); + assert(size > 0); + + snprintf(vibe_buffer, size, "%s", file_name); + + length = strlen(vibe_buffer); + while (vibe_buffer[--length] == ' '); + vibe_buffer[length + 1] = '\0'; +} + +static int __check_ext(const char *name) +{ + char *ext; + + assert(name); + + ext = strrchr(name, '.'); + if (ext && !strcmp(ext, HAPTIC_PLAY_FILE_EXT)) + return 1; + + return 0; +} + +static int __get_size(FILE *pf, const char *fname) +{ + int status; + int size; + + assert(pf); + + status = fseek(pf, 0, SEEK_END); + if (status == -1) { + MODULE_ERROR("fseek failed: %s", fname); + return -1; + } + + size = ftell(pf); + + status = fseek(pf, 0, SEEK_SET); + if (status == -1) { + MODULE_ERROR("fseek failed: %s", fname); + return -1; + } + + return size; +} + +static unsigned char *__read_file(const char *fname) +{ + int status; + FILE *pf; + long size; + unsigned char *vibe_buffer; + + assert(fname); + + pf = fopen(fname, "rb"); + if (!pf) { + MODULE_ERROR("fopen failed: %s", fname); + return NULL; + } + + size = __get_size(pf, fname); + if (size <= 0) { + fclose(pf); + return NULL; + } + + vibe_buffer = malloc(size); + if (!vibe_buffer) { + fclose(pf); + MODULE_ERROR("buffer alloc failed"); + return NULL; + } + + status = fread(vibe_buffer, 1, size, pf); + if (status != size) { + MODULE_ERROR("fread failed: expect %d read %d", size, status); + free(vibe_buffer); + vibe_buffer = NULL; + } + + fclose(pf); + + return vibe_buffer; +} + +static unsigned char* __convert_file_to_buffer(const char *file_name) +{ + char fname[FILENAME_MAX]; + int status; + + __trim_name(file_name, fname, sizeof(fname)); + status = __check_ext(fname); + if (!status) { + MODULE_ERROR("__check_file faild"); + return NULL; + } + + return __read_file(fname); +} + +static int __save_file(const unsigned char *vibe_buferf, int size, const char *file_name) +{ + int status; + FILE *pf; + int fd; + + pf = fopen(file_name, "wb+"); + if (pf == NULL) { + MODULE_ERROR("To open file is failed"); + return HAPTIC_MODULE_OPERATION_FAILED; + } + + status = fwrite(vibe_buferf, 1, size, pf); + if (status != size) { + MODULE_ERROR("To write file is failed"); + fclose(pf); + return HAPTIC_MODULE_OPERATION_FAILED; + } + + fd = fileno(pf); + if (fd == -1) { + MODULE_ERROR("To get file descriptor is failed"); + fclose(pf); + return HAPTIC_MODULE_OPERATION_FAILED; + } + + status = fsync(fd); + if (status == -1) { + MODULE_ERROR("To be synchronized with the disk is failed"); + fclose(pf); + return HAPTIC_MODULE_OPERATION_FAILED; + } + + fclose(pf); + + return 0; +} + +static int __vibrate(int device_handle, const unsigned char *vibe_buffer, int iteration, int feedback, int priority) +{ + int status; + int level; + + assert(vibe_buffer); + + status = __to_level(feedback, &level); + if (status != HAPTIC_MODULE_ERROR_NONE) + return status; + + status = PlayBuffer(device_handle, vibe_buffer, iteration, level); + if (status < 0) { + MODULE_ERROR("PlayHapticBuffer fail : %d", status); + return HAPTIC_MODULE_OPERATION_FAILED; + } + + return 0; +} + +static void *_create_handle(void) +{ + static int i = 0; + return ((getpid()<<16)|(time(NULL)+(i++))); +} +/* END of Static Function Section */ + +static int _get_device_count(int *count) +{ + if (count == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + *count = DEFAULT_MOTOR_COUNT; + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _open_device(int device_index, int *device_handle) +{ + int handle; + int status; + + if (device_index < HAPTIC_MODULE_DEVICE_0 || device_index > HAPTIC_MODULE_DEVICE_ALL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (device_handle == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + handle = _create_handle(); + status = OpenDevice(handle); + if (status < 0) { + MODULE_ERROR("OpenHapticDevice fail :%d", status); + return HAPTIC_MODULE_OPERATION_FAILED; + } + + *device_handle = handle; + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _close_device(int device_handle) +{ + int status; + + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + status = CloseDevice(device_handle); + if (status < 0) { + MODULE_ERROR("CloseHapticDevice fail : %d", status); + return HAPTIC_MODULE_OPERATION_FAILED; + } + + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _vibrate_monotone(int device_handle, int duration, int feedback, int priority, int *effect_handle) +{ + int status; + int level; + + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (duration < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (feedback < HAPTIC_MODULE_FEEDBACK_MIN || feedback > HAPTIC_MODULE_FEEDBACK_MAX) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (priority < HAPTIC_MODULE_PRIORITY_MIN || priority > HAPTIC_MODULE_PRIORITY_HIGH) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (effect_handle == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (feedback == HAPTIC_MODULE_FEEDBACK_MIN) + return HAPTIC_MODULE_ERROR_NONE; + + status = __to_level(feedback, &level); + if (status != HAPTIC_MODULE_ERROR_NONE) + return status; + + status = PlayOneshot(device_handle, duration, level); + if (status < 0) { + MODULE_ERROR("PlayOneshot fail : %d", status); + return HAPTIC_MODULE_OPERATION_FAILED; + } + + *effect_handle = DEFAULT_EFFECT_HANDLE; + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _vibrate_file(int device_handle, const char *file_path, int iteration, int feedback, int priority, int *effect_handle) +{ + int status; + unsigned char *vibe_buffer; + + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (file_path == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (iteration < HAPTIC_MODULE_ITERATION_ONCE || iteration > HAPTIC_MODULE_ITERATION_INFINITE) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (feedback < HAPTIC_MODULE_FEEDBACK_MIN || feedback > HAPTIC_MODULE_FEEDBACK_MAX) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (priority < HAPTIC_MODULE_PRIORITY_MIN || priority > HAPTIC_MODULE_PRIORITY_HIGH) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (effect_handle == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (feedback == HAPTIC_MODULE_FEEDBACK_MIN) + return HAPTIC_MODULE_ERROR_NONE; + + vibe_buffer = __convert_file_to_buffer(file_path); + if (!vibe_buffer) { + MODULE_ERROR("File load filed"); + return HAPTIC_MODULE_OPERATION_FAILED; + } + + status = __vibrate(device_handle, vibe_buffer, iteration, feedback, priority); + free(vibe_buffer); + + *effect_handle = DEFAULT_EFFECT_HANDLE; + return status; +} + +static int _vibrate_buffer(int device_handle, const unsigned char *vibe_buffer, int iteration, int feedback, int priority, int *effect_handle) +{ + int status; + + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (vibe_buffer == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (iteration < HAPTIC_MODULE_ITERATION_ONCE || iteration > HAPTIC_MODULE_ITERATION_INFINITE) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (feedback < HAPTIC_MODULE_FEEDBACK_MIN || feedback > HAPTIC_MODULE_FEEDBACK_MAX) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (priority < HAPTIC_MODULE_PRIORITY_MIN || priority > HAPTIC_MODULE_PRIORITY_HIGH) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (effect_handle == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (feedback == HAPTIC_MODULE_FEEDBACK_MIN) + return HAPTIC_MODULE_ERROR_NONE; + + status = __vibrate(device_handle, vibe_buffer, iteration, feedback, priority); + + *effect_handle = DEFAULT_EFFECT_HANDLE; + return status; +} + +static int _stop_effect(int device_handle, int effect_handle) +{ + int status; + + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (effect_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + status = Stop(device_handle); + if (status < 0) { + MODULE_ERROR("StopHaptic fail : %d", status); + return HAPTIC_MODULE_OPERATION_FAILED; + } + + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _stop_all_effects(int device_handle) +{ + int status; + + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + status = Stop(device_handle); + if (status < 0) { + MODULE_ERROR("StopHaptic fail : %d", status); + return HAPTIC_MODULE_OPERATION_FAILED; + } + + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _pause_effect(int device_handle, int effect_handle) +{ + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (effect_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + MODULE_ERROR("This device is not supported this function(%s)", __func__); + return HAPTIC_MODULE_NOT_SUPPORTED; +} + +static int _resume_effect(int device_handle, int effect_handle) +{ + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (effect_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + MODULE_ERROR("This device is not supported this function(%s)", __func__); + return HAPTIC_MODULE_NOT_SUPPORTED; +} + +static int _get_effect_state(int device_handle, int effect_handle, int *state) +{ + int status; + int cur_state; + + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (effect_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (state == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + status = GetState(device_handle, &cur_state); + if (status < 0) { + MODULE_ERROR("GetState fail : %d", status); + return HAPTIC_MODULE_OPERATION_FAILED; + } + + *state = cur_state; + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _create_effect(unsigned char *vibe_buffer, int max_bufsize, haptic_module_effect_element *elem_arr, int max_elemcnt) +{ + int status; + int i; + HapticElement elem; + + if (vibe_buffer == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (max_bufsize < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (elem_arr == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (max_elemcnt < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + status = InitializeBuffer(vibe_buffer, max_bufsize); + if (status < 0) { + MODULE_ERROR("InitializeHapticBuffer fail: %d", status); + return HAPTIC_MODULE_OPERATION_FAILED; + } + + MODULE_LOG("effect count : %d", max_elemcnt); + for (i = 0; i < max_elemcnt; ++i) { + elem.duration = elem_arr[i].haptic_duration; + elem.level = elem_arr[i].haptic_level; + MODULE_LOG("%d) duration : %d, level : %d", i, elem_arr[i].haptic_duration, elem_arr[i].haptic_level); + + status = InsertElement(vibe_buffer, max_bufsize, &elem); + if (status < 0) { + MODULE_ERROR("InsertHapticElement fail: %d", status); + return HAPTIC_MODULE_OPERATION_FAILED; + } + } + + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _save_effect(const unsigned char *vibe_buffer, int max_bufsize, const char *file_path) +{ + int status; + int size; + + if (vibe_buffer == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (max_bufsize < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (file_path == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + status = GetBufferSize(vibe_buffer, &size); + if (status < 0) { + MODULE_ERROR("GetHapticBufferSize fail: %d", status); + return HAPTIC_MODULE_OPERATION_FAILED; + } + + return __save_file(vibe_buffer, size, file_path); +} + +static int _get_file_duration(int device_handle, const char *file_path, int *file_duration) +{ + int status; + unsigned char *vibe_buffer; + int duration; + + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (file_path == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (file_duration == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + vibe_buffer = __convert_file_to_buffer(file_path); + if (!vibe_buffer) { + MODULE_ERROR("File load filed"); + return HAPTIC_MODULE_OPERATION_FAILED; + } + + status = GetBufferDuration(vibe_buffer, &duration); + free(vibe_buffer); + if (status < 0) { + MODULE_ERROR("GetHapticBufferDuration fail: %d", status); + return HAPTIC_MODULE_OPERATION_FAILED; + } + + *file_duration = duration; + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _get_buffer_duration(int device_handle, const unsigned char *vibe_buffer, int *buffer_duration) +{ + int status; + int duration; + + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (vibe_buffer == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (buffer_duration == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + status = GetBufferDuration(vibe_buffer, &duration); + if (status < 0) { + MODULE_ERROR("GetHapticBufferDuration fail: %d", status); + return HAPTIC_MODULE_OPERATION_FAILED; + } + + *buffer_duration = duration; + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _convert_binary (void) +{ + MODULE_ERROR("This device is not supported this function(%s)", __func__); + return HAPTIC_MODULE_NOT_SUPPORTED; +} + +static const haptic_plugin_interface haptic_plugin_tizen = { + .haptic_internal_get_device_count = _get_device_count, + .haptic_internal_open_device = _open_device, + .haptic_internal_close_device = _close_device, + .haptic_internal_vibrate_monotone = _vibrate_monotone, + .haptic_internal_vibrate_file = _vibrate_file, + .haptic_internal_vibrate_buffer = _vibrate_buffer, + .haptic_internal_stop_effect = _stop_effect, + .haptic_internal_stop_all_effects = _stop_all_effects, + .haptic_internal_pause_effect = _pause_effect, + .haptic_internal_resume_effect = _resume_effect, + .haptic_internal_get_effect_state = _get_effect_state, + .haptic_internal_create_effect = _create_effect, + .haptic_internal_save_effect = _save_effect, + .haptic_internal_get_file_duration = _get_file_duration, + .haptic_internal_get_buffer_duration = _get_buffer_duration, + .haptic_internal_convert_binary = _convert_binary, +}; + +EXTAPI +const haptic_plugin_interface *get_haptic_plugin_interface() +{ + return &haptic_plugin_tizen; +} diff --git a/tizen/DEVICE/src/sysnoti.c b/tizen/DEVICE/src/sysnoti.c new file mode 100644 index 0000000..56aaad8 --- /dev/null +++ b/tizen/DEVICE/src/sysnoti.c @@ -0,0 +1,163 @@ +/* + * haptic-module-tizen + * Copyright (c) 2012 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stdarg.h> +#include <errno.h> + +#include "haptic_module_log.h" + +#define HAPTIC_RETRY_READ_COUNT 5 +#define HAPTIC_PARAM_CNT 3 +#define HAPTIC_MAXSTR 100 +#define HAPTIC_MAXARG 16 +#define PREDEF_HAPTIC "haptic" +#define SYSNOTI_SOCKET_PATH "/tmp/sn" + +enum sysnoti_cmd { + ADD_HAPTIC_ACTION, + CALL_HAPTIC_ACTION, +}; + +struct sysnoti_type { + int pid; + int cmd; + char *type; + char *path; + int argc; + char *argv[HAPTIC_MAXARG]; +}; + +static inline int __send_int(int fd, int val) +{ + return write(fd, &val, sizeof(int)); +} + +static inline int __send_str(int fd, char *str) +{ + int len; + int r; + + if (str == NULL) { + len = 0; + r = write(fd, &len, sizeof(int)); + } else { + len = strlen(str); + if (len > HAPTIC_MAXSTR) + len = HAPTIC_MAXSTR; + r = write(fd, &len, sizeof(int)); + r = write(fd, str, len); + } + + return r; +} + +static int __sysnoti_send(struct sysnoti_type *msg) +{ + int sockfd; + int len; + struct sockaddr_un addr; + int retry_cnt; + int ret; + int i; + int r; + + sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd == -1) { + MODULE_ERROR("socket create failed"); + return -1; + } + + bzero(&addr, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, SYSNOTI_SOCKET_PATH, sizeof(addr.sun_path) - 1); + len = sizeof(addr); + + if (connect(sockfd, (struct sockaddr *)&addr, len) < 0) { + MODULE_ERROR("connect failed"); + close(sockfd); + return -1; + } + MODULE_LOG("connect : %x", sockfd); + + __send_int(sockfd, msg->pid); + __send_int(sockfd, msg->cmd); + __send_str(sockfd, msg->type); + __send_str(sockfd, msg->path); + __send_int(sockfd, msg->argc); + for (i = 0; i < msg->argc; i++) + __send_str(sockfd, msg->argv[i]); + + MODULE_LOG("read"); + retry_cnt = 0; + while ((r = read(sockfd, &ret, sizeof(int))) < 0) { + + if (errno != EINTR) { + MODULE_LOG("read fail : %s(%d)", strerror(errno), errno); + ret = -1; + break; + } + + if (retry_cnt == HAPTIC_RETRY_READ_COUNT) { + MODULE_ERROR("retry(%d) fail", retry_cnt); + ret = -1; + break; + } + + MODULE_ERROR("Re-read for error(EINTR)"); + ++retry_cnt; + } + + MODULE_LOG("close (ret : %d) : %x", ret, sockfd); + close(sockfd); + return ret; +} + +int __haptic_call_predef_action(const char *type, int num, ...) +{ + struct sysnoti_type msg; + char *args; + va_list argptr; + int i; + + if (type == NULL || num > HAPTIC_MAXARG) { + errno = EINVAL; + return -1; + } + + msg.pid = getpid(); + msg.cmd = CALL_HAPTIC_ACTION; + msg.type = (char *)type; + msg.path = NULL; + msg.argc = num; + + va_start(argptr, num); + for (i = 0; i < num; i++) { + args = va_arg(argptr, char *); + msg.argv[i] = args; + } + va_end(argptr); + + return __sysnoti_send(&msg); +} + diff --git a/tizen/SIMULATOR/CMakeLists.txt b/tizen/SIMULATOR/CMakeLists.txt new file mode 100644 index 0000000..91a79a3 --- /dev/null +++ b/tizen/SIMULATOR/CMakeLists.txt @@ -0,0 +1,27 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +SET(DEPENDENTS "dlog haptic-plugin") + +SET(SRCS + src/haptic.c) + +INCLUDE(FindPkgConfig) +pkg_check_modules(rpkgs REQUIRED ${DEPENDENTS}) + +FOREACH(flag ${rpkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -g -fno-omit-frame-pointer") +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,--no-as-needed") + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${rpkgs_LDFLAGS}) + +ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"") +ADD_DEFINITIONS("-DENABLE_DLOG_OUT -DSLP_DEBUG") + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR}) diff --git a/tizen/SIMULATOR/src/haptic.c b/tizen/SIMULATOR/src/haptic.c new file mode 100644 index 0000000..c81fe2a --- /dev/null +++ b/tizen/SIMULATOR/src/haptic.c @@ -0,0 +1,312 @@ +/* + * haptic-module-tizen + * Copyright (c) 2012 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <haptic_plugin_intf.h> +#include "haptic_module_log.h" + +#ifndef EXTAPI +#define EXTAPI __attribute__ ((visibility("default"))) +#endif + +#define DEFAULT_MOTOR_COUNT 1 +#define DEFAULT_DEVICE_HANDLE 0x01 +#define DEFAULT_EFFECT_HANDLE 0x02 + +static int _get_device_count(int *count) +{ + if (count == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + *count = DEFAULT_MOTOR_COUNT; + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _open_device(int device_index, int *device_handle) +{ + if (device_index < HAPTIC_MODULE_DEVICE_0 || device_index > HAPTIC_MODULE_DEVICE_ALL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (device_handle == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + *device_handle = DEFAULT_DEVICE_HANDLE; + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _close_device(int device_handle) +{ + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _vibrate_monotone(int device_handle, int duration, int feedback, int priority, int *effect_handle) +{ + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (duration < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (feedback < HAPTIC_MODULE_FEEDBACK_MIN || feedback > HAPTIC_MODULE_FEEDBACK_MAX) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (priority < HAPTIC_MODULE_PRIORITY_MIN || priority > HAPTIC_MODULE_PRIORITY_HIGH) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (effect_handle == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (feedback == HAPTIC_MODULE_FEEDBACK_MIN) + return HAPTIC_MODULE_ERROR_NONE; + + MODULE_LOG("call %s function", __func__); + + *effect_handle = DEFAULT_EFFECT_HANDLE; + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _vibrate_file(int device_handle, const char *file_path, int iteration, int feedback, int priority, int *effect_handle) +{ + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (file_path == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (iteration < HAPTIC_MODULE_ITERATION_ONCE || iteration > HAPTIC_MODULE_ITERATION_INFINITE) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (feedback < HAPTIC_MODULE_FEEDBACK_MIN || feedback > HAPTIC_MODULE_FEEDBACK_MAX) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (priority < HAPTIC_MODULE_PRIORITY_MIN || priority > HAPTIC_MODULE_PRIORITY_HIGH) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (effect_handle == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (feedback == HAPTIC_MODULE_FEEDBACK_MIN) + return HAPTIC_MODULE_ERROR_NONE; + + MODULE_LOG("call %s function", __func__); + + *effect_handle = DEFAULT_EFFECT_HANDLE; + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _vibrate_buffer(int device_handle, const unsigned char *vibe_buffer, int iteration, int feedback, int priority, int *effect_handle) +{ + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (vibe_buffer == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (iteration < HAPTIC_MODULE_ITERATION_ONCE || iteration > HAPTIC_MODULE_ITERATION_INFINITE) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (feedback < HAPTIC_MODULE_FEEDBACK_MIN || feedback > HAPTIC_MODULE_FEEDBACK_MAX) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (priority < HAPTIC_MODULE_PRIORITY_MIN || priority > HAPTIC_MODULE_PRIORITY_HIGH) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (effect_handle == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (feedback == HAPTIC_MODULE_FEEDBACK_MIN) + return HAPTIC_MODULE_ERROR_NONE; + + MODULE_LOG("call %s function", __func__); + + *effect_handle = DEFAULT_EFFECT_HANDLE; + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _stop_effect(int device_handle, int effect_handle) +{ + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (effect_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + MODULE_LOG("call %s function", __func__); + + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _stop_all_effects(int device_handle) +{ + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + MODULE_LOG("call %s function", __func__); + + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _pause_effect(int device_handle, int effect_handle) +{ + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (effect_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + MODULE_LOG("call %s function", __func__); + + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _resume_effect(int device_handle, int effect_handle) +{ + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (effect_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + MODULE_LOG("call %s function", __func__); + + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _get_effect_state(int device_handle, int effect_handle, int *effect_state) +{ + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (effect_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (effect_state == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + MODULE_LOG("call %s function", __func__); + + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _create_effect(const unsigned char *vibe_buffer, int max_bufsize, haptic_module_effect_element *elem_arr, int max_elemcnt) +{ + if (vibe_buffer == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (max_bufsize < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (elem_arr == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (max_elemcnt < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + MODULE_LOG("call %s function", __func__); + + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _save_effect(const unsigned char *vibe_buffer, int max_bufsize, const char *file_path) +{ + if (vibe_buffer == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (max_bufsize < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (file_path == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + MODULE_LOG("call %s function", __func__); + + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _get_file_duration(int device_handle, const char *file_path, int *file_duration) +{ + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (file_path == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (file_duration == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + MODULE_LOG("call %s function", __func__); + + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _get_buffer_duration(int device_handle, const unsigned char *vibe_buffer, int *buffer_duration) +{ + if (device_handle < 0) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (vibe_buffer == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + if (buffer_duration == NULL) + return HAPTIC_MODULE_INVALID_ARGUMENT; + + MODULE_LOG("call %s function", __func__); + + return HAPTIC_MODULE_ERROR_NONE; +} + +static int _convert_binary (void) +{ + MODULE_ERROR("This device is not supported this function(%s)", __func__); + return HAPTIC_MODULE_NOT_SUPPORTED; +} + +static haptic_plugin_interface haptic_plugin_emul = { + .haptic_internal_get_device_count = _get_device_count, + .haptic_internal_open_device = _open_device, + .haptic_internal_close_device = _close_device, + .haptic_internal_vibrate_monotone = _vibrate_monotone, + .haptic_internal_vibrate_file = _vibrate_file, + .haptic_internal_vibrate_buffer = _vibrate_buffer, + .haptic_internal_stop_effect = _stop_effect, + .haptic_internal_stop_all_effects = _stop_all_effects, + .haptic_internal_pause_effect = _pause_effect, + .haptic_internal_resume_effect = _resume_effect, + .haptic_internal_get_effect_state = _get_effect_state, + .haptic_internal_create_effect = _create_effect, + .haptic_internal_save_effect = _save_effect, + .haptic_internal_get_file_duration = _get_file_duration, + .haptic_internal_get_buffer_duration = _get_buffer_duration, + .haptic_internal_convert_binary = _convert_binary, +}; + +EXTAPI +const haptic_plugin_interface *get_haptic_plugin_interface() +{ + return &haptic_plugin_emul; +} |