Developing in C# for Pimax 4K HMD

I have the SDK and I am diving in. My comments so far are at the end of the thread at:
http://community.openmr.ai/t/is-there-and-sdk-hdk-for-the-pm4k/379/13

I will report any future findings here. I hope that others will get involved. I’d like to see the Pimax 4K HMD reach its full potential and a strong developer community can be a big help in making that a reality.

My first goal is a simple console app that displays positional data from the headset while in extended mode. If this is possible (for me and anyone willing to help out) then we can advance quickly to a robust utility to help all games that run on the PC either native SBS or via utilities like Tridef to work with Pimax 4K.

I’m not looking to sell anything, and I’ll make all my code open source and the utilities free for all. Let me know if you might be willing to help!

2 Likes

I Hi there.
I am willing to help.
C# is al my daily poison at work, so I would like to see some development with this language.

Someone did a DLL dump in regards to the SDK reference,
http://community.openmr.ai/t/is-there-and-sdk-hdk-for-the-pm4k/379/20

I have been a little slow getting into the coding of this project. Last night I made the mistake of installing the oculus store or maybe it was something else but it prevented extended mode from working… luckily I had a system restore point.

I wonder how LifeRiftView supports both oculus and Pimax flawlessly without anything special needed. If only we had his source… I imagine he doesn’t even use the Pimax SDK, and yet has all this working.

Also it seems like, a lot of games on the Pimax store are oculus games that had code injected or something. Like many of those games if u get it from another oculus source they don’t work with the Pimax… but somehow the version in the PiStore has patched them into working.

I am also only newly learning OSVR,
But adding support through there could also make head tracking and such work with many more games.

Let me know your dev status,
And I will do the same.
With enough like minded people we will produce something awesome!!!

Cheers,
Chris

1 Like

That someone was me :slight_smile:

I will continue to record my progress and hopefully soon I’ll have the initialization working. Once I get that working, it won’t take too long to get the console app working… then the full utility. Maybe by Christmas, which is my goal. I got one for my 24-year-old daughter and she will love it if she can play WoW and Ark with the Pimax 4K at 2K resolution. She will use an XBox controller for motion and head tracking (assuming I get it working) to look around. This is why I am highly motivated to get this working… to make my Christmas gift really rock for her.

Hehe, I should pay more attention to usernames… or even linked post titles, haha.

I am just getting into playing with those components too… I’ll let you know if I make some good progress.
Good Luck!

PS: You daughter would freak with such an awesome gift I am thinking!!! :smiley:

1 Like

I’m not able to code but any testing or confirming needed done, will be willing to help.
It is a great idea and if all I can do is cheer you on, then “yay good work! You can do it!”

Love to have access to head tracking in extended mode.

1 Like

Can’t seem to get the LibPVRClient64.dll to load. Here is my code:

Api.cs

using System;
using System.Runtime.InteropServices;

namespace Win32
{
    internal static class Api
    {
        [DllImport("kernel32.dll")]
        public static extern IntPtr LoadLibrary(string dllToLoad);

        [DllImport("kernel32.dll")]
        public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

        [DllImport("kernel32.dll")]
        public static extern bool FreeLibrary(IntPtr hModule);
    }
}

Program.cs

using System;
using System.IO;

namespace PimaxReader
{
    static class Program
    {
        public static int Main(string[] args)
        {
            string dllFile = Path.Combine(Environment.SystemDirectory, "LibPVRClient64.dll");
            IntPtr dllHandle = Win32.Api.LoadLibrary(dllFile);
            if (dllHandle == IntPtr.Zero)
            {
                return 1;
            }

            var interfacePtr = Win32.Api.GetProcAddress(dllHandle, "getPvrInterface");
            if (interfacePtr == IntPtr.Zero)
            {
                Win32.Api.FreeLibrary(dllHandle);
                return 2;
            }

            return -1;
        }
    }
}

Notes

Put any DLL name in the Windows\System32 folder and this code works, use LibPVRClient64.dll and you get back zero every time. I tried with Pimax unplugged, in extended and in Pimax mode. In all cases I get a zero back.

If I can’t get the dll to load, then I can’t access any methods, so it’s a lost effort. Can anyone shine any light or have any results that differ from mine?

This is about as basic as the code can get, so not sure where to go from here. Pimax folks… any hints?

Not sure if this will help you but do you know the program open track or free pie ?

They can read udp over USB. For head tracking.
I got it to read the headtracking in direct mode. Not in extended.

