2e774feffa5ee07495cedacc9e9414e8314fedb4
[framework/web/wrt-plugins-common.git] / src / modules / tizen / Haptics / Motor.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file        Motor.cpp
18  * @modify    Lileiming (leiming.li@samsung.com)
19  * @version   0.1
20  * @brief       add function run_beep &stop_beep
21  */
22
23 #include <Commons/Exception.h>
24 #include <VConf/Key.h>
25 #include <sys/utsname.h>
26 #include <fstream>
27 #include "Motor.h"
28 #include <mmf/mm_sound_private.h>
29
30 namespace WrtDeviceApis {
31 namespace Haptics {
32 namespace {
33 const int INVALID_BEEP_HANDLER = -1;
34 }
35
36 Motor::Motor(haptic_dev_idx index) :
37     EventHapticActionReqReceiver(Commons::ThreadEnum::HAPTICS_THREAD),
38     EventStartMotorReqReceiver(Commons::ThreadEnum::HAPTICS_THREAD),
39     EventPlayBeepReqReceiver(Commons::ThreadEnum::HAPTICS_THREAD),
40     m_beepHandle(INVALID_BEEP_HANDLER)
41 {
42     m_device = device_haptic_open(index, 0);
43     if (m_device < 0) {
44         ThrowMsg(Commons::PlatformException, "Could not open haptic device.");
45     }
46 }
47
48 Motor::~Motor()
49 {
50     if (device_haptic_close(m_device) < 0) {
51         LogDebug("Could not close haptic device.");
52     }
53 }
54
55 int Motor::playBeep(unsigned long duration,
56                     int /*volume*/)
57 {
58     int retMmSound = -1;
59
60     retMmSound = mm_sound_play_tone(MM_SOUND_TONE_PROP_BEEP, VOLUME_TYPE_SYSTEM, 1, duration, &m_beepHandle);
61 //    retMmSound = mm_sound_play_beep(VOLUME_TYPE_SYSTEM, duration, &m_beepHandle);
62     if (retMmSound < 0) {
63         m_beepHandle = INVALID_BEEP_HANDLER;
64         ThrowMsg(Commons::PlatformException, "Play Beep is Failed!");
65     }
66
67     return retMmSound;
68 }
69
70 void Motor::playBeep(const Api::EventPlayBeepPtr& event)
71 {
72     EventPlayBeepReqReceiver::PostRequest(event);
73 }
74
75 void Motor::stopBeep()
76 {
77     if (m_beepHandle == INVALID_BEEP_HANDLER) {
78         LogError("m_beepHandle is wrong!!");
79         ThrowMsg(Commons::PlatformException, "m_beepHandle is wrong!!");
80     }
81     if (mm_sound_stop_sound(m_beepHandle) != 0) {
82         LogError("mm_sound_stop_sound FAIL!!");
83         ThrowMsg(Commons::PlatformException, "mm_sound_stop_sound FAIL!!");
84     }
85     m_beepHandle = INVALID_BEEP_HANDLER;
86 }
87
88 void Motor::run(unsigned long duration)
89 {
90     if (device_haptic_play_monotone(m_device, duration) != 0) {
91         ThrowMsg(Commons::PlatformException, "Could not run haptic motor.");
92     }
93 }
94
95 void Motor::run(const Api::HapticPatternPtr& pattern)
96 {
97     LogInfo("Entered!");
98
99     m_pattern.Reset();
100     if (!pattern || 0 == pattern->length()) {
101         return; // nothing to do
102     }
103     m_current = 0;
104     m_pattern = pattern;
105     if (m_event) {
106         LogDebug("Wait current event! And then run Next pattern!");
107         return;
108     }
109     runNextPattern();
110 }
111
112 void Motor::run(const Api::EventStartMotorPtr& event)
113 {
114     EventStartMotorReqReceiver::PostRequest(event);
115 }
116
117 void Motor::stopMotor()
118 {
119     if (device_haptic_stop_play(m_device) != 0) {
120         LogError("Haptic motor stop fail!");
121         ThrowMsg(Commons::PlatformException, "Could not stop haptic motor.");
122     }
123 }
124
125 void Motor::stopVibration()
126 {
127     LogDebug("Entered!");
128
129     /* Stop pattern */
130     if (m_pattern) {
131         m_current = m_pattern->length();
132     }
133
134     /* Stop Motor */
135     stopMotor();
136 }
137
138 void Motor::OnRequestReceived(const EventHapticActionPtr& event)
139 {
140     LogInfo("Haptic action event received");
141
142     DPL::Mutex::ScopedLock lock(&m_patternMutex);
143     if (event->checkCancelled()) {
144         LogWarning("Haptic pattern canceled by another one");
145         return; // event has been canceled by another Motor::run -> nothing to do
146     }
147
148     runNextPattern();
149 }
150
151 void Motor::OnRequestReceived(const Api::EventStartMotorPtr& event)
152 {
153     LogInfo("Start motor event received");
154     try
155     {
156         if (event == NULL) {
157             LogError("Event is NULL!");
158             ThrowMsg(Commons::PlatformException, "Event is NULL!!");
159         }
160
161         unsigned long duration = 0;
162         Api::HapticPatternPtr patternPtr = event->getPatternRef();
163         size_t patternLength = patternPtr->length();
164
165         if (event->getDuration() > 0) {
166             // Ignore duration if duration is lower than 0
167             duration = event->getDuration();
168         }
169
170         if ((duration > 0) && (patternLength == 0)) {
171             // run motor during duration
172             run(duration);
173         } else if ((duration == 0) && (patternLength > 0)) {
174             // run motor by pattern
175             run(patternPtr);
176         } else if ((duration > 0) && (patternLength > 0)) {
177             // run motor by pattern during duration
178             arragePattern(patternPtr, duration);
179             run(patternPtr);
180         } else {
181             LogDebug("duration is 0 and pattern is null!!! Do Nothing!");
182         }
183     }
184     catch (Commons::PlatformException) {
185         LogError("platform exception");
186         event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
187     }
188 }
189
190 void Motor::OnRequestReceived(const Api::EventPlayBeepPtr& event)
191 {
192     LogInfo("Play beep event received");
193     try
194     {
195         if (event == NULL) {
196             LogError("event is NULL!");
197             ThrowMsg(Commons::PlatformException, "Event is NULL!!");
198         }
199
200         LogDebug(
201             "duration: " << event->getDuration() << ", volume: " <<
202             event->getVolume());
203         if (event->getDuration() <= 0) {
204             LogDebug("duration is less than 0!! Do Nothing!");
205             return;
206         }
207         if (playBeep(static_cast<unsigned long>(event->getDuration()),
208                      event->getVolume()) < 0) {
209             LogError("playBeep returned error!!");
210             ThrowMsg(Commons::PlatformException, "Play Beep is Failed!");
211         }
212     }
213     catch (Commons::PlatformException) {
214         LogError("platform exception");
215         event->setExceptionCode(Commons::ExceptionCodes::PlatformException);
216     }
217 }
218
219 void Motor::runNextPattern()
220 {
221     // always stop the motor
222     LogInfo("stopping motor");
223     stopMotor();
224
225     if (m_current >= m_pattern->length()) {
226         m_event.Reset();
227         m_pattern.Reset();
228         LogInfo("end of pattern");
229         return; // end of pattern
230     }
231
232     unsigned long duration = m_pattern->duration(m_current);
233
234     bool active = false;
235     Try {
236         active = m_pattern->isActive(m_current);
237     }
238     Catch(Commons::OutOfRangeException) {
239         LogError("Platform sequence size exceeded. Finishing.");
240         m_event.Reset();
241         m_pattern.Reset();
242         return;
243     }
244
245     // action
246     if (active) {
247         LogInfo("haptic action for " << duration << "ms");
248         run(duration);
249     }
250     // pause
251     else {
252         LogInfo("pausing for " << duration << "ms");
253     }
254
255     LogInfo("post request delayed for " << duration << "ms");
256     m_current++;
257     m_event = EventHapticActionPtr(new EventHapticAction());
258     m_event->setForAsynchronousCall(NULL);  // not interested in answer
259
260     // post delayed event
261     EventHapticActionReqReceiver::PostRequest(m_event, duration / 1000.0);
262 }
263
264 void Motor::arragePattern(Api::HapticPatternPtr& patternPtr,
265         const unsigned long duration)
266 {
267     LogInfo("Entered!!");
268
269     if (patternPtr == NULL) {
270         LogError("patternPtr is NULL");
271         return;
272     }
273
274     size_t patternLength = patternPtr->length();
275     unsigned long totalPatternDuration = 0;
276     unsigned long repeatCnt = 0;
277     unsigned long addingCnt = 0;
278     size_t currentInterval = 0;
279
280     for (size_t i = 0; i < patternLength; i++) {
281         totalPatternDuration += patternPtr->duration(i);
282     }
283     if ((duration % totalPatternDuration) == 0) {
284         repeatCnt = (duration / totalPatternDuration);
285     } else {
286         repeatCnt = (duration / totalPatternDuration) + 1;
287     }
288     addingCnt = repeatCnt - 1;
289
290     /* Repeat pattern during duration */
291     for (unsigned long i = 0; i < addingCnt; i++) {
292         for (currentInterval = 0;
293              currentInterval < patternLength;
294              currentInterval++) {
295             patternPtr->addInterval(patternPtr->duration(
296                                         currentInterval),
297                                     patternPtr->isActive(currentInterval));
298         }
299     }
300 }
301 } // Haptics
302 } // WrtDeviceApis