Making The HTC Touch Diamond Vibrate

One of the minor problems I had when making the Stopwatch for my HTC Touch Diamond, was to make the phone vibrate automatically. It seems there are no managed way of doing this. However, after a bit of googling around, I found out that the vibrator typically can be addressed as a LED object using the Open NET CF Framework. So I decided to throw together a tiny wrapper class around this functionality, so I can use it generally in the future. The most useful thing here, I think, is the ability to have the phone vibrate using a given on-off pattern in a fire-and-forget pattern that works well when programming Compact Framework forms.

This is the simple Vibrator class:

         1: using System;
         2: using System.Threading;
         3: using OpenNETCF.WindowsCE.Notification;
         4:  
         5:  namespace dr.WM.Common
         6: {
         7:     /// <summary>
         8:     /// Vibrator class. Works on HTC Touch Diamond, not tested anywhere else.
         9:     /// (Mostly, The LED index could be different on other devices.)
         10:     /// </summary>
         11:     public class Vibrator
         12:     {
         13:         /// <summary>
         14:         /// Index of the Vibrator LED.
         15:         /// </summary>
         16:         private const int VibratorLedIndex = 1;
         17:         /// <summary>
         18:         /// LED instance.
         19:         /// </summary>
         20:         private readonly Led led = new Led();
         21:         /// <summary>
         22:         /// Whether the Run thread is allowed to run.
         23:         /// </summary>
         24:         private bool allowRun = false;
         25:         /// <summary>
         26:         /// Starts this instance.
         27:         /// </summary>
         28:         public void Start()
         29:         {
         30:             allowRun = true;
         31:             led.SetLedStatus(VibratorLedIndex,Led.LedState.Blink);
         32:         }
         33:  
         34:         /// <summary>
         35:         /// Stops this instance.
         36:         /// </summary>
         37:         public void Stop()
         38:         {
         39:             allowRun = false;
         40:             led.SetLedStatus(VibratorLedIndex, Led.LedState.Off);            
         41:         }
         42:  
         43:         /// <summary>
         44:         /// Starts a vibrating sequence by specifying the vibrate and pause times.
         45:         /// Vibration will run until the Stop method is called.
         46:         /// </summary>
         47:         /// <param name="msVibrate">The vibrate time in milliseconds.</param>
         48:         /// <param name="msPause">The pause time in milliseconds.</param>
         49:         public void StartSequence(int msVibrate, int msPause)
         50:         {
         51:             StartSequence(msVibrate,msPause,0);
         52:         }
         53:         /// <summary>
         54:         /// Starts a vibrating sequence by specifying the vibrate and pause times.
         55:         /// Vibration will run for the specified total time, or until the Stop method is called.
         56:         /// </summary>
         57:         /// <param name="msVibrate">The vibrate time in milliseconds.</param>
         58:         /// <param name="msPause">The pause time in milliseconds.</param>
         59:         /// <param name="totalLength">The total time to vibrate.</param>
         60:         public void StartSequence(int msVibrate, int msPause, int totalLength)
         61:         {
         62:             allowRun = true;
         63:             ThreadPool.QueueUserWorkItem(Run,
         64:                                          new RunState
         65:                                              {VibrateTime = msVibrate, PauseTime = msPause, TotalTime = totalLength});
         66:         }
         67:  
         68:         /// <summary>
         69:         /// Thread worker for a vibrating sequence.
         70:         /// </summary>
         71:         /// <param name="state">The state.</param>
         72:         private void Run(object state)
         73:         {
         74:             long begin = Environment.TickCount;
         75:             RunState runState = (RunState)state;
         76:             while(allowRun && (runState.TotalTime <= 0 || Environment.TickCount - begin < runState.TotalTime))
         77:             {
         78:                 led.SetLedStatus(VibratorLedIndex, Led.LedState.Blink);
         79:                 Thread.Sleep(runState.VibrateTime);
         80:                 led.SetLedStatus(VibratorLedIndex, Led.LedState.Off);
         81:                 Thread.Sleep(runState.PauseTime);
         82:             }
         83:         }
         84:  
         85:         /// <summary>
         86:         /// Helper for passing vibration state to the worker thread.
         87:         /// </summary>
         88:         private struct RunState
         89:         {
         90:             public int VibrateTime { get; set; }
         91:             public int PauseTime { get; set; }
         92:             public int TotalTime { get; set; }
         93:         }
         94:     }
         95: }

Please note that this might (propably) will not work on other devices, since the vibrator might not be on the same LED index. One could refactor the class and make a couple of vibrator on/off virtual protected methods, and call these from the Start / Stop methods. That way, it could be easy to make the class general enough for use on other devices, you would just need to implement the start and stop operations. However, there might be an easier way of doing this using an unmanaged API (actually I hope there is, since collecting info about all types of devices in order to figure out how to fire the vibrator, seems as an unfeasible task).

It seems that the Klaxon Open-Source alarm clock for Windows Mobile has just been made Open Source. I think I will have a look at the source to see whether my way of using the vibrator is feasible, or the Klaxon author uses a better approach ;-)