예제 #1
0
// Serializes the profiles to disk.
void ProfileManager::SaveCache()
{
    String path = GetProfilePath(true);
 
    Lock::Locker lockScope(&ProfileLock);

    // TODO: Since there is only a single device type now, a full tree overwrite
    // is sufficient but in the future a selective device branch replacement will
    // be necessary

    Ptr<JSON> root = *JSON::CreateObject();
    root->AddNumberItem("Oculus Profile Version", PROFILE_VERSION);
    root->AddStringItem("CurrentProfile", DefaultProfile);
    root->AddNumberItem("ProfileCount", (double) ProfileCache.GetSize());

    // Generate a JSON subtree for each profile
    for (unsigned int i=0; i<ProfileCache.GetSize(); i++)
    {
        Profile* profile = ProfileCache[i];

        JSON* json_profile = JSON::CreateObject();
        json_profile->Name = "Profile";
        json_profile->AddStringItem("Name", profile->Name);
        const char* gender;
        switch (profile->GetGender())
        {
            case Profile::Gender_Male:   gender = "Male"; break;
            case Profile::Gender_Female: gender = "Female"; break;
            default: gender = "Unspecified";
        }
        json_profile->AddStringItem("Gender", gender);
        json_profile->AddNumberItem("PlayerHeight", profile->PlayerHeight);
        json_profile->AddNumberItem("IPD", profile->IPD);

        if (profile->Type == Profile_RiftDK1)
        {
            RiftDK1Profile* riftdk1 = (RiftDK1Profile*)profile;
            JSON* json_riftdk1 = JSON::CreateObject();
            json_profile->AddItem("RiftDK1", json_riftdk1);

            const char* eyecup = "A";
            switch (riftdk1->EyeCups)
            {
                case RiftDK1Profile::EyeCup_A: eyecup = "A"; break;
                case RiftDK1Profile::EyeCup_B: eyecup = "B"; break;
                case RiftDK1Profile::EyeCup_C: eyecup = "C"; break;
            }
            json_riftdk1->AddStringItem("EyeCup", eyecup);
            json_riftdk1->AddNumberItem("LL", riftdk1->LL);
            json_riftdk1->AddNumberItem("LR", riftdk1->LR);
            json_riftdk1->AddNumberItem("RL", riftdk1->RL);
            json_riftdk1->AddNumberItem("RR", riftdk1->RR);
        }

        root->AddItem("Profile", json_profile);
    }

    root->Save(path);
}
예제 #2
0
// Writes the current calibration for a particular device to a device profile file
// sensor - the sensor that was calibrated
// cal_name - an optional name for the calibration or default if cal_name == NULL
bool SensorFusion::SaveMagCalibration(const char* calibrationName) const
{
    if (CachedSensorInfo.SerialNumber[0] == 0 || !HasMagCalibration())
        return false;
    
    // A named calibration may be specified for calibration in different
    // environments, otherwise the default calibration is used
    if (calibrationName == NULL)
        calibrationName = "default";

    // Generate a mag calibration event
    JSON* calibration = JSON::CreateObject();
    // (hardcoded for now) the measurement and representation method 
    calibration->AddStringItem("Version", "2.0");   
    calibration->AddStringItem("Name", "default");

    // time stamp the calibration
    char time_str[64];
   
#if defined(OVR_OS_WIN32) and !defined(__MINGW32__)
    struct tm caltime;
    localtime_s(&caltime, &MagCalibrationTime);
    strftime(time_str, 64, "%Y-%m-%d %H:%M:%S", &caltime);
#else
    struct tm* caltime;
    caltime = localtime(&MagCalibrationTime);
    strftime(time_str, 64, "%Y-%m-%d %H:%M:%S", caltime);
#endif
   
    calibration->AddStringItem("Time", time_str);

    // write the full calibration matrix
    char matrix[256];
    Matrix4f calmat = GetMagCalibration();
    calmat.ToString(matrix, 256);
    calibration->AddStringItem("CalibrationMatrix", matrix);
    // save just the offset, for backwards compatibility
    // this can be removed when we don't want to support 0.2.4 anymore
    Vector3f center(calmat.M[0][3], calmat.M[1][3], calmat.M[2][3]);
    Matrix4f tmp = calmat; tmp.M[0][3] = tmp.M[1][3] = tmp.M[2][3] = 0; tmp.M[3][3] = 1;
    center = tmp.Inverted().Transform(center);
    Matrix4f oldcalmat; oldcalmat.M[0][3] = center.x; oldcalmat.M[1][3] = center.y; oldcalmat.M[2][3] = center.z; 
    oldcalmat.ToString(matrix, 256);
    calibration->AddStringItem("Calibration", matrix);
    

    String path = GetBaseOVRPath(true);
    path += "/Devices.json";

    // Look for a prexisting device file to edit
    Ptr<JSON> root = *JSON::Load(path);
    if (root)
    {   // Quick sanity check of the file type and format before we parse it
        JSON* version = root->GetFirstItem();
        if (version && version->Name == "Oculus Device Profile Version")
        {   
            int major = atoi(version->Value.ToCStr());
            if (major > MAX_DEVICE_PROFILE_MAJOR_VERSION)
            {
                // don't use the file on unsupported major version number
                root->Release();
                root = NULL;
            }
        }
        else
        {
            root->Release();
            root = NULL;
        }
    }

    JSON* device = NULL;
    if (root)
    {
        device = root->GetFirstItem();   // skip the header
        device = root->GetNextItem(device);
        while (device)
        {   // Search for a previous calibration with the same name for this device
            // and remove it before adding the new one
            if (device->Name == "Device")
            {   
                JSON* item = device->GetItemByName("Serial");
                if (item && item->Value == CachedSensorInfo.SerialNumber)
                {   // found an entry for this device
                    item = device->GetNextItem(item);
                    while (item)
                    {
                        if (item->Name == "MagCalibration")
                        {   
                            JSON* name = item->GetItemByName("Name");
                            if (name && name->Value == calibrationName)
                            {   // found a calibration of the same name
                                item->RemoveNode();
                                item->Release();
                                break;
                            } 
                        }
                        item = device->GetNextItem(item);
                    }

                    // update the auto-mag flag
                    item = device->GetItemByName("EnableYawCorrection");
                    if (item)
                        item->dValue = (double)EnableYawCorrection;
                    else
                        device->AddBoolItem("EnableYawCorrection", EnableYawCorrection);

                    break;
                }
            }

            device = root->GetNextItem(device);
        }
    }
    else
    {   // Create a new device root
        root = *JSON::CreateObject();
        root->AddStringItem("Oculus Device Profile Version", "1.0");
    }

    if (device == NULL)
    {
        device = JSON::CreateObject();
        device->AddStringItem("Product", CachedSensorInfo.ProductName);
        device->AddNumberItem("ProductID", CachedSensorInfo.ProductId);
        device->AddStringItem("Serial", CachedSensorInfo.SerialNumber);
        device->AddBoolItem("EnableYawCorrection", EnableYawCorrection);

        root->AddItem("Device", device);
    }

    // Create and the add the new calibration event to the device
    device->AddItem("MagCalibration", calibration);

    return root->Save(path);
}
예제 #3
0
// Serializes the profiles to disk.
void ProfileManager::SaveCache()
{
    String path = GetProfilePath(true);
 
    Lock::Locker lockScope(&ProfileLock);

    Ptr<JSON> oldroot = *JSON::Load(path);
    if (oldroot)
    {
        if (oldroot->GetItemCount() >= 3)
        {
            JSON* item0 = oldroot->GetFirstItem();
            JSON* item1 = oldroot->GetNextItem(item0);
            oldroot->GetNextItem(item1);

            if (item0->Name == "Oculus Profile Version")
            {
                int major = atoi(item0->Value.ToCStr());
                if (major > MAX_PROFILE_MAJOR_VERSION)
                    oldroot.Clear();   // don't use the file on unsupported major version number
            }
            else
            {
                oldroot.Clear(); 
            }
        }
        else
        {
            oldroot.Clear();
        }
    }
    
    // Create a new json root
    Ptr<JSON> root = *JSON::CreateObject();
    root->AddNumberItem("Oculus Profile Version", PROFILE_VERSION);
    root->AddStringItem("CurrentProfile", DefaultProfile);
    root->AddNumberItem("ProfileCount", (double) ProfileCache.GetSize());

    // Generate a JSON subtree for each profile
    for (unsigned int i=0; i<ProfileCache.GetSize(); i++)
    {
        Profile* profile = ProfileCache[i];

        // Write the base profile information
        JSON* json_profile = JSON::CreateObject();
        json_profile->Name = "Profile";
        json_profile->AddStringItem("Name", profile->Name);
        const char* gender;
        switch (profile->GetGender())
        {
            case Profile::Gender_Male:   gender = "Male"; break;
            case Profile::Gender_Female: gender = "Female"; break;
            default: gender = "Unspecified";
        }
        json_profile->AddStringItem("Gender", gender);
        json_profile->AddNumberItem("PlayerHeight", profile->PlayerHeight);
        json_profile->AddNumberItem("IPD", profile->IPD);

        const char* device_name = NULL;
        // Create a device-specific subtree for the cached device
        if (profile->Type == Profile_RiftDK1)
        {
            device_name = "RiftDK1";
            
            RiftDK1Profile* rift = (RiftDK1Profile*)profile;
            JSON* json_rift = JSON::CreateObject();
            json_profile->AddItem(device_name, json_rift);

            const char* eyecup = "A";
            switch (rift->EyeCups)
            {
                case EyeCup_A: eyecup = "A"; break;
                case EyeCup_B: eyecup = "B"; break;
                case EyeCup_C: eyecup = "C"; break;
            }
            json_rift->AddStringItem("EyeCup", eyecup);
            json_rift->AddNumberItem("LL", rift->LL);
            json_rift->AddNumberItem("LR", rift->LR);
            json_rift->AddNumberItem("RL", rift->RL);
            json_rift->AddNumberItem("RR", rift->RR);
        }
        else if (profile->Type == Profile_RiftDKHD)
        {
            device_name = "RiftDKHD";
            
            RiftDKHDProfile* rift = (RiftDKHDProfile*)profile;
            JSON* json_rift = JSON::CreateObject();
            json_profile->AddItem(device_name, json_rift);

            const char* eyecup = "A";
            switch (rift->EyeCups)
            {
                case EyeCup_A: eyecup = "A"; break;
                case EyeCup_B: eyecup = "B"; break;
                case EyeCup_C: eyecup = "C"; break;
            }
            json_rift->AddStringItem("EyeCup", eyecup);
            //json_rift->AddNumberItem("LL", rift->LL);
            //json_rift->AddNumberItem("LR", rift->LR);
            //json_rift->AddNumberItem("RL", rift->RL);
            //json_rift->AddNumberItem("RR", rift->RR);
        }

        // There may be multiple devices stored per user, but only a single
        // device is represented by this root.  We don't want to overwrite
        // the other devices so we need to examine the older root 
        // and merge previous devices into new json root
        if (oldroot)
        {
            JSON* old_profile = oldroot->GetFirstItem();
            while (old_profile)
            {
                if (old_profile->Name == "Profile")
                {
                    JSON* profile_name = old_profile->GetItemByName("Name");
                    if (profile_name && OVR_strcmp(profile->Name, profile_name->Value) == 0)
                    {   // Now that we found the user in the older root, add all the 
                        // object children to the new root - except for the one for the
                        // current device
                        JSON* old_item = old_profile->GetFirstItem();
                        while (old_item)
                        {
                            if (old_item->Type == JSON_Object 
                                && (device_name == NULL || OVR_strcmp(old_item->Name, device_name) != 0))
                            {
                                JSON* old_device = old_item;
                                old_item = old_profile->GetNextItem(old_item);

                                // remove the node from the older root to avoid multiple reference
                                old_device->RemoveNode();
                                // add the node pointer to the new root
                                json_profile->AddItem(old_device->Name, old_device);
                            }
                            else
                            {
                                old_item = old_profile->GetNextItem(old_item);
                            }
                        }

                        break;
                    }
                }

                old_profile = oldroot->GetNextItem(old_profile);
            }
        }

        // Add the completed user profile to the new root
        root->AddItem("Profile", json_profile);
    }

    // Save the profile to disk
    root->Save(path);
}
예제 #4
0
void ProfileManager::LoadV1Profiles(JSON* v1)
{
    JSON* item0 = v1->GetFirstItem();
    JSON* item1 = v1->GetNextItem(item0);
    JSON* item2 = v1->GetNextItem(item1);

    // Create the new profile database
    Ptr<JSON> root = *JSON::CreateObject();
    root->AddNumberItem("Oculus Profile Version", 2.0);
    root->AddItem("Users", JSON::CreateArray());
    root->AddItem("TaggedData", JSON::CreateArray());
    ProfileCache = root;

    const char* default_dk1_user = item1->Value;
    
    // Read the number of profiles
    int   profileCount = (int)item2->dValue;
    JSON* profileItem  = item2;

    for (int p=0; p<profileCount; p++)
    {
        profileItem = root->GetNextItem(profileItem);
        if (profileItem == NULL)
            break;

        if (profileItem->Name == "Profile")
        {
            // Read the required Name field
            const char* profileName;
            JSON* item = profileItem->GetFirstItem();
        
            if (item && (item->Name == "Name"))
            {   
                profileName = item->Value;
            }
            else
            {
                return;   // invalid field
            }
            
            // Read the user profile fields
            if (CreateUser(profileName, profileName))
            {
                const char* tag_names[2] = {"User", "Product"};
                const char* tags[2];
                tags[0] = profileName;

                Ptr<Profile> user_profile = *CreateProfile();
                user_profile->SetValue(OVR_KEY_NAME, profileName);

                float neckeye[2] = { 0, 0 };

                item = profileItem->GetNextItem(item);
                while (item)
                {
                    if (item->Type != JSON_Object)
                    {
                        if (item->Name == OVR_KEY_PLAYER_HEIGHT)
                        {   // Add an explicit eye height

                        }
                        if (item->Name == "NeckEyeHori")
                            neckeye[0] = (float)item->dValue;
                        else if (item->Name == "NeckEyeVert")
                            neckeye[1] = (float)item->dValue;
                        else 
                            user_profile->SetValue(item);
                    }
                    else
                    {   
                        // Add the user/device tag values
                        const char* device_name = item->Name.ToCStr();
                        Ptr<Profile> device_profile = *CreateProfile();

                        JSON* device_item = item->GetFirstItem();
                        while (device_item)
                        {
                            device_profile->SetValue(device_item);
                            device_item = item->GetNextItem(device_item);
                        }

                        tags[1] = device_name;
                        SetTaggedProfile(tag_names, tags, 2, device_profile);
                    }

                    item = profileItem->GetNextItem(item);
                }

                // Add an explicit eye-height field
                float player_height = user_profile->GetFloatValue(OVR_KEY_PLAYER_HEIGHT,
                                                                  OVR_DEFAULT_PLAYER_HEIGHT);
                if (player_height > 0)
                {
                    char gender[16];
                    user_profile->GetValue(OVR_KEY_GENDER, gender, 16);
        
                    const float EYE_TO_HEADTOP_RATIO =   0.44538f;
                    const float MALE_AVG_HEAD_HEIGHT =   0.232f;
                    const float FEMALE_AVG_HEAD_HEIGHT = 0.218f;
     
                    // compute distance from top of skull to the eye
                    float head_height;
                    if (OVR_strcmp(gender, "Female") == 0)
                        head_height = FEMALE_AVG_HEAD_HEIGHT;
                    else
                        head_height = MALE_AVG_HEAD_HEIGHT;

                    float skull = EYE_TO_HEADTOP_RATIO * head_height;
                    float eye_height = player_height - skull;

                    user_profile->SetFloatValue(OVR_KEY_EYE_HEIGHT, eye_height);
                }

                // Convert NeckEye values to an array
                if (neckeye[0] > 0 && neckeye[1] > 0)
                    user_profile->SetFloatValues(OVR_KEY_NECK_TO_EYE_DISTANCE, neckeye, 2);

                // Add the user tag values
                SetTaggedProfile(tag_names, tags, 1, user_profile);
            }
        }
    }

    // since V1 profiles were only for DK1, the assign the user to all DK1's
    const char* tag_names[1] = { "Product" };
    const char* tags[1] = { "RiftDK1" };
    Ptr<Profile> product_profile = *CreateProfile();
    product_profile->SetValue("DefaultUser", default_dk1_user);
    SetTaggedProfile(tag_names, tags, 1, product_profile);
}
예제 #5
0
// Populates the local profile cache.  This occurs on the first access of the profile
// data.  All profile operations are performed against the local cache until the
// ProfileManager is released or goes out of scope at which time the cache is serialized
// to disk.
void ProfileManager::LoadCache(bool create)
{
    Lock::Locker lockScope(&ProfileLock);

    ClearProfileData();

    String path = GetProfilePath();

    Ptr<JSON> root = *JSON::Load(path);
    if (root == NULL)
    {   
        path = BasePath + "/Profiles.json";  // look for legacy profile
        root = *JSON::Load(path);
        
        if (root == NULL)
        {
            if (create)
            {   // Generate a skeleton profile database
                root = *JSON::CreateObject();
                root->AddNumberItem("Oculus Profile Version", 2.0);
                root->AddItem("Users", JSON::CreateArray());
                root->AddItem("TaggedData", JSON::CreateArray());
                ProfileCache = root;
            }
            
            return;
        }

        // Verify the legacy version
        JSON* version_item = root->GetFirstItem();
        if (version_item->Name == "Oculus Profile Version")
        {
            int major = atoi(version_item->Value.ToCStr());
            if (major != 1)
                return;   // don't use the file on unsupported major version number
        }
        else
        {
            return;      // invalid file
        }

        // Convert the legacy format to the new database format
        LoadV1Profiles(root);
    }
    else
    {
        // Verify the file format and version
        JSON* version_item = root->GetFirstItem();
        if (version_item->Name == "Oculus Profile Version")
        {
            int major = atoi(version_item->Value.ToCStr());
            if (major != 2)
                return;   // don't use the file on unsupported major version number
        }
        else
        {
            return;       // invalid file 
        }

        ProfileCache = root;   // store the database contents for traversal
    }
}