MODULE UsbHidParser;
IMPORT SYSTEM, KernelLog, UsbHid, Usbdi, UsbHidErrors, HidParserExt := UsbHidParserExt, UsbHidReport;
CONST
Trace* = FALSE;
Debug* = FALSE;
ShortItemBTypeMain = 0H;
ShortItemBTypeGlobal = 1H;
ShortItemBTypeLocal = 2H;
ShortItemBTypeReserved = 3H;
UndefinedState* = UsbHidReport.UndefinedState;
StatusCodeOk* = 1;
StatusCodeFailed* = 0;
IDUsagePage = HidParserExt.ParseIDUsagePage;
IDLogicalMinimum = HidParserExt.ParseIDLogicalMinimum;
IDLogicalMaximum = HidParserExt.ParseIDLogicalMaximum;
IDPhysicalMinimum = HidParserExt.ParseIDPhysicalMinimum;
IDPhysicalMaximum = HidParserExt.ParseIDPhysicalMaximum;
IDUnitExponent = HidParserExt.ParseIDUnitExponent;
IDUnit = HidParserExt.ParseIDUnit;
IDReportSize = HidParserExt.ParseIDReportSize;
IDReportID = HidParserExt.ParseIDReportID;
IDReportCount = HidParserExt.ParseIDReportCount;
LengthGlobalState = 10;
IDLocalUsage = HidParserExt.ParseIDUsage;
IDLocalUsageMinimum = HidParserExt.ParseIDUsageMinimum;
IDLocalUsageMaximum = HidParserExt.ParseIDUsageMaximum;
IDLocalDesignatorIndex = HidParserExt.ParseIDDesignatorIndex;
IDLocalDesignatorMinimum = HidParserExt.ParseIDDesignatorMinimum;
IDLocalDesignatorMaximum = HidParserExt.ParseIDDesignatorMaximum;
IDLocalStringIndex = HidParserExt.ParseIDStringIndex-1;
IDLocalStringMinimum = HidParserExt.ParseIDStringMinimum-1;
IDLocalStringMaximum = HidParserExt.ParseIDStringMaximum-1;
IDLocalDelimiter = HidParserExt.ParseIDDelimiter-1;
LengthLocalState = 10;
IDLocalExtUsage = HidParserExt.ParseIDUsage;
IDLocalExtUsageMinimum = HidParserExt.ParseIDUsageMinimum;
IDLocalExtUsageMaximum = HidParserExt.ParseIDUsageMaximum;
LengthExtLocalState = 3;
IDLocalAddStringIndex = 4;
IDMainIsConstant* = HidParserExt.ParseIDDataConstant;
IDMainIsVariable* = HidParserExt.ParseIDArrayVariable;
IDMainIsRelative* = HidParserExt.ParseIDAbsoluteRelative;
IDMainIsWrap* = HidParserExt.ParseIDNoWrapWrap;
IDMainIsNonLinear* = HidParserExt.ParseIDLinearNonLinear;
IDMainIsNoPreferred* = HidParserExt.ParseIDPreferdStateNoPreferd;
IDMainIsNullState* = HidParserExt.ParseIDNoNullPositionNullState;
IDMainIsVolatile* = HidParserExt.ParseIDNonVolatileVolatile;
IDMainIsBufferedBytes* = HidParserExt.ParseIDBitFieldBufferedByte;
IDMainItemInput = 08H;
IDMainItemOutput = 09H;
IDMainItemFeature = 0BH;
IDMainItemCollection = 0AH;
IDMainItemEndCollection = 0CH;
TYPE
Item = RECORD
bSize : LONGINT;
bType : LONGINT;
bTag : LONGINT;
data : LONGINT;
END;
MainState = LONGINT;
GlobalState = POINTER TO RECORD
state : ARRAY LengthGlobalState OF LONGINT;
isReadByMain : ARRAY LengthGlobalState OF BOOLEAN;
next : GlobalState;
END;
LocalState = POINTER TO RECORD
state : ARRAY LengthLocalState OF LONGINT;
ext : ARRAY LengthExtLocalState OF LONGINT;
END;
UsageQueueItem = POINTER TO RECORD
usage : LONGINT;
usagePage : LONGINT;
arrLen : LONGINT;
next : UsageQueueItem;
END;
PtrToUsageTupleArr = UsbHidReport.PtrToUsageTupleArr;
UsageQueue=OBJECT
VAR
first, last : UsageQueueItem;
totalLen : LONGINT;
PROCEDURE Add*(usage, arrLen, usageExt: LONGINT);
BEGIN
IF (last = NIL) THEN
NEW(last);
first := last;
ELSE
NEW(last.next);
last := last.next;
END;
last.usage := usage;
last.usagePage := usageExt;
last.arrLen:= arrLen;
totalLen:= totalLen + arrLen;
END Add;
PROCEDURE CreateUsageDictionary():UsbHidReport.UsageDictionary;
VAR
cursor: UsageQueueItem;
usageQueueCounter, i: LONGINT;
dict: UsbHidReport.UsageDictionary;
BEGIN
cursor := first;
WHILE (cursor # NIL) DO
cursor := cursor.next;
usageQueueCounter := usageQueueCounter + 1;
END;
IF (usageQueueCounter>0) THEN
NEW(dict);
NEW(dict.elements,usageQueueCounter);
cursor := first;
FOR i:= 0 TO usageQueueCounter-1 DO
dict.elements[i].firstUsageID := cursor.usage;
dict.elements[i].otherUsagePage := cursor.usagePage;
dict.elements[i].nofFollowing := cursor.arrLen-1;
cursor := cursor.next;
END;
END;
RETURN dict;
END CreateUsageDictionary;
PROCEDURE CreateUsageTupleArray(reportCount: LONGINT; isArrayFlagSet:BOOLEAN): PtrToUsageTupleArr ;
VAR
i,index: LONGINT;
cursor: UsageQueueItem;
usageArr : PtrToUsageTupleArr ;
BEGIN
IF(totalLen>0) THEN
NEW(usageArr, reportCount);
cursor := first;
index := 0;
WHILE(cursor#NIL) DO
FOR i:=0 TO cursor.arrLen-1 DO
NEW(usageArr[index]);
IF UsbHidReport.UseUsageDictionaryExt THEN
IF isArrayFlagSet THEN
usageArr[index].usageID := UndefinedState;
ELSE
usageArr[index].usageID := cursor.usage+i;
END;
ELSE
usageArr[index].usageID := cursor.usage+i;
END;
IF UsbHidReport.Debug THEN
KernelLog.String("Created usage entry for usage "); KernelLog.Int(usageArr[index].usageID,0); KernelLog.Ln;
END;
IF (index>=reportCount-1) THEN
RETURN usageArr;
END;
index := index + 1;
END;
IF((cursor.next=NIL)&(reportCount>index)) THEN
i:=0;
WHILE(index<reportCount) DO
NEW(usageArr[index]);
usageArr[index].usageID := cursor.usage + cursor.arrLen+i;
i := i + 1;
index := index+1;
IF Debug THEN
KernelLog.String('UsbHidParser:CreateUsageTupleArray: reportCount>usages, fill up with usage '); KernelLog.Int(cursor.usage+cursor.arrLen+i-1,0);
KernelLog.Ln;
END;
END;
END;
cursor := cursor.next;
END;
ELSE
RETURN NIL;
END;
RETURN usageArr;
END CreateUsageTupleArray;
PROCEDURE EmptyUsageQueue;
BEGIN
first:=NIL;
last:=NIL;
totalLen:= 0;
END EmptyUsageQueue;
PROCEDURE &Init*;
BEGIN
totalLen := 0;
END Init;
END UsageQueue;
TYPE
GlobalStateObject* = OBJECT
VAR
firstGlobalState, globalState, gsCursor : GlobalState;
PROCEDURE State(i:SHORTINT):LONGINT;
BEGIN
IF ((i>=0) & (i < LengthGlobalState)) THEN
RETURN globalState.state[i];
ELSE
RETURN UndefinedState;
END;
END State;
PROCEDURE Push;
VAR i : LONGINT;
BEGIN
NEW(globalState.next);
FOR i:= 0 TO LengthGlobalState-1 DO
globalState.next.state[i] := globalState.state[i];
globalState.next.isReadByMain[i] := globalState.isReadByMain[i];
END;
globalState:=globalState.next;
END Push;
PROCEDURE Pop():BOOLEAN;
BEGIN
IF(globalState=firstGlobalState) THEN
RETURN FALSE;
ELSE
gsCursor := firstGlobalState;
WHILE (gsCursor.next # globalState) DO
gsCursor := gsCursor.next;
END;
globalState := gsCursor;
globalState.next := NIL;
RETURN TRUE;
END;
END Pop;
PROCEDURE CleanGlobalState(data: GlobalState);
BEGIN
data.state[IDUsagePage]:= UndefinedState;
data.state[IDLogicalMinimum]:= UndefinedState;
data.state[IDLogicalMaximum]:= UndefinedState;
data.state[IDPhysicalMinimum]:= UndefinedState;
data.state[IDPhysicalMaximum]:= UndefinedState;
data.state[IDUnitExponent]:= UndefinedState;
data.state[IDUnit]:= UndefinedState;
data.state[IDReportSize]:= UndefinedState;
data.state[IDReportID]:= UndefinedState;
data.state[IDReportCount]:= UndefinedState;
data.isReadByMain[IDUsagePage]:= FALSE;
data.isReadByMain[IDLogicalMinimum]:= FALSE;
data.isReadByMain[IDLogicalMaximum]:= FALSE;
data.isReadByMain[IDPhysicalMinimum]:= FALSE;
data.isReadByMain[IDPhysicalMaximum]:= FALSE;
data.isReadByMain[IDUnitExponent]:= FALSE;
data.isReadByMain[IDUnit]:= FALSE;
data.isReadByMain[IDReportSize]:= FALSE;
data.isReadByMain[IDReportID]:= FALSE;
data.isReadByMain[IDReportCount]:= FALSE;
data.next:= NIL;
END CleanGlobalState;
PROCEDURE SetState( VAR errorList: UsbHidErrors.ErrorList; globalStateField: LONGINT; newValue, itemNr:LONGINT);
BEGIN
IF((globalStateField<0) OR (globalStateField>LengthGlobalState)) THEN
RETURN;
END;
IF(globalState.isReadByMain[globalStateField]=FALSE) THEN
globalState.isReadByMain[globalStateField]:= TRUE;
globalState.state[globalStateField] := newValue;
ELSE
errorList.Add(itemNr, UsbHidErrors.GlobalItemGeneral, 0H);
END;
END SetState;
PROCEDURE ResetGlobalStateFlags;
VAR i : LONGINT;
BEGIN
FOR i:=0 TO LengthGlobalState-1 DO
globalState.isReadByMain[i]:=FALSE;
END;
END ResetGlobalStateFlags;
PROCEDURE VerifyGlobalState( VAR errorList: UsbHidErrors.ErrorList; itemNr: LONGINT):BOOLEAN;
VAR
minReportSize, maxReportSize: LONGINT;
mustStop: BOOLEAN;
BEGIN
mustStop:= FALSE;
IF((globalState.state[IDUsagePage] = UndefinedState) OR
(globalState.state[IDLogicalMinimum] = UndefinedState) OR
(globalState.state[IDLogicalMaximum] = UndefinedState) OR
(globalState.state[IDReportSize] = UndefinedState) OR
(globalState.state[IDReportCount] = UndefinedState)) THEN
errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0H);
mustStop:=TRUE;
END;
IF((globalState.state[IDPhysicalMinimum]#UndefinedState)OR(globalState.state[IDPhysicalMaximum]#UndefinedState)) THEN
IF(globalState.state[IDPhysicalMaximum]=UndefinedState) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemPhysicalMinimum, 0H);
END;
IF(globalState.state[IDPhysicalMinimum]=UndefinedState) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemPhysicalMaximum, 0H);
END;
END;
IF((globalState.state[IDReportSize]>0) & (globalState.state[IDReportSize]<=32)) THEN
minReportSize:=1;
maxReportSize:=SYSTEM.LSH(minReportSize,globalState.state[IDReportSize]);
IF((globalState.state[IDLogicalMaximum]-globalState.state[IDLogicalMinimum])>=maxReportSize) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMinimum, 0);
errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMaximum, 0);
END;
END;
RETURN mustStop;
END VerifyGlobalState;
PROCEDURE PrintGlobalState*(data: GlobalState);
BEGIN
KernelLog.String("local state table:"); KernelLog.Ln;
KernelLog.String("data.state[IDUsagePage]: "); KernelLog.Int(data.state[IDUsagePage],0); KernelLog.Ln;
KernelLog.String("data.state[IDLogicalMinimum]: "); KernelLog.Int(data.state[IDLogicalMinimum],0); KernelLog.Ln;
KernelLog.String("data.state[IDLogicalMaximum]: "); KernelLog.Int(data.state[IDLogicalMaximum],0); KernelLog.Ln;
KernelLog.String("data.state[IDPhysicalMinimum]: "); KernelLog.Int(data.state[IDPhysicalMinimum],0); KernelLog.Ln;
KernelLog.String("data.state[IDPhysicalMaximum]: "); KernelLog.Int(data.state[IDPhysicalMaximum],0); KernelLog.Ln;
KernelLog.String("data.state[IDUnitExponent]: "); KernelLog.Int(data.state[IDUnitExponent],0); KernelLog.Ln;
KernelLog.String("data.state[IDUnit]: "); KernelLog.Int(data.state[IDUnit],0); KernelLog.Ln;
KernelLog.String("data.state[IDReportSize]: "); KernelLog.Int(data.state[IDReportSize],0); KernelLog.Ln;
KernelLog.String("data.state[IDReportID]: "); KernelLog.Int(data.state[IDReportID],0); KernelLog.Ln;
KernelLog.String("data.state[IDReportCount]: "); KernelLog.Int(data.state[IDReportCount],0); KernelLog.Ln;
KernelLog.Ln;
END PrintGlobalState;
BEGIN
NEW(globalState);
firstGlobalState := globalState;
CleanGlobalState(globalState);
globalState.next := NIL;
END GlobalStateObject;
TYPE
LocalStateObj*=OBJECT
VAR
localState : LocalState;
usageQueue: UsageQueue;
PROCEDURE State(i:LONGINT):LONGINT;
BEGIN
IF ((i>=0) & (i < LengthLocalState)) THEN
RETURN localState.state[i];
ELSE
RETURN UndefinedState;
END;
END State;
PROCEDURE CreateUsageDictionary(): UsbHidReport.UsageDictionary;
BEGIN
RETURN usageQueue.CreateUsageDictionary();
END CreateUsageDictionary;
PROCEDURE CreateUsageArray(reportCount: LONGINT;isArrayFlagSet:BOOLEAN): PtrToUsageTupleArr ;
BEGIN
RETURN usageQueue.CreateUsageTupleArray(reportCount,isArrayFlagSet);
END CreateUsageArray;
PROCEDURE AppendUsageMinMaxArray(mainState: MainState; globalState: GlobalStateObject);
VAR
usageMin, usageMax: LONGINT;
usageExt: LONGINT;
set: SET;
BEGIN
set := SYSTEM.VAL(SET, mainState);
usageMin := State(IDLocalUsageMinimum);
usageMax := State(IDLocalUsageMaximum);
usageExt:= Ext(IDLocalExtUsageMinimum);
IF(IDMainIsVariable IN set) THEN
IF ((usageMin#UndefinedState) & (usageMax#UndefinedState) & (usageMax>=usageMin)) THEN
usageQueue.Add(usageMin, usageMax-usageMin+1, usageExt);
ELSE
END;
ELSE
IF ((usageMin#UndefinedState) & (usageMax#UndefinedState) & (usageMax>=usageMin)) THEN
IF UsbHidReport.UseUsageDictionaryExt THEN
usageQueue.Add(usageMin, usageMax-usageMin+1,usageExt);
ELSE
usageQueue.Add(usageMin,globalState.State(IDReportCount),usageExt);
END;
END;
IF UsbHidReport.Debug THEN
KernelLog.String("UsbHidParser::LocalStateObj.AppendUsageMinMaxArray:");
KernelLog.String(" found Constant bit in mainState and added only ReportCount usageTuples");
KernelLog.Ln;
END;
END;
END AppendUsageMinMaxArray;
PROCEDURE SetState(i, value:LONGINT);
BEGIN
IF ((i>=0) & (i < LengthLocalState)) THEN
CASE i OF
IDLocalUsage:
localState.state[i] := value MOD 10000H;
SetExt(IDLocalExtUsage, value DIV 10000H);
usageQueue.Add(value MOD 10000H,1,value DIV 10000H);
|IDLocalUsageMinimum:
localState.state[i] := value MOD 10000H;
SetExt(IDLocalExtUsageMinimum, value DIV 10000H);
|IDLocalUsageMaximum:
localState.state[i] := value MOD 10000H;
SetExt(IDLocalExtUsageMaximum, value DIV 10000H);
ELSE
localState.state[i] := value;
END
END;
IF(i=IDLocalUsage) THEN
END;
END SetState;
PROCEDURE Ext(i:LONGINT):LONGINT;
BEGIN
IF ((i>=0) & (i < LengthExtLocalState)) THEN
RETURN localState.ext[i];
ELSE
RETURN UndefinedState;
END;
END Ext;
PROCEDURE SetExt(i, value:LONGINT);
BEGIN
IF ((i>=0) & (i < LengthExtLocalState)) THEN
localState.ext[i] := value;
END;
END SetExt;
PROCEDURE CleanLocalState;
BEGIN
localState.state[IDLocalUsage]:= UndefinedState;
localState.state[IDLocalUsageMinimum]:= UndefinedState;
localState.state[IDLocalUsageMaximum]:= UndefinedState;
localState.state[IDLocalDesignatorIndex]:= UndefinedState;
localState.state[IDLocalDesignatorMinimum]:= UndefinedState;
localState.state[IDLocalDesignatorMaximum]:= UndefinedState;
localState.state[IDLocalStringIndex]:= UndefinedState;
localState.state[IDLocalStringMinimum]:= UndefinedState;
localState.state[IDLocalStringMaximum]:= UndefinedState;
localState.state[IDLocalDelimiter]:= UndefinedState;
localState.ext[IDLocalExtUsageMinimum]:= UndefinedState;
localState.ext[IDLocalExtUsageMaximum]:= UndefinedState;
usageQueue.EmptyUsageQueue();
END CleanLocalState;
PROCEDURE PrintLocalState*(data: LocalState);
BEGIN
KernelLog.String("global state table:"); KernelLog.Ln;
KernelLog.String("data.Usage: "); KernelLog.Int(data.state[IDLocalUsage],0); KernelLog.Ln;
KernelLog.String("data.UsageMinimum: "); KernelLog.Int(data.state[IDLocalUsageMinimum],0); KernelLog.Ln;
KernelLog.String("data.UsageMaximum: "); KernelLog.Int(data.state[IDLocalUsageMaximum],0); KernelLog.Ln;
KernelLog.String("data.DesignatorIndex: "); KernelLog.Int(data.state[IDLocalDesignatorIndex],0); KernelLog.Ln;
KernelLog.String("data.DesignatorMinimum: "); KernelLog.Int(data.state[IDLocalDesignatorMinimum],0); KernelLog.Ln;
KernelLog.String("data.DesignatorMaximum: ");KernelLog.Int(data.state[IDLocalDesignatorMaximum],0); KernelLog.Ln;
KernelLog.String("data.StringIndex: "); KernelLog.Int(data.state[IDLocalStringIndex],0); KernelLog.Ln;
KernelLog.String("data.StringMinimum: "); KernelLog.Int(data.state[IDLocalStringMinimum],0); KernelLog.Ln;
KernelLog.String("data.StringMaximum: "); KernelLog.Int(data.state[IDLocalStringMaximum],0); KernelLog.Ln;
KernelLog.String("data.Delimiter: "); KernelLog.Int(data.state[IDLocalDelimiter],0); KernelLog.Ln;
KernelLog.String("ext.UsageMinimum: "); KernelLog.Int(data.ext[IDLocalExtUsageMinimum],0); KernelLog.Ln;
KernelLog.String("data.UsageMaximum: "); KernelLog.Int(data.ext[IDLocalExtUsageMaximum],0); KernelLog.Ln;
KernelLog.Ln;
END PrintLocalState;
PROCEDURE VerifyLocalState(VAR errorList: UsbHidErrors.ErrorList; itemNr: LONGINT);
BEGIN
IF(localState.state[IDLocalUsage]=UndefinedState) THEN
IF((localState.state[IDLocalUsageMinimum]=UndefinedState)OR(localState.state[IDLocalUsageMaximum]=UndefinedState)) THEN
errorList.Add(itemNr, UsbHidErrors.LocalItemUsage,0H);
END;
END;
IF ((localState.state[IDLocalUsageMinimum]#UndefinedState)OR(localState.state[IDLocalUsageMaximum]#UndefinedState)) THEN
IF(localState.state[IDLocalUsageMinimum]=UndefinedState) THEN
errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMaximum, 0H);
END;
IF(localState.state[IDLocalUsageMaximum]=UndefinedState) THEN
errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMinimum, 0H);
END;
IF(localState.state[IDLocalUsageMinimum]>localState.state[IDLocalUsageMaximum]) THEN
errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMaximum, 1H);
errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMinimum, 1H);
END;
IF(localState.ext[IDLocalExtUsageMinimum]#localState.ext[IDLocalExtUsageMaximum]) THEN
errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMinimum, 3H);
errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMaximum, 2H);
END;
END;
IF ((localState.state[IDLocalDesignatorMinimum]#UndefinedState)OR(localState.state[IDLocalDesignatorMaximum]#UndefinedState)) THEN
IF(localState.state[IDLocalDesignatorMinimum]=UndefinedState) THEN
errorList.Add(itemNr, UsbHidErrors.LocalItemDesignatorMaximum, 0H);
END;
IF(localState.state[IDLocalDesignatorMaximum]=UndefinedState) THEN
errorList.Add(itemNr, UsbHidErrors.LocalItemDesignatorMinimum, 0H);
END;
IF(localState.state[IDLocalDesignatorMinimum]>localState.state[IDLocalDesignatorMaximum]) THEN
errorList.Add(itemNr, UsbHidErrors.LocalItemDesignatorMaximum, 1H);
errorList.Add(itemNr, UsbHidErrors.LocalItemDesignatorMinimum, 1H);
END;
END;
IF ((localState.state[IDLocalStringMinimum]#UndefinedState)OR(localState.state[IDLocalStringMaximum]#UndefinedState)) THEN
IF(localState.state[IDLocalStringMinimum]=UndefinedState) THEN
errorList.Add(itemNr, UsbHidErrors.LocalItemStringMaximum, 0H);
END;
IF(localState.state[IDLocalStringMaximum]=UndefinedState) THEN
errorList.Add(itemNr, UsbHidErrors.LocalItemStringMinimum, 0H);
END;
IF(localState.state[IDLocalStringMinimum]>localState.state[IDLocalStringMaximum]) THEN
errorList.Add(itemNr, UsbHidErrors.LocalItemStringMaximum, 1H);
errorList.Add(itemNr, UsbHidErrors.LocalItemStringMinimum, 1H);
END;
END;
END VerifyLocalState;
PROCEDURE &Init*;
BEGIN
NEW(localState);
NEW(usageQueue);
CleanLocalState;
END Init;
END LocalStateObj;
ItemParser* = OBJECT
VAR
mainState : MainState;
globalState : GlobalStateObject;
localState : LocalStateObj;
errorList* : UsbHidErrors.ErrorList;
inputOutputFeatureParsed : BOOLEAN;
depth : LONGINT;
reportManager : UsbHidReport.HidReportManager;
PROCEDURE ToSignedLong*(nofBytes, data : LONGINT): LONGINT;
VAR returnValue : LONGINT;
BEGIN
returnValue := data;
CASE nofBytes OF
1:
IF(data>=80H) THEN
returnValue := data- 100H;
END;
|2:
IF(data>=8000H) THEN
returnValue := data- 10000H;
END;
|4:
IF(data>=80000000H) THEN
returnValue := data- SHORT(0FFFFFFFFH) - SHORT(0FFFFFFFFH) - 2;
END;
ELSE
returnValue := 0;
END;
RETURN returnValue;
END ToSignedLong;
PROCEDURE CreateHidReport(reportType, itemNr: LONGINT):UsbHidReport.HidReport;
VAR
hidReport: UsbHidReport.HidReport;
isArrayFlagSet: BOOLEAN;
diff, maxVal: LONGINT;
BEGIN
IF(reportType=IDMainItemInput) THEN
NEW(hidReport);
hidReport.reportID := globalState.State(IDReportID);
hidReport.reportType := reportType;
hidReport.reportSize := globalState.State(IDReportSize);
hidReport.usagePage := globalState.State(IDUsagePage);
hidReport.mainState := mainState;
hidReport.reportCount := globalState.State(IDReportCount);
hidReport.logicalMinimum := globalState.State(IDLogicalMinimum);
hidReport.logicalMaximum := globalState.State(IDLogicalMaximum);
hidReport.physicalMinimum := globalState.State(IDPhysicalMinimum);
hidReport.physicalMaximum := globalState.State(IDPhysicalMaximum);
hidReport.unitExponent := globalState.State(IDUnitExponent);
hidReport.unit := globalState.State(IDUnit);
isArrayFlagSet := {IDMainIsVariable} * SYSTEM.VAL(SET,mainState) = {};
IF UsbHidReport.UseUsageDictionaryExt THEN
IF isArrayFlagSet THEN
hidReport.supportedUsages := localState.CreateUsageDictionary();
END;
END;
hidReport.usages := localState.CreateUsageArray(hidReport.reportCount, isArrayFlagSet);
END;
diff:=hidReport.logicalMaximum-hidReport.logicalMinimum;
maxVal := SYSTEM.VAL(LONGINT,SYSTEM.VAL(SET,{hidReport.reportSize}));
IF((diff>maxVal)&(hidReport.reportSize<32)) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMinimum,0H);
errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMaximum,0H);
END;
IF( {IDMainIsVariable,IDMainIsConstant} * SYSTEM.VAL(SET,hidReport.mainState)={})THEN
IF UsbHidReport.UseUsageDictionaryExt THEN
maxVal := reportManager.DictSize(hidReport.supportedUsages);
IF(maxVal#hidReport.logicalMaximum-hidReport.logicalMinimum+1) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMaximum,2H);
END;
END;
END;
RETURN hidReport;
END CreateHidReport;
PROCEDURE GetReportManager*(): UsbHidReport.HidReportManager;
BEGIN
RETURN reportManager;
END GetReportManager;
PROCEDURE ParseMainItem*(si: Item; itemNr: LONGINT);
VAR
checkLocalState : BOOLEAN;
aReport: UsbHidReport.HidReport;
PROCEDURE VerifyMainPreconditions;
BEGIN
IF(globalState.State(IDLogicalMinimum)>=globalState.State(IDLogicalMaximum)) THEN
IF globalState.State(IDLogicalMinimum)#UndefinedState THEN
errorList.Add(itemNr, UsbHidErrors.MainItemInput, 3);
END;
END;
IF(globalState.State(IDPhysicalMinimum)>=globalState.State(IDPhysicalMaximum)) THEN
IF globalState.State(IDPhysicalMinimum)#UndefinedState THEN
errorList.Add(itemNr, UsbHidErrors.MainItemInput, 3);
END;
END;
IF globalState.State(IDUsagePage) = UndefinedState THEN
errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
IF Trace THEN KernelLog.String("Usage Page must be defined prior"); END;
END;
IF globalState.State(IDLogicalMinimum) = UndefinedState THEN
errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
IF Trace THEN KernelLog.String("Logical Min must be defined prior"); END;
END;
IF globalState.State(IDLogicalMaximum) = UndefinedState THEN
errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
IF Trace THEN KernelLog.String("Logical Max must be defined prior"); END;
END;
IF globalState.State(IDReportSize) = UndefinedState THEN
errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
IF Trace THEN KernelLog.String("Report Size must be defined prior"); END;
END;
IF globalState.State(IDReportCount) = UndefinedState THEN
errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
IF Trace THEN KernelLog.String("Report Count must be defined prior"); END;
END;
END VerifyMainPreconditions;
BEGIN
IF (Trace OR Debug) THEN
HidParserExt.ParseMainItem(si.bTag,si.bSize, si.data, itemNr, depth);
END;
checkLocalState := TRUE;
CASE si.bTag OF
IDMainItemInput:
IF IDMainIsConstant IN SYSTEM.VAL(SET, si.data) THEN
checkLocalState := FALSE;
END;
inputOutputFeatureParsed := TRUE;
mainState:= si.data;
VerifyMainPreconditions;
localState.AppendUsageMinMaxArray(mainState, globalState);
aReport := CreateHidReport(IDMainItemInput,itemNr);
IF ((aReport.usages = NIL) & ({IDMainIsConstant} * SYSTEM.VAL(SET,aReport.mainState)={})) THEN
errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
END;
reportManager.AddReport(aReport);
|IDMainItemOutput:
IF IDMainIsConstant IN SYSTEM.VAL(SET, si.data) THEN
checkLocalState := FALSE;
END;
inputOutputFeatureParsed := TRUE;
mainState:= si.data;
VerifyMainPreconditions;
|IDMainItemFeature:
IF IDMainIsConstant IN SYSTEM.VAL(SET, si.data) THEN
checkLocalState := FALSE;
END;
inputOutputFeatureParsed := TRUE;
mainState:= si.data;
VerifyMainPreconditions;
|IDMainItemCollection:
INC(depth);
IF (si.data>6H) THEN
IF si.data < 8FH THEN
errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
ELSE
errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
END;
END;
IF ((reportManager.OnTopLevel()=FALSE) & (si.data=1H)) THEN
errorList.Add(itemNr, UsbHidErrors.MainItemCollection, 2H);
END;
reportManager.BeginCollection(si.data, globalState.State(IDUsagePage), localState.State(IDLocalUsage));
checkLocalState := FALSE;
|IDMainItemEndCollection:
DEC(depth);
checkLocalState := FALSE;
IF reportManager.OnTopLevel() THEN
errorList.Add(itemNr, UsbHidErrors.MainItemEndCollection, 0);
END;
reportManager.EndCollection;
ELSE
errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
END;
IF (checkLocalState) THEN
localState.VerifyLocalState(errorList, itemNr);
IF(globalState.VerifyGlobalState(errorList, itemNr)=FALSE) THEN
END;
END;
IF(inputOutputFeatureParsed=TRUE) THEN
END;
globalState.ResetGlobalStateFlags;
localState.CleanLocalState;
END ParseMainItem;
PROCEDURE ParseGlobalItem*( si: Item; itemNr: LONGINT);
VAR temp : LONGINT;
BEGIN
IF (Trace OR Debug) THEN
IF((si.bTag=1H) OR (si.bTag=2H)) THEN
temp := si.data;
HidParserExt.ParseGlobalItem(si.bTag, si.bSize, ToSignedLong(si.bSize,temp), itemNr, depth);
ELSE
HidParserExt.ParseGlobalItem(si.bTag, si.bSize, si.data, itemNr, depth);
END;
END;
CASE si.bTag OF
0H:
globalState.SetState(errorList, IDUsagePage, si.data, itemNr);
IF((inputOutputFeatureParsed= TRUE)&(globalState.State(IDUsagePage)=UndefinedState)) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemUsagePage, 2H);
END;
CASE si.data OF
0H:
errorList.Add(itemNr, UsbHidErrors.GlobalItemUsagePage, 0H);
|1H:
|2H:
|3H:
|4H:
|5H:
|6H:
|7H:
|8H:
|9H:
|0AH:
|0BH:
|0CH:
|0DH:
|0EH:
|0FH:
|10H:
|14H:
|40:
|81H:
|82H:
|83H:
|84H:
|85H:
|86H:
|87H:
|8CH:
|8DH:
|8EH:
|8FH:
ELSE
IF(si.data>0FFFFH) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemUsagePage, 1H);
END;
errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
END;
|1H:
globalState.SetState(errorList, IDLogicalMinimum, ToSignedLong(si.bSize, si.data), itemNr);
IF((inputOutputFeatureParsed= TRUE)&(globalState.State(IDLogicalMinimum)=UndefinedState)) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMinimum, 1H);
END;
|2H:
globalState.SetState(errorList, IDLogicalMaximum, ToSignedLong(si.bSize, si.data), itemNr);
IF((inputOutputFeatureParsed= TRUE)&(globalState.State(IDLogicalMaximum)=UndefinedState)) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMaximum, 1H);
END;
|3H:
globalState.SetState(errorList, IDPhysicalMinimum, si.data, itemNr);
|4H:
globalState.SetState(errorList, IDPhysicalMaximum, si.data, itemNr);
|5H:
globalState.SetState(errorList, IDUnitExponent, si.data, itemNr);
|6H:
globalState.SetState(errorList, IDUnit, si.data, itemNr);
|7H:
globalState.SetState(errorList, IDReportSize, si.data, itemNr);
IF((inputOutputFeatureParsed= TRUE)&(globalState.State(IDReportSize)=UndefinedState)) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemReportSize, 1H);
END;
|8H:
globalState.SetState(errorList, IDReportID, si.data, itemNr);
IF((inputOutputFeatureParsed= TRUE)&(globalState.State(IDReportID)=UndefinedState)) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemReportID, 2H);
END;
IF(si.data=0) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemReportID, 0H);
ELSE
IF(si.data>255) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemReportID, 1H);
END;
END;
IF (reportManager.OnTopLevel()) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemReportID, 3H);
errorList.Add(itemNr, UsbHidErrors.GlobalItemReportID, 4H);
END;
|9H:
globalState.SetState(errorList, IDReportCount, si.data, itemNr);
IF(si.data=0) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemReportCount, 0H);
END;
|10:
globalState.Push;
IF(si.bSize#0) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemPush, 1H);
END;
|11:
IF(globalState.Pop()=FALSE) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemPop, 0H);
END;
IF(si.bSize#0) THEN
errorList.Add(itemNr, UsbHidErrors.GlobalItemPop, 1H);
END;
ELSE
errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
END;
END ParseGlobalItem;
PROCEDURE ParseLocalItem*(si: Item; itemNr: LONGINT);
BEGIN
IF (Trace OR Debug) THEN
HidParserExt.ParseLocalItem(si.bTag, si.bSize, si.data, itemNr, depth, globalState.State(IDUsagePage));
END;
CASE si.bTag OF
0H:
localState.SetState(IDLocalUsage, si.data);
|1H:
localState.SetState(IDLocalUsageMinimum, si.data);
|2H:
localState.SetState(IDLocalUsageMaximum, si.data);
|3H:
localState.SetState(IDLocalDesignatorIndex, si.data);
|4H:
localState.SetState(IDLocalDesignatorMinimum, si.data);
|5H:
localState.SetState(IDLocalDesignatorMaximum, si.data);
|7H:
localState.SetState(IDLocalStringIndex, si.data);
|8H:
localState.SetState(IDLocalStringMinimum, si.data);
|9H:
localState.SetState(IDLocalStringMaximum, si.data);
|0AH:
CASE si.data OF
0:
IF (localState.State(IDLocalDelimiter)#UndefinedState) THEN
errorList.Add(itemNr, UsbHidErrors.LocalItemDelimiter, 1H);
END;
localState.SetState(IDLocalDelimiter, si.data);
|1H:
IF(localState.State(IDLocalDelimiter)=UndefinedState) THEN
errorList.Add(itemNr, UsbHidErrors.LocalItemDelimiter, 2H);
END;
localState.SetState(IDLocalDelimiter, si.data);
ELSE
errorList.Add(itemNr, UsbHidErrors.LocalItemDelimiter, 0H);
END;
ELSE
errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
END;
END ParseLocalItem;
PROCEDURE ParseLongItem*(li: Item; reportBuffer: Usbdi.BufferPtr; len, startIndex, itemNr : LONGINT);
BEGIN
errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003EH);
END ParseLongItem;
PROCEDURE ParseReportDescriptor*(hidDescriptor : UsbHid.HidDescriptor; reportBuffer : Usbdi.BufferPtr): BOOLEAN;
VAR
itemCounter : LONGINT;
cur : LONGINT;
item : POINTER TO Item;
hidCollection: UsbHidReport.HidCollection;
BEGIN
NEW(item);
itemCounter := 0;
cur := 0;
IF Trace THEN
KernelLog.Ln;
KernelLog.String("Report Descriptor Content:");
KernelLog.Ln;
END;
LOOP
IF cur > hidDescriptor.wDescriptorLength-1 THEN EXIT; END;
item.bSize := ORD(reportBuffer[cur]) MOD 4;
IF (item.bSize = 3) THEN INC(item.bSize); END;
item.bType := (ORD(reportBuffer[cur]) DIV 4) MOD 4;
item.bTag := (ORD(reportBuffer[cur]) DIV 16) MOD 16;
INC(cur);
IF (item.bType # ShortItemBTypeReserved) THEN
IF (item.bSize#0) THEN
CASE item.bSize OF
1:
item.data:= ORD(reportBuffer[cur]);
|2:
item.data:= ORD(reportBuffer[cur+1]);
item.data:= 100H*item.data+ORD(reportBuffer[cur]);
|4:
item.data:= ORD(reportBuffer[cur+3]);
item.data:= 100H*item.data + ORD(reportBuffer[cur+2]);
item.data:= 100H*item.data + ORD(reportBuffer[cur+1]);
item.data:= 100H*item.data + ORD(reportBuffer[cur]);
END;
IF(item.data<0) THEN
KernelLog.String("item.data<0 at index: "); KernelLog.Int(cur,0);KernelLog.Ln;
KernelLog.String("item.bSize is "); KernelLog.Int(item.bSize,2); KernelLog.Ln;
END;
ELSE
item.data:= 0;
END;
CASE (item.bType) OF
ShortItemBTypeMain:
IF Debug THEN KernelLog.Int(itemCounter, 4); KernelLog.String(" main "); END;
ParseMainItem(item^, itemCounter);
|ShortItemBTypeGlobal:
IF Debug THEN KernelLog.Int(itemCounter, 4); KernelLog.String(" global"); END;
ParseGlobalItem(item^, itemCounter);
|ShortItemBTypeLocal:
IF Debug THEN KernelLog.Int(itemCounter, 4); KernelLog.String(" local "); END;
ParseLocalItem(item^, itemCounter);
ELSE
RETURN FALSE;
END;
INC(cur, item.bSize);
ELSE
IF (item.bSize#0) THEN
IF((cur+1+ORD(reportBuffer[cur+1]))<hidDescriptor.wDescriptorLength) THEN
ParseLongItem(item^, reportBuffer, ORD(reportBuffer[cur+1]), cur+1, itemCounter);
END;
INC(cur,ORD(reportBuffer[cur+1]) +1);
END;
END;
INC(itemCounter);
END;
IF UsbHidReport.Debug THEN
KernelLog.String("Starting report layout:"); KernelLog.Ln;
hidCollection := reportManager.GetCollection(-1,-1);
KernelLog.String("Searching Mouse Collection (usagePage 1 and usage 2):"); KernelLog.Ln;
hidCollection := reportManager.GetCollection(1,2);
IF (hidCollection#NIL) THEN
KernelLog.String("Mouse Collection found:"); KernelLog.Ln;
KernelLog.String("usagePage: "); KernelLog.Int(hidCollection.usagePage,0);
KernelLog.String(", usage: "); KernelLog.Int(hidCollection.usage,0);
ELSE
KernelLog.String("Mouse Collection not found");
END;
KernelLog.Ln;
END;
IF (reportManager.OnTopLevel()= FALSE) THEN
errorList.Add(itemCounter, UsbHidErrors.MainItemCollection, 0);
END;
RETURN TRUE;
END ParseReportDescriptor;
PROCEDURE Disconnect*;
BEGIN
errorList := NIL;
END Disconnect;
PROCEDURE &Init*;
BEGIN
NEW(globalState);
NEW(localState);
NEW(errorList);
IF Debug THEN KernelLog.String("ItemParser is initialized"); KernelLog.Ln; END;
inputOutputFeatureParsed := FALSE;
IF Debug THEN
depth := 1;
ELSE
depth := 0;
END;
NEW(reportManager);
END Init;
END ItemParser;
END UsbHidParser.
SystemTools.Free UsbHidParser UsbHidParserExt~