Esempio n. 1
0
            public HID.UsagePage GetUsagePage(int index, ref HIDItemStateLocal localItemState)
            {
                if (!usagePage.HasValue)
                {
                    var usage = localItemState.GetUsage(index);
                    return((HID.UsagePage)(usage >> 16));
                }

                return((HID.UsagePage)usagePage.Value);
            }
Esempio n. 2
0
            // Wipe state but preserve usageList allocation.
            public static void Reset(ref HIDItemStateLocal state)
            {
                var usageList = state.usageList;

                state = new HIDItemStateLocal();
                if (usageList != null)
                {
                    usageList.Clear();
                    state.usageList = usageList;
                }
            }
Esempio n. 3
0
        public unsafe static bool ParseReportDescriptor(byte *bufferPtr, int bufferLength, ref HID.HIDDeviceDescriptor deviceDescriptor)
        {
            // Item state.
            var localItemState  = new HIDItemStateLocal();
            var globalItemState = new HIDItemStateGlobal();

            // Lists where we accumulate the data from the HID items.
            var reports           = new List <HIDReportData>();
            var elements          = new List <HID.HIDElementDescriptor>();
            var collections       = new List <HID.HIDCollectionDescriptor>();
            var currentCollection = -1;

            // Parse the linear list of items.
            var endPtr     = bufferPtr + bufferLength;
            var currentPtr = bufferPtr;

            while (currentPtr < endPtr)
            {
                var firstByte = *currentPtr;

                ////TODO
                if (firstByte == 0xFE)
                {
                    throw new NotImplementedException("long item support");
                }

                // Read item header.
                var itemSize       = (byte)(firstByte & 0x3);
                var itemTypeAndTag = (byte)(firstByte & 0xFC);
                ++currentPtr;

                // Process item.
                switch (itemTypeAndTag)
                {
                // ------------ Global Items --------------
                // These set item state permanently until it is reset.

                // Usage Page
                case (int)HIDItemTypeAndTag.UsagePage:
                    globalItemState.usagePage = ReadData(itemSize, currentPtr, endPtr);
                    break;

                // Report Count
                case (int)HIDItemTypeAndTag.ReportCount:
                    globalItemState.reportCount = ReadData(itemSize, currentPtr, endPtr);
                    break;

                // Report Size
                case (int)HIDItemTypeAndTag.ReportSize:
                    globalItemState.reportSize = ReadData(itemSize, currentPtr, endPtr);
                    break;

                // Report ID
                case (int)HIDItemTypeAndTag.ReportID:
                    globalItemState.reportId = ReadData(itemSize, currentPtr, endPtr);
                    break;

                // Logical Minimum
                case (int)HIDItemTypeAndTag.LogicalMinimum:
                    globalItemState.logicalMinimum = ReadData(itemSize, currentPtr, endPtr);
                    break;

                // Logical Maximum
                case (int)HIDItemTypeAndTag.LogicalMaximum:
                    globalItemState.logicalMaximum = ReadData(itemSize, currentPtr, endPtr);
                    break;

                // Physical Minimum
                case (int)HIDItemTypeAndTag.PhysicalMinimum:
                    globalItemState.physicalMinimum = ReadData(itemSize, currentPtr, endPtr);
                    break;

                // Physical Maximum
                case (int)HIDItemTypeAndTag.PhysicalMaximum:
                    globalItemState.physicalMaximum = ReadData(itemSize, currentPtr, endPtr);
                    break;

                // Unit Exponent
                case (int)HIDItemTypeAndTag.UnitExponent:
                    globalItemState.unitExponent = ReadData(itemSize, currentPtr, endPtr);
                    break;

                // Unit
                case (int)HIDItemTypeAndTag.Unit:
                    globalItemState.unit = ReadData(itemSize, currentPtr, endPtr);
                    break;

                // ------------ Local Items --------------
                // These set the state for the very next elements to be generated.

                // Usage
                case (int)HIDItemTypeAndTag.Usage:
                    localItemState.SetUsage(ReadData(itemSize, currentPtr, endPtr));
                    break;

                // Usage Minimum
                case (int)HIDItemTypeAndTag.UsageMinimum:
                    localItemState.usageMinimum = ReadData(itemSize, currentPtr, endPtr);
                    break;

                // Usage Maximum
                case (int)HIDItemTypeAndTag.UsageMaximum:
                    localItemState.usageMaximum = ReadData(itemSize, currentPtr, endPtr);
                    break;

                // ------------ Main Items --------------
                // These emit things into the descriptor based on the local and global item state.

                // Collection
                case (int)HIDItemTypeAndTag.Collection:

                    // Start new collection.
                    var parentCollection = currentCollection;
                    currentCollection = collections.Count;
                    collections.Add(new HID.HIDCollectionDescriptor
                    {
                        type       = (HID.HIDCollectionType)ReadData(itemSize, currentPtr, endPtr),
                        parent     = parentCollection,
                        usagePage  = globalItemState.GetUsagePage(0, ref localItemState),
                        usage      = localItemState.GetUsage(0),
                        firstChild = elements.Count
                    });

                    HIDItemStateLocal.Reset(ref localItemState);
                    break;

                // EndCollection
                case (int)HIDItemTypeAndTag.EndCollection:
                    if (currentCollection == -1)
                    {
                        return(false);
                    }

                    // Close collection.
                    var collection = collections[currentCollection];
                    collection.childCount          = elements.Count - collection.firstChild;
                    collections[currentCollection] = collection;

                    // Switch back to parent collection (if any).
                    currentCollection = collection.parent;

                    HIDItemStateLocal.Reset(ref localItemState);
                    break;

                // Input/Output/Feature
                case (int)HIDItemTypeAndTag.Input:
                case (int)HIDItemTypeAndTag.Output:
                case (int)HIDItemTypeAndTag.Feature:

                    // Determine report type.
                    var reportType = itemTypeAndTag == (int)HIDItemTypeAndTag.Input
                            ? HID.HIDReportType.Input
                            : itemTypeAndTag == (int)HIDItemTypeAndTag.Output
                            ? HID.HIDReportType.Output
                            : HID.HIDReportType.Feature;

                    // Find report.
                    var reportIndex = HIDReportData.FindOrAddReport(globalItemState.reportId, reportType, reports);
                    var report      = reports[reportIndex];

                    // If we have a report ID, then reports start with an 8 byte report ID.
                    // Shift our offsets accordingly.
                    if (report.currentBitOffset == 0 && globalItemState.reportId.HasValue)
                    {
                        report.currentBitOffset = 8;
                    }

                    // Add elements to report.
                    var reportCount = globalItemState.reportCount.GetValueOrDefault(1);
                    var flags       = ReadData(itemSize, currentPtr, endPtr);
                    for (var i = 0; i < reportCount; ++i)
                    {
                        var element = new HID.HIDElementDescriptor
                        {
                            usage              = localItemState.GetUsage(i) & 0xFFFF, // Mask off usage page, if set.
                            usagePage          = globalItemState.GetUsagePage(i, ref localItemState),
                            reportType         = reportType,
                            reportSizeInBits   = globalItemState.reportSize.GetValueOrDefault(8),
                            reportOffsetInBits = report.currentBitOffset,
                            reportId           = globalItemState.reportId.GetValueOrDefault(1),
                            flags              = (HID.HIDElementFlags)flags,
                            logicalMin         = globalItemState.logicalMinimum.GetValueOrDefault(0),
                            logicalMax         = globalItemState.logicalMaximum.GetValueOrDefault(0),
                            physicalMin        = globalItemState.GetPhysicalMin(),
                            physicalMax        = globalItemState.GetPhysicalMax(),
                            unitExponent       = globalItemState.unitExponent.GetValueOrDefault(0),
                            unit = globalItemState.unit.GetValueOrDefault(0),
                        };
                        report.currentBitOffset += element.reportSizeInBits;
                        elements.Add(element);
                    }
                    reports[reportIndex] = report;

                    HIDItemStateLocal.Reset(ref localItemState);
                    break;
                }

                if (itemSize == 3)
                {
                    currentPtr += 4;
                }
                else
                {
                    currentPtr += itemSize;
                }
            }

            deviceDescriptor.elements    = elements.ToArray();
            deviceDescriptor.collections = collections.ToArray();

            // Set usage and usage page on device descriptor to what's
            // on the toplevel application collection.
            foreach (var collection in collections)
            {
                if (collection.parent == -1 && collection.type == HID.HIDCollectionType.Application)
                {
                    deviceDescriptor.usage     = collection.usage;
                    deviceDescriptor.usagePage = collection.usagePage;
                    break;
                }
            }

            return(true);
        }