float HMDState::getFloatValue(const char* propertyName, float defaultVal) { if (OVR_strcmp(propertyName, "LensSeparation") == 0) { return OurHMDInfo.LensSeparationInMeters; } else if (OVR_strcmp(propertyName, "VsyncToNextVsync") == 0) { return OurHMDInfo.Shutter.VsyncToNextVsync; } else if (OVR_strcmp(propertyName, "PixelPersistence") == 0) { return OurHMDInfo.Shutter.PixelPersistence; } else if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetNumberValue, propertyName)) { return (float)NetClient::GetInstance()->GetNumberValue(GetNetId(), propertyName, defaultVal); } else if (pProfile) { return pProfile->GetFloatValue(propertyName, defaultVal); } return defaultVal; }
bool HMDProfile::ParseProperty(const char* prop, const char* sval) { if (OVR_strcmp(prop, "LL") == 0) { LL = atoi(sval); return true; } else if (OVR_strcmp(prop, "LR") == 0) { LR = atoi(sval); return true; } else if (OVR_strcmp(prop, "RL") == 0) { RL = atoi(sval); return true; } else if (OVR_strcmp(prop, "RR") == 0) { RR = atoi(sval); return true; } return Profile::ParseProperty(prop, sval); }
// Removes an existing profile. Returns true if the profile was found and deleted // and returns false otherwise. bool ProfileManager::Delete(const Profile* profile) { Lock::Locker lockScope(&ProfileLock); if (OVR_strcmp(profile->Name, "default") == 0) return false; // don't delete a default profile if (CacheDevice == Profile_Unknown) LoadCache(profile->Type); // Look for the existence of this profile for (unsigned int i=0; i<ProfileCache.GetSize(); i++) { if (OVR_strcmp(profile->Name, ProfileCache[i]->Name) == 0) { if (OVR_strcmp(profile->Name, DefaultProfile) == 0) DefaultProfile.Clear(); ProfileCache.RemoveAt(i); Changed = true; return true; } } return false; }
const JSON * JsonReader::GetChildByName( const char * childName ) const { assert( IsObject() ); // Check if the the cached child pointer is valid. if ( !Parent->Children.IsNull( Child ) ) { if ( OVR_strcmp( Child->Name, childName ) == 0 ) { const JSON * c = Child; Child = c->pNext; // Cache the next child. return c; } } // Itereate over all children. for ( const JSON * c = Parent->Children.GetFirst(); !Parent->Children.IsNull( c ); c = c->pNext ) { if ( OVR_strcmp( c->Name, childName ) == 0 ) { Child = c->pNext; // Cache the next child. return c; } } return 0; }
bool RiftDK1Profile::ParseProperty(const char* prop, const char* sval) { if (OVR_strcmp(prop, "EyeCup") == 0) { switch (sval[0]) { case 'C': EyeCups = EyeCup_C; break; case 'B': EyeCups = EyeCup_B; break; default: EyeCups = EyeCup_A; break; } return true; } else if (OVR_strcmp(prop, "LL") == 0) { LL = atoi(sval); return true; } else if (OVR_strcmp(prop, "LR") == 0) { LR = atoi(sval); return true; } else if (OVR_strcmp(prop, "RL") == 0) { RL = atoi(sval); return true; } else if (OVR_strcmp(prop, "RR") == 0) { RR = atoi(sval); return true; } return Profile::ParseProperty(prop, sval); }
bool ProfileManager::CreateUser(const char* user, const char* name) { Lock::Locker lockScope(&ProfileLock); if (ProfileCache == NULL) { // Load the cache LoadCache(true); if (ProfileCache == NULL) return false; } JSON* users = ProfileCache->GetItemByName("Users"); if (users == NULL) { // Generate the User section users = JSON::CreateArray(); ProfileCache->AddItem("Users", users); //TODO: Insert this before the TaggedData } // Search for the pre-existence of this user JSON* user_item = users->GetFirstItem(); int index = 0; while (user_item) { JSON* userid = user_item->GetItemByName("User"); int compare = OVR_strcmp(user, userid->Value); if (compare == 0) { // The user already exists so simply update the fields JSON* name_item = user_item->GetItemByName("Name"); if (name_item && OVR_strcmp(name, name_item->Value) != 0) { name_item->Value = name; Changed = true; } return true; } else if (compare < 0) { // A new user should be placed before this item break; } user_item = users->GetNextItem(user_item); index++; } // Create and fill the user struct JSON* new_user = JSON::CreateObject(); new_user->AddStringItem(OVR_KEY_USER, user); new_user->AddStringItem(OVR_KEY_NAME, name); // user_item->AddStringItem("Password", password); if (user_item == NULL) users->AddArrayElement(new_user); else users->InsertArrayElement(index, new_user); Changed = true; return true; }
bool HMDState::setFloatArray(const char* propertyName, float values[], unsigned arraySize) { if (!arraySize) { return false; } if (OVR_strcmp(propertyName, "DistortionClearColor") == 0) { CopyFloatArrayWithLimit(RenderState.ClearColor, 4, values, arraySize); return true; } if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetNumberValues, propertyName)) { double* da = new double[arraySize]; for (int i = 0; i < (int)arraySize; ++i) { da[i] = values[i]; } bool result = NetClient::GetInstance()->SetNumberValues(GetNetId(), propertyName, da, arraySize); delete[] da; return result; } return false; }
bool IsInStringArray(const char* a[], const char* key) { for (int i = 0; a[i]; ++i) { if (OVR_strcmp(a[i], key) == 0) return true; } return false; }
// Returns the child item with the given name or NULL if not found JSON * JSON::GetItemByName( const char * name ) { for ( JSON * child = Children.GetFirst(); !Children.IsNull( child ); child = child->pNext ) { if ( OVR_strcmp( child->Name, name ) == 0 ) { return child; } } return 0; }
// Saves a new or existing profile. Returns true on success or false on an // invalid or failed save. bool ProfileManager::Save(const Profile* profile) { Lock::Locker lockScope(&ProfileLock); if (OVR_strcmp(profile->Name, "default") == 0) return false; // don't save a default profile // TODO: I should also verify that this profile type matches the current cache if (CacheDevice == Profile_Unknown) LoadCache(profile->Type); // Look for the pre-existence of this profile bool added = false; for (unsigned int i=0; i<ProfileCache.GetSize(); i++) { int compare = OVR_strcmp(profile->Name, ProfileCache[i]->Name); if (compare == 0) { // TODO: I should do a proper field comparison to avoid unnecessary // overwrites and file saves // Replace the previous instance with the new profile ProfileCache[i] = *profile->Clone(); added = true; Changed = true; break; } } if (!added) { ProfileCache.PushBack(*profile->Clone()); if (ProfileCache.GetSize() == 1) CacheDevice = profile->Type; Changed = true; } return true; }
bool Profile::ParseProperty(const char* prop, const char* sval) { if (OVR_strcmp(prop, "Name") == 0) { OVR_strcpy(Name, MaxNameLen, sval); return true; } else if (OVR_strcmp(prop, "CloudUser") == 0) { OVR_strcpy(CloudUser, MaxNameLen, sval); return true; } else if (OVR_strcmp(prop, "Gender") == 0) { if (OVR_strcmp(sval, "Male") == 0) Gender = Gender_Male; else if (OVR_strcmp(sval, "Female") == 0) Gender = Gender_Female; else Gender = Gender_Unspecified; return true; } else if (OVR_strcmp(prop, "PlayerHeight") == 0) { PlayerHeight = (float)atof(sval); return true; } else if (OVR_strcmp(prop, "IPD") == 0) { IPD = (float)atof(sval); return true; } else if (OVR_strcmp(prop, "NeckEyeHori") == 0) { NeckEyeHori = (float)atof(sval); return true; } else if (OVR_strcmp(prop, "NeckEyeVert") == 0) { NeckEyeVert = (float)atof(sval); return true; } return false; }
bool ProfileManager::HasProfile(ProfileType device, const char* name) { Lock::Locker lockScope(&ProfileLock); if (CacheDevice == Profile_Unknown) LoadCache(device); for (unsigned i = 0; i< ProfileCache.GetSize(); i++) { if (ProfileCache[i] && OVR_strcmp(ProfileCache[i]->Name, name) == 0) return true; } return false; }
bool RiftDKHDProfile::ParseProperty(const char* prop, const char* sval) { if (OVR_strcmp(prop, "EyeCup") == 0) { switch (sval[0]) { case 'C': EyeCups = EyeCup_C; break; case 'B': EyeCups = EyeCup_B; break; default: EyeCups = EyeCup_A; break; } return true; } return HMDProfile::ParseProperty(prop, sval); }
bool ProfileManager::RemoveUser(const char* user) { Lock::Locker lockScope(&ProfileLock); if (ProfileCache == NULL) { // Load the cache LoadCache(false); if (ProfileCache == NULL) return true; } JSON* users = ProfileCache->GetItemByName("Users"); if (users == NULL) return true; // Remove this user from the User table JSON* user_item = users->GetFirstItem(); while (user_item) { JSON* userid = user_item->GetItemByName("User"); if (OVR_strcmp(user, userid->Value) == 0) { // Delete the user entry user_item->RemoveNode(); user_item->Release(); Changed = true; break; } user_item = users->GetNextItem(user_item); } // Now remove all data entries with this user tag JSON* tagged_data = ProfileCache->GetItemByName("TaggedData"); Array<JSON*> user_items; FilterTaggedData(tagged_data, "User", user, user_items); for (unsigned int i=0; i<user_items.GetSize(); i++) { user_items[i]->RemoveNode(); user_items[i]->Release(); Changed = true; } return Changed; }
// Returns a profile object for a particular device and user name. The returned // memory should be encapsulated in a Ptr<> object or released after use. Returns // NULL if the profile is not found Profile* ProfileManager::LoadProfile(ProfileType device, const char* user) { if (user == NULL) return NULL; Lock::Locker lockScope(&ProfileLock); if (CacheDevice == Profile_Unknown) LoadCache(device); for (unsigned int i=0; i<ProfileCache.GetSize(); i++) { if (OVR_strcmp(user, ProfileCache[i]->Name) == 0) { // Found the requested user profile Profile* profile = ProfileCache[i]; return profile->Clone(); } } return NULL; }
// Returns the child item with the given name or NULL if not found JSON* JSON::GetItemByName(const char* name) { JSON* child = 0; if (!Children.IsEmpty()) { child = Children.GetFirst(); while (OVR_strcmp(child->Name, name) != 0) { if (Children.IsNull(child->pNext)) { child = 0; break; } child = child->pNext; } } return child; }
// Poplulates 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(ProfileType device) { Lock::Locker lockScope(&ProfileLock); ClearCache(); String path = GetProfilePath(false); Ptr<JSON> root = *JSON::Load(path); if (!root || root->GetItemCount() < 3) return; // First read the file type and version to make sure this is a valid file JSON* item0 = root->GetFirstItem(); JSON* item1 = root->GetNextItem(item0); JSON* item2 = root->GetNextItem(item1); if (OVR_strcmp(item0->Name, "Oculus Profile Version") == 0) { // In the future I may need to check versioning to determine parse method } else { return; } DefaultProfile = item1->Value; // Read the number of profiles int profileCount = (int)item2->dValue; JSON* profileItem = item2; for (int p=0; p<profileCount; p++) { profileItem = profileItem->GetNextItem(profileItem); if (!profileItem) break; // Read the required Name field const char* profileName; JSON* item = profileItem->GetFirstItem(); if (item && (OVR_strcmp(item->Name, "Name") == 0)) { profileName = item->Value; } else { return; // invalid field } const char* deviceName = 0; bool deviceFound = false; Ptr<Profile> profile = *CreateProfileObject(profileName, device, &deviceName); // Read the base profile fields. if (profile) { while (item = profileItem->GetNextItem(item), item) { if (item->Type != JSON_Object) { profile->ParseProperty(item->Name, item->Value); } else { // Search for the matching device to get device specific fields if (!deviceFound && OVR_strcmp(item->Name, deviceName) == 0) { deviceFound = true; for (JSON* deviceItem = item->GetFirstItem(); deviceItem; deviceItem = item->GetNextItem(deviceItem)) { profile->ParseProperty(deviceItem->Name, deviceItem->Value); } } } } } // Add the new profile if (deviceFound) ProfileCache.PushBack(profile); } CacheDevice = device; }
unsigned HMDState::getFloatArray(const char* propertyName, float values[], unsigned arraySize) { if (arraySize) { if (OVR_strcmp(propertyName, "ScreenSize") == 0) { float data[2] = { OurHMDInfo.ScreenSizeInMeters.w, OurHMDInfo.ScreenSizeInMeters.h }; return CopyFloatArrayWithLimit(values, arraySize, data, 2); } else if (OVR_strcmp(propertyName, "DistortionClearColor") == 0) { return CopyFloatArrayWithLimit(values, arraySize, RenderState.ClearColor, 4); } else if (OVR_strcmp(propertyName, "DK2Latency") == 0) { if (OurHMDInfo.HmdType < HmdType_DK2) { return 0; } OutputLatencyTimings timings; ScreenLatencyTracker.GetLatencyTimings(timings); if (arraySize > 0) { switch (arraySize) { default: values[4] = (float)timings.ErrorTimewarp; // Fall-thru case 4: values[3] = (float)timings.ErrorRender; // Fall-thru case 3: values[2] = (float)timings.LatencyPostPresent; // Fall-thru case 2: values[1] = (float)timings.LatencyTimewarp; // Fall-thru case 1: values[0] = (float)timings.LatencyRender; } } return arraySize > 5 ? 5 : arraySize; } else if (OVR_strcmp(propertyName, "NeckModelVector3f") == 0) { // Query the service to grab the HNM. double hnm[3] = {}; int count = NetClient::GetInstance()->GetNumberValues(GetNetId(), propertyName, hnm, (int)arraySize); // If the service is unavailable or returns zero data, if (count < 3 || (hnm[0] == 0.0 && hnm[1] == 0.0 && hnm[2] == 0.0)) { // These are the default values used if the server does not return any data, due to not // being reachable or other errors. OVR_ASSERT(pProfile.GetPtr()); if (pProfile.GetPtr()) { Vector3f neckModel = GetNeckModelFromProfile(pProfile); hnm[0] = neckModel.x; hnm[1] = neckModel.y; hnm[2] = neckModel.z; } } for (unsigned i = 0; i < 3 && i < arraySize; ++i) { values[i] = (float)hnm[i]; } return arraySize > 3 ? 3 : arraySize; } else if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetNumberValues, propertyName)) { // Convert floats to doubles double* da = new double[arraySize]; for (int i = 0; i < (int)arraySize; ++i) { da[i] = values[i]; } int count = NetClient::GetInstance()->GetNumberValues(GetNetId(), propertyName, da, (int)arraySize); for (int i = 0; i < count; ++i) { values[i] = (float)da[i]; } delete[] da; return count; } else if (pProfile) { // TBD: Not quite right. Should update profile interface, so that // we can return 0 in all conditions if property doesn't exist. return pProfile->GetFloatValues(propertyName, values, arraySize); } } return 0; }
bool HMDProfile::ParseProperty(const char* prop, const char* sval) { if (OVR_strcmp(prop, "LL") == 0) { LL = atoi(sval); return true; } else if (OVR_strcmp(prop, "LR") == 0) { LR = atoi(sval); return true; } else if (OVR_strcmp(prop, "RL") == 0) { RL = atoi(sval); return true; } else if (OVR_strcmp(prop, "RR") == 0) { RR = atoi(sval); return true; } if (OVR_strcmp(prop, "EyeCup") == 0) { if ( 0 == OVR_strcmp ( sval, "A" ) ) { EyeCups = EyeCup_BlackA; } else if ( 0 == OVR_strcmp ( sval, "B" ) ) { EyeCups = EyeCup_BlackB; } else if ( 0 == OVR_strcmp ( sval, "C" ) ) { EyeCups = EyeCup_BlackC; } else if ( 0 == OVR_strcmp ( sval, "Orange A" ) ) { EyeCups = EyeCup_OrangeA; } else if ( 0 == OVR_strcmp ( sval, "Red A" ) ) { EyeCups = EyeCup_RedA; } else if ( 0 == OVR_strcmp ( sval, "Blue A" ) ) { EyeCups = EyeCup_BlueA; } else { OVR_ASSERT ( !"Unknown lens type in profile" ); EyeCups = EyeCup_BlackA; } return true; } return Profile::ParseProperty(prop, sval); }
unsigned HMDState::getFloatArray(const char* propertyName, float values[], unsigned arraySize) { if (arraySize) { if (OVR_strcmp(propertyName, "ScreenSize") == 0) { float data[2] = { OurHMDInfo.ScreenSizeInMeters.w, OurHMDInfo.ScreenSizeInMeters.h }; return CopyFloatArrayWithLimit(values, arraySize, data, 2); } else if (OVR_strcmp(propertyName, "DistortionClearColor") == 0) { return CopyFloatArrayWithLimit(values, arraySize, RenderState.ClearColor, 4); } else if (OVR_strcmp(propertyName, "DK2Latency") == 0) { if (OurHMDInfo.HmdType != HmdType_DK2) { return 0; } union { struct X { float latencyRender, latencyTimewarp, latencyPostPresent; } x; float data[3]; } m; static_assert(sizeof(m.x)==sizeof(m.data), "sizeof(struct X) failure"); TimeManager.GetLatencyTimings(m.x.latencyRender, m.x.latencyTimewarp, m.x.latencyPostPresent); return CopyFloatArrayWithLimit(values, arraySize, m.data, 3); } else if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetNumberValues, propertyName)) { // Convert floats to doubles double* da = new double[arraySize]; for (int i = 0; i < (int)arraySize; ++i) { da[i] = values[i]; } int count = NetClient::GetInstance()->GetNumberValues(GetNetId(), propertyName, da, (int)arraySize); for (int i = 0; i < count; ++i) { values[i] = (float)da[i]; } delete[] da; return count; } else if (pProfile) { // TBD: Not quite right. Should update profile interface, so that // we can return 0 in all conditions if property doesn't exist. return pProfile->GetFloatValues(propertyName, values, arraySize); } } return 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); }
// 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); }
// Poplulates 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(ProfileType device) { Lock::Locker lockScope(&ProfileLock); ClearCache(); String path = GetProfilePath(false); Ptr<JSON> root = *JSON::Load(path); if (!root || root->GetItemCount() < 3) return; // First read the file type and version to make sure this is a valid file JSON* item0 = root->GetFirstItem(); JSON* item1 = root->GetNextItem(item0); JSON* item2 = root->GetNextItem(item1); if (item0->Name == "Oculus Profile Version") { int major = atoi(item0->Value.ToCStr()); if (major > MAX_PROFILE_MAJOR_VERSION) return; // don't parse the file on unsupported major version number } else { return; } DefaultProfile = 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 } const char* deviceName = 0; bool deviceFound = false; Ptr<Profile> profile = *CreateProfileObject(profileName, device, &deviceName); // Read the base profile fields. if (profile) { while (item = profileItem->GetNextItem(item), item) { if (item->Type != JSON_Object) { profile->ParseProperty(item->Name, item->Value); } else { // Search for the matching device to get device specific fields if (!deviceFound && deviceName && OVR_strcmp(item->Name, deviceName) == 0) { deviceFound = true; for (JSON* deviceItem = item->GetFirstItem(); deviceItem; deviceItem = item->GetNextItem(deviceItem)) { profile->ParseProperty(deviceItem->Name, deviceItem->Value); } } } } } // Add the new profile ProfileCache.PushBack(profile); } } CacheDevice = device; }
//----------------------------------------------------------------------------- void HIDDeviceManager::OnEvent(int i, int fd) { OVR_UNUSED(i); OVR_UNUSED(fd); // There is a device status change udev_device* hid = udev_monitor_receive_device(HIDMonitor); if (hid) { const char* dev_path = udev_device_get_devnode(hid); const char* action = udev_device_get_action(hid); HIDDeviceDesc device_info; device_info.Path = dev_path; MessageType notify_type; if (OVR_strcmp(action, "add") == 0) { notify_type = Message_DeviceAdded; // Retrieve the device info. This can only be done on a connected // device and is invalid for a disconnected device // Get the USB device hid = udev_device_get_parent_with_subsystem_devtype(hid, "usb", "usb_device"); if (!hid) { return; } const char* path = udev_device_get_syspath(hid); GetDescriptorFromPath(path, &device_info); } else if (OVR_strcmp(action, "remove") == 0) { notify_type = Message_DeviceRemoved; } else { return; } bool error = false; bool deviceFound = false; for (UPInt i = 0; i < NotificationDevices.GetSize(); i++) { if (NotificationDevices[i] && NotificationDevices[i]->OnDeviceNotification(notify_type, &device_info, &error)) { // The notification was for an existing device deviceFound = true; break; } } if (notify_type == Message_DeviceAdded && !deviceFound) { DevManager->DetectHIDDevice(device_info); } udev_device_unref(hid); } }