void ReportCallback(void *target,IOReturn result,void *refcon,void *sender,psych_uint32 bufferSize) { int deviceIndex,i,n,m; unsigned char *ptr; ReportStruct *r; CountReports("ReportCallback beginning."); deviceIndex=(int)refcon; if(deviceIndex<0 | deviceIndex>MAXDEVICEINDEXS-1){ printf("ReportCallback received out-of-range deviceIndex %d. Substituting zero.\n",deviceIndex); deviceIndex=0; } // take report from free list. if(freeReportsPtr==NULL){ // Darn. We're full. It might be elegant to discard oldest report, but for now, we'll just ignore the new one. printf("ReportCallback warning. No more free reports. Discarding new report.\n"); return; } r=freeReportsPtr; freeReportsPtr=r->next; r->next=NULL; // install report into the device's list. r->next=deviceReportsPtr[deviceIndex]; deviceReportsPtr[deviceIndex]=r; // fill in the rest of the report struct r->error=result; r->bytes=bufferSize; r->deviceIndex=deviceIndex; ptr=target; for(i=0;i<bufferSize && i<MAXREPORTSIZE;i++)r->report[i]=*(ptr+i); PsychGetPrecisionTimerSeconds(&r->time); if(optionsPrintReportSummary){ // print diagnostic summary of the report int serial; serial=r->report[62]+256*r->report[63]; // 32-bit serial number at end of AInScan report from PMD-1208FS printf("Got input report %4d: %2ld bytes, dev. %d, %4.0f ms. ",serial,(long)r->bytes,deviceIndex,1000*(r->time-AInScanStart)); if(r->bytes>0){ printf(" report "); n=r->bytes; if(n>6)n=6; for(i=0;i<n;i++)printf("%3d ",(int)r->report[i]); m=r->bytes-2; if(m>i){ printf("... "); i=m; } for(;i<r->bytes;i++)printf("%3d ",(int)r->report[i]); } printf("\n"); } CountReports("ReportCallback end."); return; }
// GiveMeReports is called solely by PsychHIDGiveMeReports, but the code resides here // in PsychHIDReceiveReports because it uses the typedefs and static variables that // are defined solely in this file. The linked lists of reports are unknown outside of this file. PsychError GiveMeReports(int deviceIndex,int reportBytes) { mwSize dims[]={1,1}; mxArray **outReports; ReportStruct *r,*rTail; const char *fieldNames[]={"report", "device", "time"}; mxArray *fieldValue; unsigned char *reportBuffer; int i,n; unsigned int j; long error=0; double now; CountReports("GiveMeReports beginning."); outReports=PsychGetOutArgMxPtr(1); r=deviceReportsPtr[deviceIndex]; n=0; while(r!=NULL){ n++; rTail=r; r=r->next; } *outReports=mxCreateStructMatrix(1,n,3,fieldNames); r=deviceReportsPtr[deviceIndex]; PsychGetPrecisionTimerSeconds(&now); for(i=n-1;i>=0;i--){ // assert(r!=NULL); if(r->error)error=r->error; dims[0]=1; //printf("%2d: r->bytes %2d, reportBytes %4d, -%4.1f s\n",i,(int)r->bytes,(int)reportBytes, now-r->time); if(r->bytes> (unsigned int) reportBytes)r->bytes=reportBytes; dims[1]=r->bytes; fieldValue=mxCreateNumericArray(2,(void *)dims,mxUINT8_CLASS,mxREAL); reportBuffer=(void *)mxGetData(fieldValue); for(j=0;j<r->bytes;j++)reportBuffer[j]=r->report[j]; if(fieldValue==NULL)PrintfExit("Couldn't allocate report array."); mxSetField(*outReports,i,"report",fieldValue); fieldValue=mxCreateDoubleMatrix(1,1,mxREAL); *mxGetPr(fieldValue)=(double)r->deviceIndex; mxSetField(*outReports,i,"device",fieldValue); fieldValue=mxCreateDoubleMatrix(1,1,mxREAL); *mxGetPr(fieldValue)=r->time; mxSetField(*outReports,i,"time",fieldValue); r=r->next; } if(deviceReportsPtr[deviceIndex]!=NULL){ // transfer all these now-obsolete reports to the free list rTail->next=freeReportsPtr; freeReportsPtr=deviceReportsPtr[deviceIndex]; deviceReportsPtr[deviceIndex]=NULL; } CountReports("GiveMeReports end."); return error; }
// Called solely by PsychHIDGetReport, but resides here in order to access the linked list of reports. PsychError GiveMeReport(int deviceIndex,psych_bool *reportAvailablePtr,unsigned char *reportBuffer,psych_uint32 *reportBytesPtr,double *reportTimePtr) { ReportStruct *r,*rOld; long error; unsigned int i; CountReports("GiveMeReport beginning."); r=deviceReportsPtr[deviceIndex]; if(r!=NULL){ // report available? // grab the oldest report for this device *reportAvailablePtr=1; if(r->next==NULL){ deviceReportsPtr[deviceIndex]=NULL; }else{ while(r->next->next!=NULL)r=r->next; rOld=r; r=r->next; rOld->next=NULL; } if(*reportBytesPtr > r->bytes)*reportBytesPtr=r->bytes; for(i=0;i<*reportBytesPtr;i++)reportBuffer[i]=r->report[i]; *reportTimePtr=r->time; error=r->error; // add it to the free list r->next=freeReportsPtr; freeReportsPtr=r; }else{ *reportAvailablePtr=0; *reportBytesPtr=0; *reportTimePtr=0.0; error=0; } CountReports("GiveMeReport end."); return error; }
/* Do all the report processing: Iterates in a fetch loop * until either no more reports pending for processing, error condition, * or a maximum allowable processing time of optionSecs seconds has been * exceeded. * * Calls hidlib function hid_read() to get reports, one at a time, enqueues * it in our own reports lists for later retrieval by 'GiveMeReports' or * 'GiveMeReport'. * */ PsychError ReceiveReports(int deviceIndex) { double deadline, now; pRecDevice device; int n, m; unsigned int i; ReportStruct *r; long error = 0; CountReports("ReceiveReports beginning."); if(freeReportsPtr==NULL) PrintfExit("No free reports."); if(deviceIndex < 0 || deviceIndex > MAXDEVICEINDEXS-1) PrintfExit("Sorry. Can't cope with deviceNumber %d (more than %d). Please tell [email protected]",deviceIndex, (int) MAXDEVICEINDEXS-1); PsychHIDVerifyInit(); device = PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex); last_hid_device = (hid_device*) device->interface; PsychGetAdjustedPrecisionTimerSeconds(&deadline); deadline += optionsSecs; // Iterate until deadline reached or no more pending reports to process: while (TRUE) { // Test for timeout: PsychGetAdjustedPrecisionTimerSeconds(&now); if (now >= deadline) break; CountReports("ReportCallback beginning."); // take report from free list. if(freeReportsPtr == NULL){ // Darn. We're full. It might be elegant to discard oldest report, but for now, we'll just ignore the new one. printf("PsychHID: WARNING! ReportCallback warning. No more free reports. Discarding new report.\n"); break; } r = freeReportsPtr; freeReportsPtr = r->next; r->next=NULL; // install report into the device's list. r->next = deviceReportsPtr[deviceIndex]; deviceReportsPtr[deviceIndex] = r; // fill in the rest of the report struct r->deviceIndex = deviceIndex; // Fetch the actual data: Bytes fetched, or zero for no reports available, or // -1 for error condition. r->error = hid_read((hid_device*) device->interface, &(r->report[0]), MAXREPORTSIZE); if (r->error >= 0) { // Success: Reset error, assign size of retrieved report: r->bytes = r->error; r->error = 0; } else { // Error: No data assigned. r->bytes = 0; // Signal error return code -1: error = -1; // Abort fetch loop: break; } // Timestamp processing: PsychGetPrecisionTimerSeconds(&r->time); if (optionsPrintReportSummary) { // print diagnostic summary of the report int serial; serial = r->report[62] + 256 * r->report[63]; // 32-bit serial number at end of AInScan report from PMD-1208FS printf("Got input report %4d: %2ld bytes, dev. %d, %4.0f ms. ", serial, (long) r->bytes, deviceIndex, 1000 * (r->time - AInScanStart)); if(r->bytes>0) { printf(" report "); n = r->bytes; if (n > 6) n=6; for(i=0; i < (unsigned int) n; i++) printf("%3d ", (int) r->report[i]); m = r->bytes - 2; if (m > (int) i) { printf("... "); i = m; } for(; i < r->bytes; i++) printf("%3d ", (int) r->report[i]); } printf("\n"); } CountReports("ReportCallback end."); // If no data has been returned then we're done for now: if (r->bytes == 0) break; } CountReports("ReceiveReports end."); return error; }
PsychError ReceiveReports(int deviceIndex) { long error=0; pRecDevice device; IOHIDDeviceInterface122** interface=NULL; int reason; // kCFRunLoopRunFinished, kCFRunLoopRunStopped, kCFRunLoopRunTimedOut, kCFRunLoopRunHandledSource CountReports("ReceiveReports beginning."); if(freeReportsPtr==NULL)PrintfExit("No free reports."); PsychHIDVerifyInit(); device=PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex); if(!HIDIsValidDevice(device))PrintfExit("PsychHID: Invalid device.\n"); interface=device->interface; if(interface==NULL)PrintfExit("PsychHID: No interface for device.\n"); if(deviceIndex<0 || deviceIndex>MAXDEVICEINDEXS-1)PrintfExit("Sorry. Can't cope with deviceNumber %d (more than %d). Please tell [email protected]",deviceIndex,(int)MAXDEVICEINDEXS-1); CheckRunLoopSource(deviceIndex,"ReceiveReports",__LINE__); if(!ready[deviceIndex]){ // setInterruptReportHandlerCallback static unsigned char buffer[MAXREPORTSIZE]; psych_uint32 bufferSize=MAXREPORTSIZE; psych_bool createSource; createSource=(source[deviceIndex]==NULL); if(createSource){ if(optionsPrintCrashers && createSource)printf("%d: createAsyncEventSource\n",deviceIndex); error=(*interface)->createAsyncEventSource(interface,&(source[deviceIndex])); if(error)PrintfExit("ReceiveReports - createAsyncEventSource error 0x%lx.",error); if(0 && optionsPrintCrashers && createSource) printf("%d: source %4.4lx validity %d, CFRunLoopContainsSource is %d.\n",deviceIndex,(unsigned long)source[deviceIndex] ,CFRunLoopSourceIsValid(source[deviceIndex]) ,CFRunLoopContainsSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode)); } if(optionsPrintCrashers && createSource)printf("%d: getAsyncEventSource\n",deviceIndex); CheckRunLoopSource(deviceIndex,"ReceiveReports",__LINE__); if(optionsPrintCrashers && createSource)printf("%d: CFRunLoopAddSource\n",deviceIndex); CFRunLoopAddSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode); if(0 && optionsPrintCrashers && createSource)printf("%d: source %4.4lx validity %d, CFRunLoopContainsSource is %d.\n",deviceIndex,(unsigned long)source[deviceIndex] ,CFRunLoopSourceIsValid(source[deviceIndex]) ,CFRunLoopContainsSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode)); ready[deviceIndex]=1; CheckRunLoopSource(deviceIndex,"ReceiveReports",__LINE__); if(optionsPrintCrashers && createSource)printf("%d: setInterruptReportHandlerCallback\n",deviceIndex); error=(*interface)->setInterruptReportHandlerCallback(interface,buffer,bufferSize,ReportCallback,buffer,(void *)deviceIndex); if(error)PrintfExit("ReceiveReports - setInterruptReportHandlerCallback error 0x%lx.",error); if(optionsPrintCrashers && createSource)printf("%d: CFRunLoopRunInMode.\n",deviceIndex); } //printf("%d: CFRunLoopRunInMode\n",deviceIndex); reason=CFRunLoopRunInMode(myRunLoopMode,optionsSecs,false); if(reason!=kCFRunLoopRunTimedOut && reason!=kCFRunLoopRunHandledSource){ char *s; switch(reason){ case kCFRunLoopRunFinished: s="kCFRunLoopRunFinished"; break; case kCFRunLoopRunStopped: s="kCFRunLoopRunStopped"; break; case kCFRunLoopRunTimedOut: s="kCFRunLoopRunTimedOut"; break; case kCFRunLoopRunHandledSource: s="kCFRunLoopRunHandledSource"; break; default: s="of unknown reason."; } printf("RunLoop ended at %.3f s because %s.\n",CFAbsoluteTimeGetCurrent()-AInScanStart,s); } CountReports("ReceiveReports end."); return error; }
/* Do all the report processing for all devices: Iterates in a fetch loop * until error condition, or a maximum allowable processing time of * optionSecs seconds has been exceeded. * * Calls hidlib function hid_read() to get reports, one at a time, enqueues * it in our own reports lists for later retrieval by 'GiveMeReports' or * 'GiveMeReport'. * */ PsychError ReceiveReports(int deviceIndex) { int rateLimit[MAXDEVICEINDEXS] = { 0 }; double deadline, now; pRecDevice device; int n, m; unsigned int i; ReportStruct *r; long error = 0; PsychHIDVerifyInit(); if(deviceIndex < 0 || deviceIndex >= MAXDEVICEINDEXS) PrintfExit("Sorry. Can't cope with deviceNumber %d (more than %d). Please tell [email protected]",deviceIndex, (int) MAXDEVICEINDEXS-1); // Allocate report buffers if needed: PsychHIDAllocateReports(deviceIndex); CountReports("ReceiveReports beginning."); if (freeReportsPtr[deviceIndex] == NULL) PrintfExit("No free reports."); // Enable this device for hid report reception: ready[deviceIndex] = TRUE; PsychGetAdjustedPrecisionTimerSeconds(&now); deadline = now + optionsSecs; // Iterate until deadline reached or no more pending reports to process: while ((error == 0) && (now <= deadline)) { // Iterate over all active devices: for (deviceIndex = 0; deviceIndex < MAXDEVICEINDEXS; deviceIndex++) { // Test for timeout: PsychGetAdjustedPrecisionTimerSeconds(&now); if (now > deadline) break; // Skip this device if it isn't enabled to receive hid reports: if (!ready[deviceIndex]) continue; // Free target report buffers? if(freeReportsPtr[deviceIndex] == NULL) { // Darn. We're full. It might be elegant to discard oldest report, but for now, we'll just ignore the new one. if (!rateLimit[deviceIndex]) printf("PsychHID: WARNING! ReportCallback warning. No more free reports for deviceIndex %i. Discarding new report.\n", deviceIndex); rateLimit[deviceIndex] = 1; continue; } // Handle one report for this device: CountReports("ReportCallback beginning."); device = PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex); last_hid_device = (hid_device*) device->interface; // Get a report struct to fill in: r = freeReportsPtr[deviceIndex]; // Fetch the actual data: Bytes fetched, or zero for no reports available, or // -1 for error condition. r->error = hid_read((hid_device*) device->interface, &(r->report[0]), MaxDeviceReportSize[deviceIndex]); // Skip remainder if no data received: if (r->error == 0) continue; // Ok, we got something, even if it is only an error code. Need // to move the (r)eport from the free list to the received list: freeReportsPtr[deviceIndex] = r->next; r->next=NULL; // install report into the device's list. r->next = deviceReportsPtr[deviceIndex]; deviceReportsPtr[deviceIndex] = r; // fill in the rest of the report struct r->deviceIndex = deviceIndex; // Timestamp processing: PsychGetPrecisionTimerSeconds(&r->time); // Success or error? if (r->error > 0) { // Success: Reset error, assign size of retrieved report: r->bytes = r->error; r->error = 0; } else { // Error: No data assigned. r->bytes = 0; // Signal error return code -1: error = -1; // Abort fetch loop: break; } if (optionsPrintReportSummary) { // print diagnostic summary of the report int serial; serial = r->report[62] + 256 * r->report[63]; // 32-bit serial number at end of AInScan report from PMD-1208FS printf("Got input report %4d: %2ld bytes, dev. %d, %4.0f ms. ", serial, (long) r->bytes, deviceIndex, 1000 * (r->time - AInScanStart)); if(r->bytes>0) { printf(" report "); n = r->bytes; if (n > 6) n=6; for(i=0; i < (unsigned int) n; i++) printf("%3d ", (int) r->report[i]); m = r->bytes - 2; if (m > (int) i) { printf("... "); i = m; } for(; i < r->bytes; i++) printf("%3d ", (int) r->report[i]); } printf("\n"); } CountReports("ReportCallback end."); } } CountReports("ReceiveReports end."); return error; }