nuclear@0: /************************************************************************************ nuclear@0: nuclear@0: Filename : OVR_System.cpp nuclear@0: Content : General kernel initialization/cleanup, including that nuclear@0: of the memory allocator. nuclear@0: Created : September 19, 2012 nuclear@0: Notes : nuclear@0: nuclear@0: Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. nuclear@0: nuclear@0: Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); nuclear@0: you may not use the Oculus VR Rift SDK except in compliance with the License, nuclear@0: which is provided at the time of installation or download, or which nuclear@0: otherwise accompanies this software in either electronic or hard copy form. nuclear@0: nuclear@0: You may obtain a copy of the License at nuclear@0: nuclear@0: http://www.oculusvr.com/licenses/LICENSE-3.2 nuclear@0: nuclear@0: Unless required by applicable law or agreed to in writing, the Oculus VR SDK nuclear@0: distributed under the License is distributed on an "AS IS" BASIS, nuclear@0: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. nuclear@0: See the License for the specific language governing permissions and nuclear@0: limitations under the License. nuclear@0: nuclear@0: ************************************************************************************/ nuclear@0: nuclear@0: #include "OVR_SerialFormat.h" nuclear@0: nuclear@0: #ifdef SERIAL_FORMAT_UNIT_TEST nuclear@0: #include "Kernel/OVR_Log.h" nuclear@0: #endif nuclear@0: nuclear@0: namespace OVR { nuclear@0: nuclear@0: nuclear@0: //// Serial Format Detection nuclear@0: nuclear@0: SerialFormatType DetectBufferFormat(uint8_t firstByte, int sizeInBytes) nuclear@0: { nuclear@0: switch (firstByte) nuclear@0: { nuclear@0: case SerialFormatType_DK2: nuclear@0: if (sizeInBytes == 12) nuclear@0: { nuclear@0: return SerialFormatType_DK2; nuclear@0: } nuclear@0: break; nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: return SerialFormatType_Invalid; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //// DK2 Helpers nuclear@0: nuclear@0: static bool ValidDK2ProductId(int x) nuclear@0: { nuclear@0: switch (x) nuclear@0: { nuclear@0: case DK2ProductId_DK1: nuclear@0: case DK2ProductId_DK2: nuclear@0: case DK2ProductId_Refurb: nuclear@0: return true; nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: static bool ValidDK2PartId(int x) nuclear@0: { nuclear@0: switch (x) nuclear@0: { nuclear@0: case DK2PartId_HMD: nuclear@0: case DK2PartId_PTC: nuclear@0: case DK2PartId_Carton: nuclear@0: return true; nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //// DK2BinarySerialFormat nuclear@0: nuclear@0: bool DK2BinarySerialFormat::FromBuffer(const uint8_t buffer[12], bool allowUnknownTypes) nuclear@0: { nuclear@0: // Format Type must be 0 nuclear@0: nuclear@0: int formatType = buffer[0]; nuclear@0: nuclear@0: if (formatType != SerialFormatType_DK2) nuclear@0: { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: // Product Id nuclear@0: nuclear@0: int productId = buffer[1] >> 4; nuclear@0: nuclear@0: if (!allowUnknownTypes && !ValidDK2ProductId(productId)) nuclear@0: { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: ProductId = (DK2ProductId)productId; nuclear@0: nuclear@0: // Part Id nuclear@0: nuclear@0: int partId = buffer[1] & 15; nuclear@0: nuclear@0: if (!allowUnknownTypes && !ValidDK2PartId(partId)) nuclear@0: { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: PartId = (DK2PartId)partId; nuclear@0: nuclear@0: // Minutes Since Epoch (May 1, 2014) nuclear@0: nuclear@0: MinutesSinceEpoch = buffer[4] | ((uint32_t)buffer[3] << 8) | ((uint32_t)buffer[2] << 16); nuclear@0: nuclear@0: // Unit number on that day nuclear@0: nuclear@0: UnitNumber = buffer[6] | ((uint32_t)buffer[5] << 8); nuclear@0: nuclear@0: // Hash of MAC address nuclear@0: nuclear@0: MacHash[0] = buffer[7]; nuclear@0: MacHash[1] = buffer[8]; nuclear@0: MacHash[2] = buffer[9]; nuclear@0: MacHash[3] = buffer[10]; nuclear@0: MacHash[4] = buffer[11]; nuclear@0: nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: void DK2BinarySerialFormat::ToBuffer(uint8_t buffer[12]) nuclear@0: { nuclear@0: // Serialize to buffer nuclear@0: buffer[0] = SerialFormatType_DK2; nuclear@0: buffer[1] = (uint8_t)((ProductId << 4) | (PartId)); nuclear@0: buffer[2] = (uint8_t)(MinutesSinceEpoch >> 16); nuclear@0: buffer[3] = (uint8_t)(MinutesSinceEpoch >> 8); nuclear@0: buffer[4] = (uint8_t)MinutesSinceEpoch; nuclear@0: buffer[5] = (uint8_t)(UnitNumber >> 8); nuclear@0: buffer[6] = (uint8_t)UnitNumber; nuclear@0: nuclear@0: buffer[7] = MacHash[0]; nuclear@0: buffer[8] = MacHash[1]; nuclear@0: buffer[9] = MacHash[2]; nuclear@0: buffer[10] = MacHash[3]; nuclear@0: buffer[11] = MacHash[4]; nuclear@0: } nuclear@0: nuclear@0: bool DK2BinarySerialFormat::operator==(const DK2BinarySerialFormat& rhs) nuclear@0: { nuclear@0: if (ProductId != rhs.ProductId) nuclear@0: return false; nuclear@0: if (PartId != rhs.PartId) nuclear@0: return false; nuclear@0: if (MinutesSinceEpoch != rhs.MinutesSinceEpoch) nuclear@0: return false; nuclear@0: if (UnitNumber != rhs.UnitNumber) nuclear@0: return false; nuclear@0: for (int ii = 0; ii < 5; ++ii) nuclear@0: { nuclear@0: if (MacHash[ii] != rhs.MacHash[ii]) nuclear@0: return false; nuclear@0: } nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //// DK2PrintedSerialFormat nuclear@0: nuclear@0: // Base-32 Crockford decoding rules: nuclear@0: // 0 o O => 0 nuclear@0: // 1 i | I L l => 1 nuclear@0: // 2, 3, 4, 5, 6, 7, 8, 9 => 2 - 9 nuclear@0: // a, b, c, d, e, f, g, h => 10 - 17 nuclear@0: // j, k => 18, 19 nuclear@0: // m, n => 20, 21 nuclear@0: // p, q, r, s, t => 22, 23, 24, 25, 26 nuclear@0: // v, w, x, y, z => 27, 28, 29, 30, 31 nuclear@0: static const char Base32FromChar[256] = { nuclear@0: // Null - Unit Separator nuclear@0: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, nuclear@0: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, nuclear@0: // (sp)!"#$%&'()*+,-./ nuclear@0: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, nuclear@0: // 0123456789:;<=>? nuclear@0: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, nuclear@0: // @ - _ (upper case) nuclear@0: -1, 10, 11, 12, 13, 14, 15, 16, 17, 1, 18, 19, 1, 20, 21, 0, nuclear@0: 22, 23, 24, 25, 26, -1, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, nuclear@0: // ` - DEL (lower case) nuclear@0: -1, 10, 11, 12, 13, 14, 15, 16, 17, 1, 18, 19, 1, 20, 21, 0, nuclear@0: 22, 23, 24, 25, 26, -1, 27, 28, 29, 30, 31, -1, 1, -1, -1, -1, nuclear@0: nuclear@0: // Extended ASCII: nuclear@0: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, nuclear@0: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, nuclear@0: nuclear@0: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, nuclear@0: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, nuclear@0: nuclear@0: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, nuclear@0: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, nuclear@0: nuclear@0: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, nuclear@0: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 nuclear@0: }; nuclear@0: nuclear@0: // Base-32 Crockford encoding rules: nuclear@0: // 0-9 => 0-9 nuclear@0: // 10 - 17 => a, b, c, d, e, f, g, h nuclear@0: // 18, 19 => j, k nuclear@0: // 20, 21 => m, n nuclear@0: // 22, 23, 24, 25, 26 => p, q, r, s, t nuclear@0: // 27, 28, 29, 30, 31 => v, w, x, y, z nuclear@0: static const char* CharFromBase32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"; nuclear@0: nuclear@0: bool DK2PrintedSerialFormat::FromBase32(const char* str, bool allowUnknownTypes) nuclear@0: { nuclear@0: // Note: Truncated strings get caught by returning negative values from the table like other invalid characters nuclear@0: nuclear@0: // Product Id nuclear@0: nuclear@0: int productId = Base32FromChar[(unsigned char)str[0]]; nuclear@0: if (productId < 0 || (!allowUnknownTypes && !ValidDK2ProductId(productId))) nuclear@0: { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: ProductId = (DK2ProductId)productId; nuclear@0: nuclear@0: // Label Type nuclear@0: nuclear@0: int labelType = Base32FromChar[(unsigned char)str[1]]; nuclear@0: if (labelType < 0 || (!allowUnknownTypes && !ValidDK2PartId(labelType))) nuclear@0: { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: LabelType = (DK2LabelType)labelType; nuclear@0: nuclear@0: uint8_t dataBytes[7]; nuclear@0: for (int ii = 0; ii < 7; ++ii) nuclear@0: { nuclear@0: int c = Base32FromChar[(unsigned char)str[2 + ii]]; nuclear@0: if (c < 0) return false; nuclear@0: dataBytes[ii] = (uint8_t)c; nuclear@0: } nuclear@0: nuclear@0: // Minutes Since Epoch nuclear@0: nuclear@0: MinutesSinceEpoch = dataBytes[3] | ((uint32_t)dataBytes[2] << 5) | ((uint32_t)dataBytes[1] << 10) | ((uint32_t)dataBytes[0] << 15); nuclear@0: nuclear@0: // Unit Number nuclear@0: nuclear@0: UnitNumber = dataBytes[6] | ((uint32_t)dataBytes[5] << 5) | ((uint32_t)dataBytes[4] << 10); nuclear@0: nuclear@0: // MAC Hash nuclear@0: nuclear@0: for (int ii = 0; ii < 3; ++ii) nuclear@0: { nuclear@0: int c = Base32FromChar[(unsigned char)str[9 + ii]]; nuclear@0: if (c < 0) nuclear@0: { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: MacHashLow[ii] = (uint8_t)c; nuclear@0: } nuclear@0: nuclear@0: // String must be exactly 12 characters nuclear@0: if (str[12] != '\0') nuclear@0: { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: String DK2PrintedSerialFormat::ToBase32() nuclear@0: { nuclear@0: String s; nuclear@0: nuclear@0: s += CharFromBase32[ProductId]; nuclear@0: s += CharFromBase32[LabelType]; nuclear@0: s += CharFromBase32[(MinutesSinceEpoch >> 15) & 31]; nuclear@0: s += CharFromBase32[(MinutesSinceEpoch >> 10) & 31]; nuclear@0: s += CharFromBase32[(MinutesSinceEpoch >> 5) & 31]; nuclear@0: s += CharFromBase32[MinutesSinceEpoch & 31]; nuclear@0: s += CharFromBase32[(UnitNumber >> 10) & 31]; nuclear@0: s += CharFromBase32[(UnitNumber >> 5) & 31]; nuclear@0: s += CharFromBase32[UnitNumber & 31]; nuclear@0: s += CharFromBase32[MacHashLow[0] & 31]; nuclear@0: s += CharFromBase32[MacHashLow[1] & 31]; nuclear@0: s += CharFromBase32[MacHashLow[2] & 31]; nuclear@0: nuclear@0: return s; nuclear@0: } nuclear@0: nuclear@0: bool DK2PrintedSerialFormat::operator==(const DK2PrintedSerialFormat& rhs) nuclear@0: { nuclear@0: if (ProductId != rhs.ProductId) nuclear@0: return false; nuclear@0: if (LabelType != rhs.LabelType) nuclear@0: return false; nuclear@0: if (MinutesSinceEpoch != rhs.MinutesSinceEpoch) nuclear@0: return false; nuclear@0: if (UnitNumber != rhs.UnitNumber) nuclear@0: return false; nuclear@0: for (int ii = 0; ii < 3; ++ii) nuclear@0: { nuclear@0: if (MacHashLow[ii] != rhs.MacHashLow[ii]) nuclear@0: return false; nuclear@0: } nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: bool DK2PrintedSerialFormat::operator==(const DK2BinarySerialFormat& rhs) nuclear@0: { nuclear@0: if (ProductId != rhs.ProductId) nuclear@0: return false; nuclear@0: if (LabelType != rhs.PartId) nuclear@0: return false; nuclear@0: if (MinutesSinceEpoch != rhs.MinutesSinceEpoch) nuclear@0: return false; nuclear@0: if (UnitNumber != rhs.UnitNumber) nuclear@0: return false; nuclear@0: for (int ii = 0; ii < 3; ++ii) nuclear@0: { nuclear@0: if (MacHashLow[ii] != (rhs.MacHash[ii] & 31)) nuclear@0: return false; nuclear@0: } nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: void DK2PrintedSerialFormat::FromBinary(const DK2BinarySerialFormat& bin) nuclear@0: { nuclear@0: ProductId = bin.ProductId; nuclear@0: LabelType = bin.PartId; nuclear@0: MinutesSinceEpoch = bin.MinutesSinceEpoch; nuclear@0: UnitNumber = bin.UnitNumber; nuclear@0: MacHashLow[0] = bin.MacHash[0] & 31; nuclear@0: MacHashLow[1] = bin.MacHash[1] & 31; nuclear@0: MacHashLow[2] = bin.MacHash[2] & 31; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //// Unit Tests nuclear@0: nuclear@0: #ifdef SERIAL_FORMAT_UNIT_TEST nuclear@0: nuclear@0: int DecodeBase32(char ch) nuclear@0: { nuclear@0: if (ch >= '2' && ch <= '9') nuclear@0: return 2 + ch - '2'; nuclear@0: if (ch >= 'a' && ch <= 'h') nuclear@0: return 10 + ch - 'a'; nuclear@0: if (ch >= 'A' && ch <= 'H') nuclear@0: return 10 + ch - 'A'; nuclear@0: if (ch >= 'j' && ch <= 'k') nuclear@0: return 18 + ch - 'j'; nuclear@0: if (ch >= 'J' && ch <= 'K') nuclear@0: return 18 + ch - 'J'; nuclear@0: if (ch >= 'm' && ch <= 'n') nuclear@0: return 20 + ch - 'm'; nuclear@0: if (ch >= 'M' && ch <= 'N') nuclear@0: return 20 + ch - 'M'; nuclear@0: if (ch >= 'p' && ch <= 't') nuclear@0: return 22 + ch - 'p'; nuclear@0: if (ch >= 'P' && ch <= 'T') nuclear@0: return 22 + ch - 'P'; nuclear@0: if (ch >= 'v' && ch <= 'z') nuclear@0: return 27 + ch - 'v'; nuclear@0: if (ch >= 'V' && ch <= 'Z') nuclear@0: return 27 + ch - 'V'; nuclear@0: nuclear@0: switch (ch) nuclear@0: { nuclear@0: case '0': nuclear@0: case 'o': nuclear@0: case 'O': nuclear@0: return 0; nuclear@0: case '1': nuclear@0: case 'i': nuclear@0: case '|': nuclear@0: case 'I': nuclear@0: case 'L': nuclear@0: case 'l': nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@0: void TestSerialFormatStuff() nuclear@0: { nuclear@0: for (int ii = 0; ii < 256; ++ii) nuclear@0: { nuclear@0: OVR_ASSERT(Base32FromChar[ii] == (char)DecodeBase32((char)ii)); nuclear@0: } nuclear@0: nuclear@0: DK2BinarySerialFormat sa; nuclear@0: sa.ProductId = DK2ProductId_DK2; nuclear@0: sa.PartId = DK2PartId_HMD; nuclear@0: sa.MinutesSinceEpoch = 65000; nuclear@0: sa.UnitNumber = 2; nuclear@0: sa.MacHash[0] = 0xa1; nuclear@0: sa.MacHash[1] = 0xb2; nuclear@0: sa.MacHash[2] = 0xc3; nuclear@0: sa.MacHash[3] = 0xd4; nuclear@0: sa.MacHash[4] = 0xe5; nuclear@0: nuclear@0: uint8_t buffer[12]; nuclear@0: sa.ToBuffer(buffer); nuclear@0: nuclear@0: DK2BinarySerialFormat sb; nuclear@0: bool success = sb.FromBuffer(buffer); nuclear@0: OVR_ASSERT(success); nuclear@0: OVR_UNUSED(success); nuclear@0: nuclear@0: OVR_ASSERT(sa == sb); nuclear@0: nuclear@0: DK2PrintedSerialFormat psn; nuclear@0: psn.FromBinary(sb); nuclear@0: nuclear@0: OVR_ASSERT(psn == sa); nuclear@0: nuclear@0: String s = psn.ToBase32(); nuclear@0: nuclear@0: DK2PrintedSerialFormat psn2; nuclear@0: psn2.FromBase32(s.ToCStr()); nuclear@0: nuclear@0: OVR_ASSERT(psn == psn2); nuclear@0: } nuclear@0: nuclear@0: #endif // SERIAL_FORMAT_UNIT_TEST nuclear@0: nuclear@0: nuclear@0: } // OVR