Saturday, 15 August 2009

Toshiba TG01 and Accelerometer

I purchased the Toshiba TG01 a number of weeks ago and wanted to make programmatic use of the Accelerometer built into the device.

I knew that there would be a DLL on the device responsible for allowing access to the Accelerometer so I went about identifying this.

On the TG01 there is an application within the Settings called Adjust Motion Sensor and I thought that this application would make use of the DLL that would be available on the device. So I connected the TG01 via Active Sync and started Remote Process Viewer. I then started the Adjust Motion Sensor application and it appeared in the list of running processes, as expected.

Selecting the process from list provided me with a list of the Assemblies the application had loaded, one being the Axcon.dll.





I then wanted to copy the Axcon.dll to my development machine. The DLL is located in the \Windows directory of the device so I copied it from there.

I then opened the DLL using Notepad and was able to identify a number of possible method names as follows :-


?DTSDeregisterAcceleration@@YAKI@Z ?DTSDeregisterActionEvent@@YAKI@Z ?DTSGetAcceleration@@YAKIPAU_TS_ACCELERATION@@@Z ?DTSRegisterAcceleration@@YAKPAUHINSTANCE__@@IPAI@Z ?DTSRegisterActionEvent@@YAKPAUHWND__@@PAUHINSTANCE__@@PAI@Z ?DTSResumeSystemActionResponse@@YAKPAUHWND__@@@Z ?DTSSuspendSystemActionResponse@@YAKPAUHWND__@@@Z MwAxconEvtNotice MwAxconHoriPtSet MwAxconInitialSet MwAxconManOpTurn MwAxconParaSet MwAxconPresentGet MwAxconPresentGet2 MwAxconResume MwAxconStart MwAxconStop MwAxconSupend MwAxconTestRead MwAxconTestWrite TSDeregisterAcceleration TSDeregisterActionEvent TSGetAcceleration TSRegisterAcceleration TSRegisterActionEvent TSResumeSystemActionResponse TSSuspendSystemActionResponse

I then went another step further and loaded the DLL into Dependancy Walker which gave me the following :-

unsigned long DTSDeregisterAcceleration(unsigned int)
unsigned long DTSDeregisterActionEvent(unsigned int)
unsigned long DTSGetAcceleration(unsigned int,struct _TS_ACCELERATION *)
unsigned long DTSRegisterAcceleration(struct HINSTANCE__ *,unsigned int,unsigned int *)
unsigned long DTSRegisterActionEvent(struct HWND__ *,struct HINSTANCE__ *,unsigned int *)
unsigned long DTSResumeSystemActionResponse(struct HWND__ *)
unsigned long DTSSuspendSystemActionResponse(struct HWND__ *)
MwAxconEvtNotice
MwAxconHoriPtSet
MwAxconInitialSet
MwAxconManOpTurn
MwAxconParaSet
MwAxconPresentGet
MwAxconPresentGet2
MwAxconResume
MwAxconStart
MwAxconStop
MwAxconSupend
MwAxconTestRead
MwAxconTestWrite
TSDeregisterAcceleration
TSDeregisterActionEvent
TSGetAcceleration
TSRegisterAcceleration
TSRegisterActionEvent
TSResumeSystemActionResponse
TSSuspendSystemActionResponse

At this point I knew I had the methods of interest however the puzzling part was the structure being passed into the DTSGetAcceleration method.


I then fired an email off to Toshiba in the hope for some support in this area, however at the time of writing I am still waiting for a response.