Its open source so might help you get a new direction.or even integrate into open track (it has lotsof nice options to adjust settings in tracking.

Anyways hope you can find the answers your looking for. Good work.

1 Like

I tried used a redgate tool we have at work to disassemble the dll… however where did you find that LibPVRClient64.dll, I looked in Pimax and Piserver directories… I before did my tests with pvr_driver dll (named similar to that) but redgate didn’t like it… I can try the disassembler on libPVRClient64 to see if there is any clear reason why you are getting those results.

Once I find the LibPVRClient64 (I assume I’m just blind and it’s in the windows/piserver directory), once I find that I will play with your snippet and see if the redgate reflector is able to give us any more insight.

Thanks for posting the snippet,
I usually work with direct .net dll references,
So your post should help out a lot… as I figured we had to import them differently.

You maybe are getting a badimageformat exception behind the scenes or something, as that look like a win32 function loading an x64 component?

Not sure if there is a Win64.api.loadlibrary(.); similar call you could try.

1 Like

Environment.SystemDirectory returns the System32 folder. This is where you will find the .dll file. It is called out in the SDK. Notice that if you select any other .dll in that folder, it loads just fine. The zero typically means not found or dependancy not found.

Now going a different route. Looking at talking to the USB interface directly. That may be the right path when in extended mode. Even PiPlay can’t see the device in that mode, so this may be a better route. I do wish I had the source code for the OCPlugIn which seems to communicate with the Pimax well.

Here is the key part of my code:
using (var searcher = new ManagementObjectSearcher(@“Select * From Win32_PnPEntity”))
collection = searcher.Get();

I found several entries which were different when the Pimax was plugged into the USB

They were:
The Display itself. We don’t need this one.
Device ID: DISPLAY\OVR0003\5&23E4F8FF&0&UID4353, PNP Device ID: DISPLAY\OVR0003\5&23E4F8FF&0&UID4353, Description: PnP-Monitor (Standard)

One of the next two looks like the what we need. The HID-compliant one looks promising for sure!
Device ID: USB\VID_2833&PID_0021\MSCEM8R6K9DAK410Y100, PNP Device ID: USB\VID_2833&PID_0021\MSCEM8R6K9DAK410Y100, Description: USB Input Device

Device ID: HID\VID_2833&PID_0021\6&316D18B5&0&0000, PNP Device ID: HID\VID_2833&PID_0021\6&316D18B5&0&0000, Description: HID-compliant device

This is the audio, so we don’t need this.
Device ID: SWD\MMDEVAPI{0.0.0.00000000}.{31864B34-5A91-41CA-AB78-C7CD95B774F1}, PNP Device ID: SWD\MMDEVAPI{0.0.0.00000000}.{31864B34-5A91-41CA-AB78-C7CD95B774F1}, Description: Audio Endpoint

If someone needs a full example, check out ocroquette’s post referencing Adel Hazzah’s code at c# - Get List of connected USB Devices - Stack Overflow

Here is my code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;

namespace PimaxReader
{
    internal class Program
    {
        public static void Main(string[] args)
        {
            WindowsUsb();

            // Wait for user input..
            Console.ReadKey();
        }

        public static void WindowsUsb()
        {
            var usbDevices = GetUsbDevices();

            foreach (var usbDevice in usbDevices)
            {
                Console.WriteLine("Device ID: {0}, PNP Device ID: {1}, Description: {2}\n\r",
                    usbDevice.DeviceId, usbDevice.PnpDeviceId, usbDevice.Description);
            }

            Console.Read();
        }

        private static IEnumerable<UsbDeviceInfo> GetUsbDevices()
        {
            ManagementObjectCollection collection;
            using (var searcher = new ManagementObjectSearcher(@"Select * From Win32_PnPEntity"))
                collection = searcher.Get();

            var devices = (
                from ManagementBaseObject device in collection
                select new UsbDeviceInfo(
                    (string) device.GetPropertyValue("DeviceID"), 
                    (string) device.GetPropertyValue("PNPDeviceID"), 
                    (string) device.GetPropertyValue("Description")
                )).ToList();

            collection.Dispose();
            return devices;
        }

        class UsbDeviceInfo
        {
            public UsbDeviceInfo(string deviceId, string pnpDeviceId, string description)
            {
                this.DeviceId = deviceId;
                this.PnpDeviceId = pnpDeviceId;
                this.Description = description;
            }
            public string DeviceId { get; private set; }
            public string PnpDeviceId { get; private set; }
            public string Description { get; private set; }
        }
    }
}
1 Like

Thanks Mike, I was able to run your code. Just needed to import the System.Management.dll into the project reference and then everything ran. The usb output seems very general, have you been able to isolate the one(s) associated with the pimax?

Also, I was playing around a debugging tool I found called x64dbg,
still going through all the data, but when I attached one of its features, Scylla x64 to the piservice process, I noticed these other dlls mentioned.

PiHmdlib_0_8.dll
PiHmdlib_0_6.dll,
and PiHmdLib_0_4.dll

Those numbers seems to reflect maybe oculus runtimes?

2 Likes

Two posts back I isolated the four entries needed. The screen itself, what looks like the two relating to the I/O one general and one HID compliant (The one I’ll target today) as well as the device for audio. I did so by first running the utility with the HMD attached in extended mode, then again with it disconnected. I used Notepad++'s compare plugin to isolate the 4 sections.

Very interesting about your findings. If I can’t get the direct USB path to work, this offers another alternative, thank you! As long as we have paths to follow, we can keep marching forward.

I also just can’t express strongly enough how good it is to have you, and others interested in this. Working, even on small things like this, in a vacume is difficult. Knowing that others will review your work and add to it, and appreciate it, makes a world of difference. Thank you!

1 Like

Oh no way, don’t know how I missed that one.
Smart thinking with looking into the deltas of the hardware scans!!

I could agree more Mike! :slight_smile:

2 Likes

Busy weekend so didn’t have a chance to code till tonight, and then only a short time. But I modified my code to only find HID-Compliant devices which narrowed the list down quite a bit. I then expanded to code to display all of the discovered properties for the devices.

Here is the code:

using System;
using System.Linq;
using System.Management;

namespace PimaxReader
{
    internal class Program
    {
        public static void Main(string[] args)
        {
            WindowsUsb();

            // Wait for user input..
            Console.ReadKey();
        }

        public static void WindowsUsb()
        {
            GetUsbDevices();

            Console.Read();
        }

        private static void GetUsbDevices()
        {
            ManagementObjectCollection collection;
            using (var searcher = new ManagementObjectSearcher(@"Select * From Win32_PnPEntity"))
                collection = searcher.Get();

            var hidCompliantDevices = (from ManagementBaseObject device in collection
                          where device?.GetPropertyValue("Description")?.ToString() == "HID-compliant device"
                          select device.Properties).ToList();

            collection.Dispose();

            foreach (var hidCompliantDevice in hidCompliantDevices)
            {
                foreach (var property in hidCompliantDevice)
                {
                    if (property.Value != null)
                    {
                        Console.WriteLine($"Name:{property.Name}");
                        Console.WriteLine($"Origin:{property.Origin}");
                        Console.WriteLine($"Type:{property.Type}");
                        Console.WriteLine($"Value:{property.Value}");
                        if (property.IsArray)
                        {
                            if (property.Value != null)
                            {
                                var t = property.Value as string[];
                                var list = t?.ToList();
                                if (list != null)
                                {
                                    foreach (var item in list)
                                    {
                                        Console.WriteLine($"    Item:{item}");
                                    }
                                }
                            }
                        }
                        Console.WriteLine("------------------------------");
                    }
                }
                Console.WriteLine("");
                Console.WriteLine("");
                Console.WriteLine("");
                Console.WriteLine(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            }

        }
    }
}

Here is the relevant output from the Pimax 4K HMD as a USB attached HID_Complient Device. Hopefuly everything I need to start reading values is contained here. I’ve never queried a HID before, so time will tell.

The Output: (Partial)

Name:Caption
Origin:CIM_ManagedSystemElement
Type:String
Value:HID-compliant device
------------------------------
Name:ClassGuid
Origin:Win32_PnPEntity
Type:String
Value:{745a17a0-74d3-11d0-b6fe-00a0c90f57da}
------------------------------
Name:ConfigManagerErrorCode
Origin:CIM_LogicalDevice
Type:UInt32
Value:0
------------------------------
Name:ConfigManagerUserConfig
Origin:CIM_LogicalDevice
Type:Boolean
Value:False
------------------------------
Name:CreationClassName
Origin:CIM_LogicalDevice
Type:String
Value:Win32_PnPEntity
------------------------------
Name:Description
Origin:CIM_ManagedSystemElement
Type:String
Value:HID-compliant device
------------------------------
Name:DeviceID
Origin:CIM_LogicalDevice
Type:String
Value:HID\VID_2833&PID_0021\6&316D18B5&0&0000
------------------------------
Name:HardwareID
Origin:Win32_PnPEntity
Type:String
Value:System.String[]
    Item:HID\VID_2833&PID_0021&REV_0212
    Item:HID\VID_2833&PID_0021
    Item:HID\VID_2833&UP:0003_U:0005
    Item:HID_DEVICE_UP:0003_U:0005
    Item:HID_DEVICE
------------------------------
Name:Manufacturer
Origin:Win32_PnPEntity
Type:String
Value:(Standard system devices)
------------------------------
Name:Name
Origin:CIM_ManagedSystemElement
Type:String
Value:HID-compliant device
------------------------------
Name:PNPClass
Origin:Win32_PnPEntity
Type:String
Value:HIDClass
------------------------------
Name:PNPDeviceID
Origin:CIM_LogicalDevice
Type:String
Value:HID\VID_2833&PID_0021\6&316D18B5&0&0000
------------------------------

I need your help…

If someone else can run the code and compare the values and let me know if the values are the same on your machine as mine, so I can tell what is a consistent value that I can use to ID the device and what is a local ID unique to my machine, or my device. That would let me scan the attached devices and know if I found the Pimax. Once I know how to ID it, I’ll try to read from it. I just need a way to know that the code found the right device.

If you run the code with the Pimax USB disconnected, see what HID devices are on your machine, then plug it in, make sure it’s in extended mode and run again, you’ll see one additional HID and it’s that new data that I need. Use it to compare to what I have, or just paste what you get and I’ll compare the data.

Thanks in advance!

P.S.
A Google search showed me that HID with device ID: 0021 and vendor ID: 2833 is the Oculus Rift. So that makes sense, in extended mode it is supposed to be Oculus compatible… I may be on to something!

What did we all do before Google? A bit of searching lead me to this page: .net - USB HID hangs on Read() in C# - Stack Overflow which looks like code for a different device that might also work for the Pimax… or get me going the right direction.

I’ve been reading about subscribing to the callbacks and this code seems to follow the HID pattern I’ve been researching. I’ll dive in soon I hope, this shouldn’t take me long to either get working or get really stuck. I’ll report on my progress and I make any.

No way, this is awesome Mike!
I will play around with your changes tonight.

Yes, so many times at work… google > stackoverflow… cant imagine coding without those tools anymore, haha.

2 Likes

Dear MikeReedKS:
I was touched by you and saw your efforts for your daughter . The extended mode is compatible with Oculus 0.6 SDK .The Pimax mode is use pimax SDK .Pimax SDK can only be used in pimax mode.If you want to use in extended mode, you can download oculus0.6 SDK to use.Hope it helps you. good day.

1 Like

Hi guys,

I’ve just ordered my Pimax, but it will take about 10 days before it’s here from China :frowning: In the mean time I was looking at this forum and found it very disappointing that we can’t watch 4k 180/360 video without it being downsampled. The reason is, I guess, that there’s simply no VR player that supports it (it needs to get position data from the headset of course and then push correct part of the video to the HDMI). I don’t know how hard it is to fix up something like this ourselves, I guess it would mean a lot of work, unless there’s an open source player to start with.

Anyway so I was reading your efforts and am a bit confused. The way I understand it, there’s an API but it just installs one DLL which can’t be loaded ? I’m a coder and reverse engineer/hacker myself and done quite a bit of work for example in the console scene and android scene, so maybe I can help out. If you post the DLL I’ll take a look at it and see if I can find why it’s not loading.

Also, can somebody please explain what’s up with all these modes ? I understand extended mode is just windows treating the headset as a second monitor, right ? But what does ‘pimax mode’ do then ? I think I’ve read it also enables ‘extended mode’, but it most do something more ? Anybody who can shed a bit of light on all this ? Thanks !

1 Like

Hi sjefdeklerk and welcome.
So, when you install PImax software everything resolution wise is locked and behind the greyed out area shows a 1080p resolution. The team release Pix.exe to unlock full resolutions, by desktop it allows new resolutions,

That said, 3840x2160 and 2880x1800 are messed up… like verticle alignment and interlace stuff is not correct… those I feel will be fixed very shortly. That said, the issue with 3840x2160 (not a big deal for movies) is that for compatiblity they are using hdmi 1.4 (1.4b I believe), whic has bandwidth caps at 4kx30fps… so, the other resolutions you can get 60fpps…but 4k only 30 until they work out the the compression… that said any lower resolution upscales to 4k and reduces the screen-door-effect.

The above coding attempts, at least my focus is on extended mode… mainly because we can get up to 2k working. However, most games (except oculus 0.6 games as Green has pointed out) don’t make use of the head-tracking. If we could make a service application to turn headmovement to mouse-movements we open the door.

While they released the Pimax SDK… there isnt a lot of english documentation. We were experimenting to get a C# interface to the HMD working. I am just now downloading the oculus 0.6 sdk to play around.

ps: becareful as an oculus service can make the pimax have trouble connecting…
this post has a solution for this it seems,
http://community.openmr.ai/t/how-to-use-pimax-play-ochome-platform-games-run-rift-cv1-games/749

… but all that said,
we want to keep the focus on development in this thread.
I should be able to get the dll to send you…but if you install Piplay from the release section of this forum, it will add a dll to C:\Windows\System32\LibPVRClient64.dll

that is the one we were mentioning.