diff --git a/README.md b/README.md index 72dbb47..7a742db 100755 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ make ``` The driver is now installed. -Libuvc can also be built from source at: https://github.com/ktossell/libuvc.git +Libuvc can also be built from source at: https://github.com/libuvc/libuvc.git Documentation for the library can be found at: https://int80k.com/libuvc/doc/ diff --git a/RELEASE.md b/RELEASE.md index 04561aa..5986ace 100755 --- a/RELEASE.md +++ b/RELEASE.md @@ -8,6 +8,20 @@ ADUVC requires libusb, libuvc, epics-base, epics-modules, ADCore, and ADSupport. Release Notes ============= +R1-3 (06-September-2019) +----- +* Key detector features implemented: + * Added IOC feature to auto-adjust camera settings based on operating mode. + +* Key fixes and improvements + * Minor screen updates + * Repoint libuvc upstream repo. New repo has issues with CMake file + * Add documentation for fixing root ownership issues of UVC devices + +* Known Issues + * Auto adjust feature can break with certain odd configurations of the camera + * Uses array size to determine 8/16 bit and Mono/RGB, but certain compressed formats break the adjuster. + R1-2 (11-June-2019) ----- * Key detector features implemented: diff --git a/adUVCApp/Db/ADUVC.template b/adUVCApp/Db/ADUVC.template index decb543..d6ac121 100755 --- a/adUVCApp/Db/ADUVC.template +++ b/adUVCApp/Db/ADUVC.template @@ -15,12 +15,12 @@ record(ao, "$(P)$(R)UVCFramerate"){ field(PINI, "YES") field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_FRAMERATE") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_FRAMERATE") } record(ai, "$(P)$(R)UVCFramerate_RBV"){ field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_FRAMERATE") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_FRAMERATE") field(SCAN, "I/O Intr") } @@ -30,12 +30,12 @@ record(ai, "$(P)$(R)UVCFramerate_RBV"){ record(ao, "$(P)$(R)UVCComplianceLevel"){ field(PINI, "YES") field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_COMPLIANCE") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_COMPLIANCE") } record(ai, "$(P)$(R)UVCComplianceLevel_RBV"){ field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_COMPLIANCE") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_COMPLIANCE") field(SCAN, "I/O Intr") } @@ -45,12 +45,12 @@ record(ai, "$(P)$(R)UVCComplianceLevel_RBV"){ record(ao, "$(P)$(R)UVCReferenceCount"){ field(PINI, "YES") field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_REFCOUNT") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_REFCOUNT") } record(ai, "$(P)$(R)UVCReferenceCount_RBV"){ field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_REFCOUNT") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_REFCOUNT") field(SCAN, "I/O Intr") } @@ -60,27 +60,28 @@ record(ai, "$(P)$(R)UVCReferenceCount_RBV"){ record(ao, "$(P)$(R)UVCVendorID"){ field(PINI, "YES") field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_VENDOR") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_VENDOR") } record(ai, "$(P)$(R)UVCVendorID_RBV"){ field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_VENDOR") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_VENDOR") field(SCAN, "I/O Intr") } ############################################## # stores the product id for the UVC camera. Used for connecting to it if serial is unavailable ################################################ + record(ao, "$(P)$(R)UVCProductID"){ field(PINI, "YES") field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_PRODUCT") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_PRODUCT") } record(ai, "$(P)$(R)UVCProductID_RBV"){ field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_PRODUCT") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_PRODUCT") field(SCAN, "I/O Intr") } @@ -90,7 +91,7 @@ record(ai, "$(P)$(R)UVCProductID_RBV"){ record(mbbo, "$(P)$(R)UVCImageFormat"){ field(PINI, "YES") field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_FORMAT") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_FORMAT") field(ZRST, "MJPEG") field(ZRVL, "0") field(ONST, "RGB") @@ -105,7 +106,7 @@ record(mbbo, "$(P)$(R)UVCImageFormat"){ field(FVVL, "5") field(SXST, "Uncompressed") field(SXVL, "6") - field(VAL, "0") + field(VAL, "0") info(autosaveFields, "VAL") } record(mbbi, "$(P)$(R)UVCImageFormat_RBV"){ @@ -134,7 +135,7 @@ record(mbbi, "$(P)$(R)UVCImageFormat_RBV"){ record(mbbo, "$(P)$(R)UVCCameraFormat"){ field(PINI, "YES") field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_CAMERA_FORMAT") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_CAMERA_FORMAT") field(ZRST, "Supported Mode 1") field(ZRVL, "0") field(ONST, "Supported Mode 2") @@ -149,7 +150,7 @@ record(mbbo, "$(P)$(R)UVCCameraFormat"){ field(FVVL, "5") field(SXST, "Supported Mode 7") field(SXVL, "6") - field(VAL, "0") + field(VAL, "0") info(autosaveFields, "VAL") } @@ -186,18 +187,40 @@ record(waveform, "$(P)$(R)UVCFormatDescription_RBV"){ ############################################## # Applies the supported format to the IOC -################################################ +############################################## record(ao, "$(P)$(R)UVCApplyFormat"){ field(PINI, "YES") field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_APPLY_FORMAT") - field(VAL, "0") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_APPLY_FORMAT") + field(VAL, "0") field(autosaveFields, "VAL") } record(ai, "$(P)$(R)UVCApplyFormat_RBV"){ field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_APPLY_FORMAT") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_APPLY_FORMAT") + field(SCAN, "I/O Intr") +} + +############################################## +# Toggles auto adjusting Color Mode, Data Type +############################################## +record(bo, "$(P)$(R)UVCAutoAdjust"){ + field(PINI, "YES") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT),$(ADDR=0),$(TIMEOUT=1))UVC_AUTO_ADJUST") + field(ZNAM, "Disable") + field(ONAM, "Enable") + field(VAL, "1") + field(OSV, "MINOR") + info(autosaveFields, "VAL") +} + +record(bi, "$(P)$(R)UVCAutoAdjust_RBV"){ + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT),$(ADDR=0),$(TIMEOUT=1))UVC_AUTO_ADJUST") + field(ZNAM, "Disable") + field(ONAM, "Enable") field(SCAN, "I/O Intr") } @@ -211,12 +234,12 @@ record(ai, "$(P)$(R)UVCApplyFormat_RBV"){ record(ao, "$(P)$(R)UVCGamma"){ field(PINI, "YES") field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_GAMMA") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_GAMMA") } record(ai, "$(P)$(R)UVCGamma_RBV"){ field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_GAMMA") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_GAMMA") field(SCAN, "I/O Intr") } @@ -226,12 +249,12 @@ record(ai, "$(P)$(R)UVCGamma_RBV"){ record(ao, "$(P)$(R)UVCBacklightCompensation"){ field(PINI, "YES") field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_BACKLIGHT") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_BACKLIGHT") } record(ai, "$(P)$(R)UVCBacklightCompensation_RBV"){ field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_BACKLIGHT") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_BACKLIGHT") field(SCAN, "I/O Intr") } @@ -241,12 +264,12 @@ record(ai, "$(P)$(R)UVCBacklightCompensation_RBV"){ record(ao, "$(P)$(R)UVCBrightness"){ field(PINI, "YES") field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_BRIGHTNESS") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_BRIGHTNESS") } record(ai, "$(P)$(R)UVCBrightness_RBV"){ field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_BRIGHTNESS") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_BRIGHTNESS") field(SCAN, "I/O Intr") } @@ -256,42 +279,27 @@ record(ai, "$(P)$(R)UVCBrightness_RBV"){ record(ao, "$(P)$(R)UVCContrast"){ field(PINI, "YES") field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_CONTRAST") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_CONTRAST") } record(ai, "$(P)$(R)UVCContrast_RBV"){ field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_CONTRAST") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_CONTRAST") field(SCAN, "I/O Intr") } -###################################### -# Stores the Gain value -> deprecated because there is the ADGain PV already -###################################### -#record(ao, "$(P)$(R)UVCGain"){ -# field(PINI, "YES") -# field(DTYP, "asynInt32") -# field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_GAIN") -#} -# -#record(ai, "$(P)$(R)UVCGain_RBV"){ -# field(DTYP, "asynInt32") -# field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_GAIN") -# field(SCAN, "I/O Intr") -#} - ###################################### # Stores the Power line frequency value ###################################### record(ao, "$(P)$(R)UVCPowerLine"){ field(PINI, "YES") field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_POWER") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_POWER") } record(ai, "$(P)$(R)UVCPowerLine_RBV"){ field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_POWER") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_POWER") field(SCAN, "I/O Intr") } @@ -301,12 +309,12 @@ record(ai, "$(P)$(R)UVCPowerLine_RBV"){ record(ao, "$(P)$(R)UVCHue"){ field(PINI, "YES") field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_HUE") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_HUE") } record(ai, "$(P)$(R)UVCHue_RBV"){ field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_HUE") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_HUE") field(SCAN, "I/O Intr") } @@ -316,12 +324,12 @@ record(ai, "$(P)$(R)UVCHue_RBV"){ record(ao, "$(P)$(R)UVCSaturation"){ field(PINI, "YES") field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_SATURATION") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_SATURATION") } record(ai, "$(P)$(R)UVCSaturation_RBV"){ field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_SATURATION") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_SATURATION") field(SCAN, "I/O Intr") } @@ -331,11 +339,11 @@ record(ai, "$(P)$(R)UVCSaturation_RBV"){ record(ao, "$(P)$(R)UVCSharpness"){ field(PINI, "YES") field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_SHARPNESS") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_SHARPNESS") } record(ai, "$(P)$(R)UVCSharpness_RBV"){ field(DTYP, "asynInt32") - field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_SHARPNESS") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_SHARPNESS") field(SCAN, "I/O Intr") } diff --git a/adUVCApp/op/ADUVC.opi b/adUVCApp/op/ADUVC.opi index 93ba4a8..227ec55 100644 --- a/adUVCApp/op/ADUVC.opi +++ b/adUVCApp/op/ADUVC.opi @@ -28,7 +28,7 @@ true false Display - 1100 + 1200 -11870864:166d4cb956b:-4e85 670 172 @@ -63,7 +63,7 @@ false - 130 + 272 true @@ -85,10 +85,10 @@ $(pv_value) true true Rectangle - 378 + 430 -33b311ef:16b0efba116:-6925 - 718 - 342 + 715 + 340 @@ -143,7 +143,7 @@ $(pv_value) false true Rectangle - 715 + 1190 -11870864:166d4cb956b:-4e84 0 4 @@ -222,11 +222,11 @@ $(pv_value) 1 true Label - 715 + 1136 false -11870864:166d4cb956b:-4e7b - 0 - 5 + 20 + 4 @@ -5185,7 +5185,7 @@ $(pv_value) Linking Container 350 -11870864:166d4cb956b:-424b - 726 + 755 36 @@ -5225,8 +5225,8 @@ $(pv_value) Linking Container 350 -11870864:166d4cb956b:-4228 - 729 - 217 + 755 + 212 @@ -5683,7 +5683,7 @@ $(pv_value) 1 true Text Update - 100 + 142 false -33b311ef:16b0efba116:-6961 995 @@ -5875,4 +5875,240 @@ $(pv_value) 727 402 + + + false + + + + + + + 0 + 1 + true + + + + + + + 75 + 0 + Label_88 + + + true + true + false + + + When Auto Adjust is toggled on, ADUVC will attempt to +match Data type and Color mode to frame recieved +from camera when using Uncompressed acquisition. + + true + 1 + true + Label + 413 + false + 5aaa890e:16c52f8a031:-6395 + 731 + 533 + + + + false + 255 + true + false + + + + + + + false + + + + 0 + 1 + true + + + + 0.0 + + Default + + false + + + + false + 1 + true + + + + 0 + 0 + Rectangle_6 + + + + + true + true + false + + + $(pv_name) +$(pv_value) + false + true + Rectangle + 426 + 5aaa890e:16c52f8a031:-6383 + 718 + 472 + + + + false + + + + + + + 0 + 1 + true + + + + + + + 20 + 2 + Label_89 + + + true + true + false + + + UVC Auto Adjust + + true + 1 + true + Label + 150 + false + 5aaa890e:16c52f8a031:-636c + 738 + 500 + + + true + false + false + + + + false + + + + 6 + 1 + true + + Default + + false + + + + 20 + + Menu Button_7 + $(P)$(R)UVCAutoAdjust + + + + true + true + false + + + false + $(pv_name) +$(pv_value) + false + true + Menu Button + 90 + 5aaa890e:16c52f8a031:-636b + 900 + 500 + + + + false + false + false + + + + true + + + + 0 + 1 + true + + + + false + + + + 4 + 18 + 1 + Text Update_59 + 0 + true + $(P)$(R)UVCAutoAdjust_RBV + + 0.0 + + + true + true + false + + + false + ###### + $(pv_name) +$(pv_value) + false + 1 + true + Text Update + 80 + false + 5aaa890e:16c52f8a031:-636a + 1000 + 500 + \ No newline at end of file diff --git a/adUVCApp/src/ADUVC.cpp b/adUVCApp/src/ADUVC.cpp index 50aec70..03dfc6c 100755 --- a/adUVCApp/src/ADUVC.cpp +++ b/adUVCApp/src/ADUVC.cpp @@ -183,7 +183,7 @@ asynStatus ADUVC::readSupportedCameraFormats(){ asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s::%s Reading in supported camera formats\n", driverName, functionName); asynStatus status = asynSuccess; - ADUVC_CamFormat_t* formatBuffer = (ADUVC_CamFormat_t*) calloc(1, 256 * sizeof(ADUVC_CamFormat_t)); + ADUVC_CamFormat_t* formatBuffer = (ADUVC_CamFormat_t*) calloc(1, 64 * sizeof(ADUVC_CamFormat_t)); int bufferIndex = 0; if(this->pdeviceHandle != NULL){ uvc_streaming_interface_t* interfaces = this->pdeviceHandle->info->stream_ifs; @@ -227,14 +227,14 @@ void ADUVC:: populateCameraFormat(ADUVC_CamFormat_t* camFormat, uvc_format_desc_ const char* functionName = "populateCameraFormat"; switch(format_desc->bDescriptorSubtype){ case UVC_VS_FORMAT_MJPEG: - camFormat->frameFormat = ADUVC_FrameMJPEG; - camFormat->dataType = NDUInt8; - camFormat->colorMode = NDColorModeRGB1; + camFormat->frameFormat = ADUVC_FrameMJPEG; + camFormat->dataType = NDUInt8; + camFormat->colorMode = NDColorModeRGB1; break; case UVC_VS_FORMAT_UNCOMPRESSED: - camFormat->frameFormat = ADUVC_FrameUncompressed; - camFormat->dataType = NDUInt16; - camFormat->colorMode = NDColorModeMono; + camFormat->frameFormat = ADUVC_FrameUncompressed; + camFormat->dataType = NDUInt16; + camFormat->colorMode = NDColorModeMono; break; default: asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, @@ -244,9 +244,10 @@ void ADUVC:: populateCameraFormat(ADUVC_CamFormat_t* camFormat, uvc_format_desc_ camFormat->xSize = frame_desc->wWidth; camFormat->ySize = frame_desc->wHeight; camFormat->framerate = 10000000 / frame_desc->dwDefaultFrameInterval; - camFormat->formatDesc = (char*) malloc(256); - epicsSnprintf(camFormat->formatDesc, 256, "%s, X: %d, Y: %d, Rate: %d/s", - get_string_for_subtype(format_desc->bDescriptorSubtype), (int) camFormat->xSize, (int) camFormat->ySize, camFormat->framerate); + + epicsSnprintf(camFormat->formatDesc, SUPPORTED_FORMAT_DESC_BUFF, "%s, X: %d, Y: %d, Rate: %d/s", + get_string_for_subtype(format_desc->bDescriptorSubtype), (int) camFormat->xSize, + (int) camFormat->ySize, camFormat->framerate); } @@ -257,8 +258,7 @@ void ADUVC:: populateCameraFormat(ADUVC_CamFormat_t* camFormat, uvc_format_desc_ * @return: void */ void ADUVC::initEmptyCamFormat(int arrayIndex){ - this->supportedFormats[arrayIndex].formatDesc = (char*) malloc(256); - epicsSnprintf(this->supportedFormats[arrayIndex].formatDesc, 256, "Unused Camera Format"); + epicsSnprintf(this->supportedFormats[arrayIndex].formatDesc, SUPPORTED_FORMAT_DESC_BUFF, "Unused Camera Format"); this->supportedFormats[arrayIndex].frameFormat = ADUVC_FrameUnsupported; } @@ -271,12 +271,12 @@ void ADUVC::initEmptyCamFormat(int arrayIndex){ * @return: 0 if the two structs are identical, -1 if they are not */ int ADUVC::compareFormats(ADUVC_CamFormat_t camFormat1, ADUVC_CamFormat_t camFormat2){ - if (camFormat1.xSize != camFormat2.xSize) return -1; - if (camFormat1.ySize != camFormat2.ySize) return -1; - if (camFormat1.colorMode != camFormat2.colorMode) return -1; - if (camFormat1.dataType != camFormat2.dataType) return -1; - if (camFormat1.framerate != camFormat2.framerate) return -1; - if (camFormat1.frameFormat != camFormat2.frameFormat) return -1; + if (camFormat1.xSize != camFormat2.xSize) return -1; + if (camFormat1.ySize != camFormat2.ySize) return -1; + if (camFormat1.colorMode != camFormat2.colorMode) return -1; + if (camFormat1.dataType != camFormat2.dataType) return -1; + if (camFormat1.framerate != camFormat2.framerate) return -1; + if (camFormat1.frameFormat != camFormat2.frameFormat) return -1; return 0; } @@ -298,6 +298,7 @@ bool ADUVC::formatAlreadySaved(ADUVC_CamFormat_t camFormat){ } + /** * Function that selects the best discovered formats from the set of all discovered formats. * The current order of importance is MJPEG > Uncompressed (Higher end devices only have uncompressed, @@ -330,19 +331,16 @@ int ADUVC::selectBestCameraFormats(ADUVC_CamFormat_t* formatBuffer, int numForma } } } - this->supportedFormats[readFormats].colorMode = formatBuffer[bestFormatIndex].colorMode; - this->supportedFormats[readFormats].dataType = formatBuffer[bestFormatIndex].dataType; - this->supportedFormats[readFormats].frameFormat = formatBuffer[bestFormatIndex].frameFormat; - this->supportedFormats[readFormats].framerate = formatBuffer[bestFormatIndex].framerate; - this->supportedFormats[readFormats].xSize = formatBuffer[bestFormatIndex].xSize; - this->supportedFormats[readFormats].ySize = formatBuffer[bestFormatIndex].ySize; - this->supportedFormats[readFormats].formatDesc = (char*) malloc(256); - memcpy(this->supportedFormats[readFormats].formatDesc, formatBuffer[bestFormatIndex].formatDesc, 256); + this->supportedFormats[readFormats].colorMode = formatBuffer[bestFormatIndex].colorMode; + this->supportedFormats[readFormats].dataType = formatBuffer[bestFormatIndex].dataType; + this->supportedFormats[readFormats].frameFormat = formatBuffer[bestFormatIndex].frameFormat; + this->supportedFormats[readFormats].framerate = formatBuffer[bestFormatIndex].framerate; + this->supportedFormats[readFormats].xSize = formatBuffer[bestFormatIndex].xSize; + this->supportedFormats[readFormats].ySize = formatBuffer[bestFormatIndex].ySize; + + memcpy(this->supportedFormats[readFormats].formatDesc, formatBuffer[bestFormatIndex].formatDesc, SUPPORTED_FORMAT_DESC_BUFF); readFormats++; } - for(int j = 0; j < numFormats; j++){ - free(formatBuffer[j].formatDesc); - } return readFormats; } @@ -416,11 +414,7 @@ asynStatus ADUVC::disconnectFromDeviceUVC(){ const char* functionName = "disconnectFromDeviceUVC"; asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s::%s Calling all free functions for ADUVC\n", driverName, functionName); - int i; - for(i = 0; i< SUPPORTED_FORMAT_COUNT; i++){ - // free mem in supported - free(this->supportedFormats[i].formatDesc); - } + if(connected == 1){ uvc_close(pdeviceHandle); uvc_unref_device(pdevice); @@ -605,6 +599,9 @@ void ADUVC::acquireStop(){ //stop_streaming will block until last callback is processed. uvc_stop_streaming(pdeviceHandle); + // reset the validatedFrameSize flag + this->validatedFrameSize = false; + //update PV values setIntegerParam(ADStatus, ADStatusIdle); setIntegerParam(ADAcquire, 0); @@ -619,6 +616,71 @@ void ADUVC::acquireStop(){ // UVC Image Processing and callback functions //------------------------------------------------------- + +/** + * Function that is meant to adjust the NDDataType and NDColorMode. First check if current settings + * are already valid. If not then attempt to adjust them to fit the frame recieved from the camera. + * If able to adjust properly to fit the frame size, then set a validated tag to true - only compute + * on the first frame on acquisition start. + * + * @params[in]: frame -> pointer to frame recieved from the camera + */ +void ADUVC::checkValidFrameSize(uvc_frame_t* frame){ + // if user has auto adjust toggled off, skip this. + int adjust; + getIntegerParam(ADUVC_AutoAdjust, &adjust); + if(adjust == 0){ + this->validatedFrameSize = true; + return; + } + const char* functionName = "checkValidFrameSize"; + int reg_sizex, reg_sizey, colorMode, dataType; + getIntegerParam(NDColorMode, &colorMode); + getIntegerParam(NDDataType, &dataType); + getIntegerParam(ADSizeX, ®_sizex); + getIntegerParam(ADSizeY, ®_sizey); + int computedBytes = reg_sizex * reg_sizey; + if((NDDataType_t) dataType == NDUInt16 || (NDDataType_t) dataType == NDInt16) + computedBytes = computedBytes * 2; + if((NDColorMode_t) colorMode == NDColorModeRGB1) + computedBytes = computedBytes * 3; + + int num_bytes = frame->data_bytes; + if(computedBytes == num_bytes){ + this->validatedFrameSize = true; + return; + } + asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, + "%s::%s Selected dtype and color mode incompatible, attempting to auto-adjust.\n", driverName, functionName); + + int xsize = frame->width; + int ysize = frame->height; + int res = num_bytes / xsize; + res = res / ysize; + switch(res) { + case 2: + // num bytes / (xsize * ysize) = 2 means a 16 bit mono image. 2 bytes per pixel + setIntegerParam(NDColorMode, NDColorModeMono); + setIntegerParam(NDDataType, NDUInt16); + break; + case 3: + // num bytes / (xsize * ysize) = 3 means 8 bit rgb image. 1 byte per pixel per 3 colors. + setIntegerParam(NDColorMode, NDColorModeRGB1); + setIntegerParam(NDDataType, NDUInt8); + break; + case 6: + // num bytes / (xsize * ysize) = 6 means 16 bit rgb image. 2 bytes per pixel per 3 colors + setIntegerParam(NDColorMode, NDColorModeRGB1); + setIntegerParam(NDDataType, NDUInt16); + break; + default: + asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s Couldn't validate frame size.\n", driverName, functionName); + return; + } + this->validatedFrameSize = true; +} + + /* * Function used as a wrapper function for the callback. * This is necessary beacuse the callback function must be static for libuvc, meaning that function calls @@ -755,6 +817,11 @@ void ADUVC::newFrameCallback(uvc_frame_t* frame, void* ptr){ //epicsTimeStamp currentTime; static const char* functionName = "newFrameCallback"; + // check to see if frame size matches, if not, adjust color mode and data type to try and fit frame. + // **ONLY FOR UNCOMPRESSED FRAMES - otherwise byte sizes will not match ** + if(!this->validatedFrameSize && getFormatFromPV() == UVC_FRAME_FORMAT_UNCOMPRESSED) + checkValidFrameSize(frame); + getIntegerParam(NDColorMode, &colorMode); getIntegerParam(NDDataType, &dataType); @@ -1226,6 +1293,7 @@ ADUVC::ADUVC(const char* portName, const char* serial, int productID, int framer createParam(ADUVC_CameraFormatString, asynParamInt32, &ADUVC_CameraFormat); createParam(ADUVC_FormatDescriptionString, asynParamOctet, &ADUVC_FormatDescription); createParam(ADUVC_ApplyFormatString, asynParamInt32, &ADUVC_ApplyFormat); + createParam(ADUVC_AutoAdjustString, asynParamInt32, &ADUVC_AutoAdjust); createParam(ADUVC_BrightnessString, asynParamInt32, &ADUVC_Brightness); createParam(ADUVC_ContrastString, asynParamInt32, &ADUVC_Contrast); createParam(ADUVC_PowerLineString, asynParamInt32, &ADUVC_PowerLine); diff --git a/adUVCApp/src/ADUVC.h b/adUVCApp/src/ADUVC.h index 31bd66d..455ef7d 100755 --- a/adUVCApp/src/ADUVC.h +++ b/adUVCApp/src/ADUVC.h @@ -20,7 +20,8 @@ #define ADUVC_MODIFICATION 0 -#define SUPPORTED_FORMAT_COUNT 7 +#define SUPPORTED_FORMAT_COUNT 7 +#define SUPPORTED_FORMAT_DESC_BUFF 256 // includes @@ -37,6 +38,7 @@ #define ADUVC_CameraFormatString "UVC_CAMERA_FORMAT" //asynInt32 #define ADUVC_FormatDescriptionString "UVC_FORMAT_DESCRIPTION" //asynOctet #define ADUVC_ApplyFormatString "UVC_APPLY_FORMAT" //asynInt32 +#define ADUVC_AutoAdjustString "UVC_AUTO_ADJUST" //asynInt32 #define ADUVC_GammaString "UVC_GAMMA" //asynInt32 #define ADUVC_BacklightCompensationString "UVC_BACKLIGHT" //asynInt32 #define ADUVC_BrightnessString "UVC_BRIGHTNESS" //asynInt32 @@ -62,7 +64,7 @@ typedef enum { /* Struct for individual supported camera format - Used to auto read modes into dropdown for easier operation */ typedef struct ADUVC_CamFormat{ - char* formatDesc; + char formatDesc[SUPPORTED_FORMAT_DESC_BUFF]; size_t xSize; size_t ySize; int framerate; @@ -108,6 +110,7 @@ class ADUVC : ADDriver{ int ADUVC_CameraFormat; int ADUVC_FormatDescription; int ADUVC_ApplyFormat; + int ADUVC_AutoAdjust; int ADUVC_Gamma; int ADUVC_BacklightCompensation; int ADUVC_Brightness; @@ -158,6 +161,9 @@ class ADUVC : ADDriver{ int firstFrame = 0; + // bool check to see if frame size was validated with selected dtype and color mode + bool validatedFrameSize = false; + // ---------------------------------------- // UVC Functions - Logging/Reporting //----------------------------------------- @@ -224,6 +230,9 @@ class ADUVC : ADDriver{ //function that converts a UVC frame into an NDArray asynStatus uvc2NDArray(uvc_frame_t* frame, NDArray* pArray, NDDataType_t dataType, NDColorMode_t colorMode, size_t imBytes); + // function that attempts to fit data type + color mode to frame if size doesn't match + void checkValidFrameSize(uvc_frame_t* frame); + //function that gets information from a UVC device void getDeviceImageInformation(); void getDeviceInformation(); diff --git a/adUVCSupport/imageCaptureTest/Makefile b/adUVCSupport/imageCaptureTest/Makefile index a05d796..d49a79f 100644 --- a/adUVCSupport/imageCaptureTest/Makefile +++ b/adUVCSupport/imageCaptureTest/Makefile @@ -1,4 +1,4 @@ all: - g++ capture_test.cpp -o capture_test -luvc $(pkg-config --cflags --libs opencv) + g++ capture_test.cpp -o capture_test -luvc -lopencv_core -lopencv_imgproc -lopencv_highgui clean: rm capture_test diff --git a/adUVCSupport/imageCaptureTest/capture_test.cpp b/adUVCSupport/imageCaptureTest/capture_test.cpp index ef1fe70..2200c4e 100644 --- a/adUVCSupport/imageCaptureTest/capture_test.cpp +++ b/adUVCSupport/imageCaptureTest/capture_test.cpp @@ -86,7 +86,7 @@ void newFrameCallback(uvc_frame_t* frame, void* ptr){ cvImg = Mat(rgb->height, rgb->width, CV_8UC3, (uchar*)rgb->data); cvtColor(cvImg, cvImg, COLOR_RGB2BGR); } - else if(frame->frame_format == UVC_FRAME_FORMAT_YUYV){ + else if(frame->frame_format == UVC_FRAME_FORMAT_UNCOMPRESSED){ printf("Copying uncompressed frame\n"); cvImg = Mat(frame->height, frame->width, CV_16SC1, (uchar*) frame->data); } @@ -181,7 +181,7 @@ int main(int argc, char** argv){ } //connect to the device and start streaming for 200 frames. Change frame format here to use different formats - status = uvc_get_stream_ctrl_format_size(deviceHandle, &ctrl, UVC_FRAME_FORMAT_MJPEG, width, height, 30); + status = uvc_get_stream_ctrl_format_size(deviceHandle, &ctrl, UVC_FRAME_FORMAT_UNCOMPRESSED, width, height, 30); void* frame_data; if(status<0){ uvc_perror(status, "get_mode"); diff --git a/adUVCSupport/installlibuvc.sh b/adUVCSupport/installlibuvc.sh index aa3147f..b7e8aaf 100755 --- a/adUVCSupport/installlibuvc.sh +++ b/adUVCSupport/installlibuvc.sh @@ -1,7 +1,11 @@ #!/bin/bash # Install libuvc by cloning from github and running cmake +<<<<<<< HEAD +git clone https://github.com/jwlodek/libuvc.git +======= git clone https://github.com/libuvc/libuvc.git +>>>>>>> 3120101fb7a9196cc59ea15e41e95ff6afea5ff2 cd libuvc mkdir build cd build diff --git a/docs/index.html b/docs/index.html index 38c5d68..f8d1b10 100644 --- a/docs/index.html +++ b/docs/index.html @@ -62,6 +62,30 @@

Release Notes:

Release Notes

+

R1-3 (06-September-2019)

+
    +
  • +

    Key detector features implemented:

    +
      +
    • Added IOC feature to auto-adjust camera settings based on operating mode.
    • +
    +
  • +
  • +

    Key fixes and improvements

    +
      +
    • Minor screen updates
    • +
    • Repoint libuvc upstream repo. New repo has issues with CMake file
    • +
    • Add documentation for fixing root ownership issues of UVC devices
    • +
    +
  • +
  • +

    Known Issues

    +
      +
    • Auto adjust feature can break with certain odd configurations of the camera
    • +
    • Uses array size to determine 8/16 bit and Mono/RGB, but certain compressed formats break the adjuster.
    • +
    +
  • +

R1-2 (11-June-2019)