I posted a question on the Modaco forums (http://www.modaco.com/content/toshiba-tg01-tg01-modaco-com/290257/tg01-sdk/) however it seemed I had reached a dead end at this point.

I just happened to check back on the forum last night and found that a thread had been started regarding the G-Sensor in the TG01 (http://www.modaco.com/content/toshiba-tg01-tg01-modaco-com/291274/g-sensor-in-tg01-emu-dev/)

Scrolling through this thread I found that a PDF document had been posted regarding the Driver Interface Specification.

I would like to point out that an attempt had been made to contact Toshiba regarding this however no response was given.

I downloaded the PDF document and begain reading. The document contained exactly the information I had been previously lacking therefore this morning I went about creating a C# managed wrapper for the methods exposed via Axcon.DLL.

Having done a bit of P/Invoking in the past I soon was able to call the required methods, passing in the correct data types and thanks to the document, able to retrieve G-Sensor data, based on the definition of the structure mentioned early.

There were two sections to the document. One was getting the G-Sensor data and the other was getting action events. These action events were things such as Shake, Rotate, Tilt, etc. The interesting thing about the action events were that when registring the event, a Handle was required for the Window that was to recieve the action events. I managed to intercept the messages being sent from the Action Event using the NativeWindow class as specified here (http://blog.opennetcf.com/ayakhnin/CategoryView,category,NativeWindow.aspx). I managed to intercept a Shake event however my main focus was on the G-Sensor data.

Having got back an X, Y and Z value from the method call DTSGetAcceleration, I then went about trying to intergrate this into the HTCSensorSDK sample as specified here (http://blog.enterprisemobile.com/2008/07/using-htc-diamonds-sensor-sdk-from-managed-code/)

With the Toshiba you had to "manually" query the G-Sensor data using the DTSGetAcceleration method.

After a short while I had managed to integrate the TG01 G-Sensor data into the sample and was able to get the ball rolling around the screen, there seems to be a slight issue with this however I am yet to figure that out.

So I have now got the wrapper I had wanted all those weeks ago and hopefully this information and sample code will help others integrate the G-Sensor data with their applications and games.

Toshiba - Please note I have only taken the unofficial route with this due to the lack of response from yourselfs. My intentions are only to help provide the relevant information to others so that they can make use of the hardware provided in the TG01.

G-Sensor Code :-

public struct _TS_ACCELERATION
{
public short x;
public short y;
public short z;
public _FILETIME time;
}

public struct _FILETIME
{
Int32 dwLowDateTime; /* low 32 bits */
Int32 dwHighDateTime; /* high 32 bits */
}

[DllImport("CoreDll.dll", SetLastError = true)]
public static extern IntPtr GetModuleHandle(IntPtr ModuleName);

[DllImport("CoreDll.dll", SetLastError = true)]
public static extern Int32 GetModuleFileName(IntPtr hModule, StringBuilder ModuleName, Int32 cch);

[DllImport("Axcon.dll", SetLastError = true)]
public static extern Int32 TSRegisterAcceleration(IntPtr hModule, UInt32 uPeriod, out UInt32 puID);

[DllImport("Axcon.dll", SetLastError = true)]
public static extern Int32 TSDeregisterAcceleration(UInt32 uID);

[DllImport("Axcon.dll", SetLastError = true)]
public static extern Int32 TSGetAcceleration(UInt32 uID, ref _TS_ACCELERATION accel);

G-Sensor Code Usage :-

// Registrying
// Firstly get the module handle for the application
IntPtr modulehandle = GetModuleHandle(IntPtr.Zero);
// Secondly registry the Acceleration providing the module handle above, the interval at which the data will be updated and the Request Id which is used when getting the G-Sensor data
TSRegisterAcceleration(modulehandle, (UInt32)100, out puId);

// Getting G-Sensor Data
// puId is the Request Id from above and acc is the reference to the_TS_ACCELERATION structure - This method can be called in a while loop or timer tick
TSGetAcceleration(puId, ref acc);

// Deregistry
// puId is the Request Id from above
TSDeregisterAcceleration(puId);

Action Events Code :-


[DllImport("Axcon.dll", SetLastError = true)]
public static extern Int32 TSRegisterActionEvent(IntPtr hWnd, IntPtr hModule, out UInt32 puID);

[DllImport("Axcon.dll", SetLastError = true)]
public static extern Int32 TSDeregisterActionEvent(uint uID);

[DllImport("Axcon.dll", SetLastError = true)]
public static extern Int32 TSSuspendSystemActionResponse(IntPtr hWnd);

[DllImport("Axcon.dll", SetLastError = true)]
public static extern Int32 TSResumeSystemActionResponse(IntPtr hWnd);


Action Events Code Usage - In conjuction with the NativeWindow project above :-

// The control that will receive the Action Events Windows Messages
MyAccControl myAccControl = new MyAccControl(this.Handle, this.listBox1);
// Register the Action Events using the Handle of the control above, the module handle and the puId
TSRegisterActionEvent(myAccControl.Handle, modulehandle, out puId);

Snippet of Code used to determine orientation of device :-

if (acc.z > 0)
{
if (acc.z > 800)
{
this.listBox1.Items.Add("Device Face Up Flat");
}
}
else
{
if (0 - acc.z > 800)
{
this.listBox1.Items.Add("Device Face Down Flat");
}
}
if (acc.y > 0)
{
if (acc.y > 800)
{
this.listBox1.Items.Add("Device Rotated Right");
}
}
else
{
if (0 - acc.y > 800)
{
this.listBox1.Items.Add("Device Rotated Left");
}
}
if (acc.x > 0)
{
if (acc.x > 800)
{
this.listBox1.Items.Add("Device Standing Up ");
}
}
else
{
if (0 - acc.x > 800)
{
this.listBox1.Items.Add("Device Upside Down");
}
}

5 comments:

  1. Identifying the methods exported by the DLL is just a matter of opening a Visual Studio command prompt and executing the following command:

    dumpbin /exports axcon.dll

    No need to open in Notepad.

    ReplyDelete
  2. Thank you for your information.
    I'm developing a Java virtual machine for Windows Mobile (name is "Mysaifu JVM").
    I wrote a library which can control TG01 accelerometer based on your information.
    http://www2s.biglobe.ne.jp/~dat/java/project/jvm/devtg01_en.html
    Source code is here:
    http://sourceforge.jp/projects/mysaifujvm/svn/view/com.mysaifu.mobile.device.tg01/?root=mysaifujvm

    ReplyDelete
  3. is there any chance that You will post TG01/HTC wrapper so we can use all gsen games and apps from htc ?

    ReplyDelete
  4. Excellent post and wonderful blog, I really like this type of interesting articles keep it u.
    Toshiba laptops

    ReplyDelete