MODULE UsbHidReport;
IMPORT SYSTEM, UsbHidUP, KernelLog;
CONST
Debug* = FALSE;
UseUsageDictionaryExt* = TRUE;
MainTypeInput = 0;
MainTypeOutput = 1;
MainTypeFeature = 2;
UndefinedState* = -1;
TYPE
MainType* = LONGINT;
HidCollection*= POINTER TO RECORD
type*: LONGINT;
usagePage*: LONGINT;
usage*: LONGINT;
firstCollection: HidCollection;
lastCollection: HidCollection;
firstReport*: HidReport;
lastReport: HidReport;
next: HidCollection;
END;
UsageTuple* = POINTER TO RECORD
usageID*: LONGINT;
usagePage*: LONGINT;
usageValue*: LONGINT;
END;
UsageDictElement*= RECORD
firstUsageID*: LONGINT;
nofFollowing*: LONGINT;
otherUsagePage*: LONGINT;
END;
UsageDictionary*= POINTER TO RECORD
elements*: POINTER TO ARRAY OF UsageDictElement;
END;
PtrToUsageTupleArr*= POINTER TO ARRAY OF UsageTuple;
HidReport* = POINTER TO RECORD
next*: HidReport;
reportID*: LONGINT;
usagePage*: LONGINT;
usages*: PtrToUsageTupleArr;
mainState*: LONGINT;
reportSize*: LONGINT;
reportCount*: LONGINT;
reportType*: MainType;
logicalMinimum*: LONGINT;
logicalMaximum*: LONGINT;
physicalMinimum*: LONGINT;
physicalMaximum*: LONGINT;
unitExponent*: LONGINT;
unit*: LONGINT;
supportedUsages*: UsageDictionary;
END;
HidReportIterator*= POINTER TO RECORD
report*: HidReport;
next*: HidReportIterator;
END;
ParentStackItem= POINTER TO RECORD
value: HidCollection;
next: ParentStackItem;
END;
ReportItem*= POINTER TO RECORD
index: LONGINT;
reportID*: LONGINT;
reportItemSize*: LONGINT;
reportItemCount*: LONGINT;
values*: PtrToUsageTupleArr;
next*: ReportItem;
END;
ReportItemQueue* = POINTER TO RECORD
first*: ReportItem;
bitsAlreadyUsed*: LONGINT;
END;
HIDParentList*=OBJECT
VAR
first : ParentStackItem;
PROCEDURE PushFront*(value: HidCollection);
VAR cur : ParentStackItem;
BEGIN
IF (first = NIL) THEN
NEW(first);
first.value := value;
ELSE
NEW(cur);
cur.value := value;
cur.next := first;
first := cur;
END;
END PushFront;
PROCEDURE PopFront*(): HidCollection;
VAR ret : HidCollection;
BEGIN
IF(first=NIL) THEN
ret := NIL;
ELSE
ret := first.value;
first := first.next;
END;
RETURN ret;
END PopFront;
END HIDParentList;
HidReportManager*=OBJECT
VAR
rootCollection, current: HidCollection;
parentList: HIDParentList;
reportItemQueue: ReportItemQueue;
reportIterator: HidReportIterator;
PROCEDURE BeginCollection*(type, usagePage, usage: LONGINT);
VAR newCollection : HidCollection;
BEGIN
NEW(newCollection);
newCollection.type := type;
newCollection.usagePage := usagePage;
newCollection.usage := usage;
IF(current.firstCollection=NIL) THEN
current.firstCollection := newCollection;
current.lastCollection := current.firstCollection;
ELSE
current.lastCollection.next := newCollection;
current.lastCollection := newCollection;
END;
parentList.PushFront(current);
current := newCollection;
END BeginCollection;
PROCEDURE EndCollection*;
VAR ret : HidCollection;
BEGIN
ASSERT(current#rootCollection);
ret := parentList.PopFront();
current := ret;
END EndCollection;
PROCEDURE GetCollection*(usagePage, usage: LONGINT): HidCollection;
VAR collIterator, result : HidCollection;
BEGIN
ASSERT(rootCollection.firstCollection#NIL);
collIterator := rootCollection.firstCollection;
WHILE (collIterator#NIL) DO
result := FindColl(collIterator, usagePage, usage);
IF result#NIL THEN
RETURN result;
END;
collIterator := collIterator.next;
END;
RETURN NIL;
END GetCollection;
PROCEDURE FindColl(hidColl: HidCollection; usagePage, usage: LONGINT): HidCollection;
VAR rv : HidCollection;
BEGIN
IF (hidColl=NIL) THEN RETURN NIL; END;
rv := NIL;
IF Debug THEN
KernelLog.String("parsing item: UsagePage"); KernelLog.Int(hidColl.usagePage,5); KernelLog.String(" Usage("); KernelLog.Int(hidColl.usage,0); KernelLog.String("):"); UsbHidUP.PrintUsagePage(hidColl.usagePage,hidColl.usage); KernelLog.Ln;
END;
IF ((hidColl.usagePage=usagePage)&(hidColl.usage=usage)) THEN
rv := hidColl;
ELSE
IF (hidColl.firstCollection#NIL) THEN
rv := FindColl(hidColl.firstCollection, usagePage, usage);
IF((rv=NIL) & (hidColl.next#NIL)) THEN
rv := FindColl(hidColl.next, usagePage, usage);
END;
END;
END;
RETURN rv;
END FindColl;
PROCEDURE GetUsage*(usagePage, usage: LONGINT; hidCollection: HidCollection; VAR report: HidReport): UsageTuple;
VAR
cursor : HidReport;
usageTuple : UsageTuple;
subColl : HidCollection;
i,
tupleLength : LONGINT;
BEGIN
ASSERT(hidCollection#NIL);
cursor := hidCollection.firstReport;
WHILE(cursor#NIL) DO
IF((cursor.usagePage= usagePage) & (cursor.usages#NIL)) THEN
tupleLength := LEN(cursor.usages);
FOR i:= 0 TO tupleLength-1 DO
IF (cursor.usages[i].usageID=usage) THEN
usageTuple := cursor.usages[i];
report := cursor;
RETURN usageTuple;
END;
END;
IF UseUsageDictionaryExt THEN
IF cursor.supportedUsages # NIL THEN
FOR i:=0 TO LEN(cursor.supportedUsages.elements)-1 DO
IF (cursor.supportedUsages.elements[i].firstUsageID<=usage) &
(cursor.supportedUsages.elements[i].firstUsageID+
cursor.supportedUsages.elements[i].nofFollowing>=usage) THEN
usageTuple := cursor.usages[0];
report := cursor;
IF Debug THEN
KernelLog.String("searching in dictionary: firstUsage, lastUsage, val");
KernelLog.Int(cursor.supportedUsages.elements[i].firstUsageID,10);
KernelLog.Int(cursor.supportedUsages.elements[i].nofFollowing+cursor.supportedUsages.elements[i].firstUsageID,10);
KernelLog.Int(usage,10);
END;
KernelLog.Ln;
RETURN usageTuple;
END;
END;
END;
END;
END;
cursor := cursor.next;
END;
subColl := hidCollection.firstCollection;
WHILE(subColl#NIL) DO
usageTuple := GetUsage(usagePage, usage, subColl, report);
IF (usageTuple#NIL) THEN
RETURN usageTuple;
ELSE
subColl := subColl.next;
END;
END;
RETURN NIL;
END GetUsage;
PROCEDURE GetDictKey*(index: LONGINT; dict: UsageDictionary):UsageTuple;
VAR
counter, i : LONGINT;
rv : UsageTuple;
BEGIN
ASSERT(dict.elements#NIL);
NEW(rv);
FOR i:=0 TO LEN(dict.elements)-1 DO
IF (index>counter+dict.elements[i].nofFollowing) THEN
IF Debug THEN
KernelLog.String("looking in "); KernelLog.Int(dict.elements[i].firstUsageID,0); KernelLog.String("..");
KernelLog.Int(dict.elements[i].firstUsageID+dict.elements[i].nofFollowing,0);KernelLog.Ln;
END;
counter := counter + 1 + dict.elements[i].nofFollowing;
ELSE
IF Debug THEN
KernelLog.String("found in interval "); KernelLog.Int(dict.elements[i].firstUsageID,0); KernelLog.String("..");
KernelLog.Int(dict.elements[i].firstUsageID+dict.elements[i].nofFollowing,0);KernelLog.Ln;
END;
rv.usageID := dict.elements[i].firstUsageID+index-counter;
rv.usagePage := dict.elements[i].otherUsagePage;
RETURN rv;
END;
END;
RETURN rv;
END GetDictKey;
PROCEDURE DictSize*(dict: UsageDictionary):LONGINT;
VAR sum, i: LONGINT;
BEGIN
ASSERT(dict.elements#NIL);
FOR i:=0 TO LEN(dict.elements)-1 DO
sum := sum + 1 + dict.elements[i].nofFollowing;
END;
RETURN sum;
END DictSize;
PROCEDURE OnTopLevel*(): BOOLEAN;
BEGIN
RETURN current=rootCollection;
END OnTopLevel;
PROCEDURE AddReport*(report : HidReport);
VAR
newReportItem: ReportItem;
BEGIN
IF (current.firstReport=NIL) THEN
current.firstReport:= report;
current.lastReport:= current.firstReport;
ELSE
current.lastReport.next := report;
current.lastReport := report;
END;
IF Debug THEN
KernelLog.String("Report added"); KernelLog.Ln;
END;
NEW(newReportItem);
newReportItem.reportID := report.reportID;
newReportItem.reportItemSize := report.reportSize;
newReportItem.reportItemCount := report.reportCount;
newReportItem.values := report.usages;
IF Debug THEN
KernelLog.String("Add report:");KernelLog.Ln;
KernelLog.String(" index: "); KernelLog.Int(newReportItem.index,0); KernelLog.Ln;
KernelLog.String(" reportItemSize: "); KernelLog.Int(newReportItem.reportItemSize,0); KernelLog.Ln;
KernelLog.String(" reportItemCount: "); KernelLog.Int(newReportItem.reportItemCount,0); KernelLog.Ln;
KernelLog.String(" index: "); KernelLog.Int(newReportItem.index,0); KernelLog.Ln;
IF (report.usages=NIL) THEN
KernelLog.String("UsbHidReport::HIDReport.AddReport: found empty usageTupleList"); KernelLog.Ln;
ELSE
KernelLog.String("UsbHidReport::HIDReport.AddReport: found usageTupleList"); KernelLog.Ln;
END;
END;
AddReportItem(newReportItem);
AddReportIterator(report);
END AddReport;
PROCEDURE AddReportItem(reportItem: ReportItem);
VAR
cursor: ReportItem;
i: LONGINT;
BEGIN
IF (reportItemQueue.first=NIL) THEN
reportItemQueue.bitsAlreadyUsed:=0;
reportItemQueue.first := reportItem;
ELSE
cursor := reportItemQueue.first;
WHILE(cursor.next#NIL) DO
cursor := cursor.next;
END;
cursor.next := reportItem;
END;
reportItemQueue.bitsAlreadyUsed:= reportItemQueue.bitsAlreadyUsed + (reportItem.reportItemSize*reportItem.reportItemCount);
IF Debug THEN
KernelLog.String("UsbHidReport:HIDReport.AddReportItem: Successfully added report item. Updated bitsAlreadyUsed: ");
KernelLog.Int(reportItemQueue.bitsAlreadyUsed,0); KernelLog.Ln;
cursor := reportItemQueue.first;
WHILE (cursor.next#NIL) DO
cursor := cursor.next;
END;
IF (cursor.values#NIL) THEN
FOR i:=0 TO cursor.reportItemCount-1 DO
KernelLog.String("AddReportItem: cursor.values[i].usageID: "); KernelLog.Int(cursor.values[i].usageID,0); KernelLog.Ln;
END;
END;
END;
END AddReportItem;
PROCEDURE AddReportIterator(report: HidReport);
VAR cursor: HidReportIterator;
BEGIN
IF(reportIterator=NIL) THEN
NEW(reportIterator);
reportIterator.report := report;
ELSE
cursor := reportIterator;
WHILE cursor.next#NIL DO
cursor := cursor.next;
END;
NEW(cursor.next);
cursor.next.report := report;
END;
END AddReportIterator;
PROCEDURE UsesReportIDMechanism*(): BOOLEAN;
VAR cursor: HidReportIterator;
BEGIN
cursor := reportIterator;
WHILE(cursor#NIL) DO
IF(cursor.report.reportID#UndefinedState) THEN
RETURN TRUE;
END;
cursor := cursor.next;
END;
RETURN FALSE;
END UsesReportIDMechanism;
PROCEDURE GetReportItemQueue*(): ReportItemQueue;
BEGIN
RETURN reportItemQueue;
END GetReportItemQueue;
PROCEDURE PrintReportState*;
BEGIN
IF rootCollection#NIL THEN
PrintReport(rootCollection);
END;
END PrintReportState;
PROCEDURE PrintReport(collection:HidCollection);
VAR
subCollectionCursor: HidCollection;
reportCursor: HidReport;
i: LONGINT;
mainState: SET;
BEGIN
reportCursor := collection.firstReport;
WHILE reportCursor#NIL DO
KernelLog.String("+"); KernelLog.Ln;
KernelLog.String(" reportID: "); KernelLog.Int(reportCursor.reportID,0); KernelLog.Ln;
KernelLog.String(" usagePage("); KernelLog.Int(reportCursor.usagePage,0);
KernelLog.String("): "); UsbHidUP.PrintUsagePageName(reportCursor.usagePage); KernelLog.Ln;
KernelLog.String(" reportSize: "); KernelLog.Int(reportCursor.reportSize,0); KernelLog.Ln;
KernelLog.String(" reportCount: "); KernelLog.Int(reportCursor.reportCount,0); KernelLog.Ln;
KernelLog.String(" reportType: ");
IF reportCursor.reportType=MainTypeInput THEN
KernelLog.String("MainTypeInput");
ELSE
IF reportCursor.reportType=MainTypeOutput THEN
KernelLog.String("MainTypeOutput");
ELSE
IF reportCursor.reportType=MainTypeFeature THEN
KernelLog.String("MainTypeFeature");
ELSE
KernelLog.String("MainTypeUndefined");
END;
END;
END;
KernelLog.Ln;
mainState:= SYSTEM.VAL(SET,reportCursor.mainState);
KernelLog.String(" mainState: "); KernelLog.Bits(mainState,0,9); KernelLog.Ln;
IF (0 IN mainState) THEN KernelLog.String(" Constant (no usages!)") ELSE KernelLog.String(" Data") END; KernelLog.Ln;
IF (1 IN mainState) THEN KernelLog.String(" Variable") ELSE KernelLog.String(" Array") END; KernelLog.Ln;
IF (2 IN mainState) THEN KernelLog.String(" Relative") ELSE KernelLog.String(" Absolute") END; KernelLog.Ln;
IF (3 IN mainState) THEN KernelLog.String(" Wrap") ELSE KernelLog.String(" No Wrap") END; KernelLog.Ln;
IF (4 IN mainState) THEN KernelLog.String(" Non Linear") ELSE KernelLog.String(" Linear") END; KernelLog.Ln;
IF (5 IN mainState) THEN KernelLog.String(" No Preferred") ELSE KernelLog.String(" Preferred State") END; KernelLog.Ln;
IF (6 IN mainState) THEN KernelLog.String(" Null State") ELSE KernelLog.String(" No Null Position") END; KernelLog.Ln;
IF (7 IN mainState) THEN KernelLog.String(" Volatile") ELSE KernelLog.String(" Non Volatile") END; KernelLog.Ln;
IF (8 IN mainState) THEN KernelLog.String(" Buffered Bytes") ELSE KernelLog.String(" Bit Field"); END; KernelLog.Ln;
KernelLog.String(" logicalMinimum: "); KernelLog.Int(reportCursor.logicalMinimum,0); KernelLog.Ln;
KernelLog.String(" logicalMaximum: "); KernelLog.Int(reportCursor.logicalMaximum,0); KernelLog.Ln;
KernelLog.String(" physicalMinimum: "); KernelLog.Int(reportCursor.physicalMinimum,0); KernelLog.Ln;
KernelLog.String(" physicalMaximum: "); KernelLog.Int(reportCursor.physicalMaximum,0);KernelLog.Ln;
KernelLog.String(" unitExponent: "); KernelLog.Int(reportCursor.unitExponent,0); KernelLog.Ln;
KernelLog.String(" unit"); KernelLog.Int(reportCursor.unit,0); KernelLog.Ln;
IF(reportCursor.usages#NIL) THEN
FOR i:=0 TO LEN(reportCursor.usages)-1 DO
IF(1 IN mainState) THEN
KernelLog.String(" usageID("); KernelLog.Int(reportCursor.usages[i].usageID,0); KernelLog.String("): ");
UsbHidUP.PrintUsagePage(reportCursor.usagePage, reportCursor.usages[i].usageID); KernelLog.Ln;
KernelLog.String(" usageValue: "); KernelLog.Int(reportCursor.usages[i].usageValue,50); KernelLog.Ln;
ELSE
KernelLog.String(" usageID(");
IF(reportCursor.usages[i].usageValue#0) THEN
UsbHidUP.PrintUsagePage(reportCursor.usagePage, reportCursor.usages[i].usageValue);
ELSE
KernelLog.String("0");
END;
KernelLog.String(") returned"); KernelLog.Ln;
END;
END;
END;
KernelLog.Ln;
reportCursor := reportCursor.next;
END;
subCollectionCursor := collection.firstCollection;
WHILE subCollectionCursor#NIL DO
PrintReport(subCollectionCursor);
subCollectionCursor := subCollectionCursor.next;
END;
END PrintReport;
PROCEDURE &Init*;
BEGIN
NEW(rootCollection);
current := rootCollection;
NEW(parentList);
NEW(reportItemQueue);
END Init;
END HidReportManager;
END UsbHidReport.
SystemTools.Free UsbHidReport~