From 6d278b27c0e2de54e3571334f4a2b7d8e1dcdd78 Mon Sep 17 00:00:00 2001 From: Jakub Wlodek Date: Fri, 25 Jul 2025 16:03:41 -0400 Subject: [PATCH 1/3] Add clang format and pre commit configuraiton --- .clang-format | 10 ++++++++++ .pre-commit-config.yaml | 24 ++++++++++++++++++++++++ uvcApp/src/ADUVC.h | 12 ------------ 3 files changed, 34 insertions(+), 12 deletions(-) create mode 100644 .clang-format create mode 100644 .pre-commit-config.yaml diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..c0a5c54 --- /dev/null +++ b/.clang-format @@ -0,0 +1,10 @@ +BasedOnStyle: Google +IndentWidth: 4 +TabWidth: 4 +UseTab: Never +ColumnLimit: 100 + +# pointers/references are aligned to the type +PointerAlignment: Left +# Include space after C-style cast +SpaceAfterCStyleCast: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..dc5bec7 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,24 @@ +exclude: ^uvcSupport/ +repos: + # General pre-commit hooks + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-merge-conflict + - id: check-added-large-files + - id: check-case-conflict + - id: check-executables-have-shebangs + - id: check-shebang-scripts-are-executable + - id: check-yaml + - id: check-json + - id: check-xml + - id: mixed-line-ending + args: ['--fix=lf'] + + + - repo: https://github.com/pre-commit/mirrors-clang-format + rev: v14.0.6 + hooks: + - id: clang-format diff --git a/uvcApp/src/ADUVC.h b/uvcApp/src/ADUVC.h index 6bd8a06..c998e54 100644 --- a/uvcApp/src/ADUVC.h +++ b/uvcApp/src/ADUVC.h @@ -273,18 +273,6 @@ class ADUVC : ADDriver{ // UVC Functions - Camera functions //----------------------------------------- - // Functions that set image processing and acquisiton controls - asynStatus setExposure(int exposureTime); - asynStatus setGamma(int gamma); - asynStatus setBacklightCompensation(int backlightCompensation); - asynStatus setBrightness(int brightness); - asynStatus setContrast(int contrast); - asynStatus setGain(int gain); - asynStatus setPowerLineFrequency(int powerLineFrequency); - asynStatus setHue(int hue); - asynStatus setSaturation(int saturation); - asynStatus setSharpness(int sharpness); - // Functions that allow for PTZ (Pan/Tilt/Zoom) control for supported devices asynStatus processPanTilt(int panDirection, int tiltDirection); asynStatus processZoom(int zoomDirection); From 64ac3e9d7a1f54320dd90147614421e2aca8fd9f Mon Sep 17 00:00:00 2001 From: Jakub Wlodek Date: Fri, 25 Jul 2025 16:06:46 -0400 Subject: [PATCH 2/3] Apply pre-commit formatting --- LICENSE | 52 +- README.md | 2 +- RELEASE.md | 12 +- configure/CONFIG | 2 +- configure/CONFIG_SITE | 2 +- configure/Makefile | 2 +- configure/RELEASE | 2 +- configure/RULES | 2 +- configure/RULES.ioc | 2 +- configure/RULES_DIRS | 2 +- configure/RULES_TOP | 2 +- docs/ADUVC/ADUVC.rst | 12 +- docs/ADUVC/lsusb.rst | 32 +- docs/assets/lsusb.txt | 32 +- docs/index.html | 10 +- docs/scripts/insertMarkdown.py | 63 -- docs/scripts/updateReleaseNotes.sh | 12 - docs/uvcDoc.css | 2 +- iocs/uvcIOC/configure/CONFIG | 1 - .../uvcIOC/iocBoot/iocADUVC/auto_settings.req | 1 - iocs/uvcIOC/iocBoot/iocADUVC/autosave/README | 2 +- iocs/uvcIOC/iocBoot/iocADUVC/st.cmd | 10 +- iocs/uvcIOC/uvcApp/src/Makefile | 1 - iocs/uvcIOC/uvcApp/src/uvcAppMain.cpp | 10 +- uvcApp/Db/ADUVC.template | 2 - uvcApp/Db/Makefile | 2 +- uvcApp/op/opi/ADUVC.opi | 6 +- uvcApp/src/ADUVC.cpp | 779 ++++++++---------- uvcApp/src/ADUVC.h | 402 +++++---- uvcApp/src/UVC_DTYPES.md | 2 +- 30 files changed, 660 insertions(+), 803 deletions(-) delete mode 100755 docs/scripts/insertMarkdown.py delete mode 100755 docs/scripts/updateReleaseNotes.sh diff --git a/LICENSE b/LICENSE index 7781cc8..7af7d9f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,8 +1,8 @@ Copyright (c) 2018 Brookhaven Science Associates, as Operator of Brookhaven National Laboratory - + All Rights Reserved - + Area detector USB Video Class (UVC) device driver implementation Photon Sciences Division @@ -16,41 +16,41 @@ EXCEPTIONS OPEN SOURCE LICENSE - -Redistribution and use in source and binary forms, with or without + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. Software changes, - modifications, or derivative works, should be noted with comments and + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. Software changes, + modifications, or derivative works, should be noted with comments and the author and organization's name. - + 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation + this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - + 3. Neither the names of Brookhaven Science Associates, Brookhaven National Laboratory, or the Department of Energy nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -4. The software and the end-user documentation included with the + +4. The software and the end-user documentation included with the redistribution, if any, must include the following acknowledgment: - - "This product includes software produced with the support of the + + "This product includes software produced with the support of the Brookhaven National Laboratory Photon Sciences division." - + **************************************************************************** - + DISCLAIMER - + THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT WARRANTY OF ANY KIND. - -Neither the United States GOVERNMENT, nor the United States Department -of Energy, NOR Brookhaven National Laboratory, LLC, nor any of their employees, makes -any warranty, express or implied, or assumes any legal liability or -responsibility for the accuracy, completeness, or usefulness of any -information, data, apparatus, product, or process disclosed, or + +Neither the United States GOVERNMENT, nor the United States Department +of Energy, NOR Brookhaven National Laboratory, LLC, nor any of their employees, makes +any warranty, express or implied, or assumes any legal liability or +responsibility for the accuracy, completeness, or usefulness of any +information, data, apparatus, product, or process disclosed, or represents that its use would not infringe privately owned rights. - -**************************************************************************** \ No newline at end of file + +**************************************************************************** diff --git a/README.md b/README.md index 9b40243..8bfe206 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ An [EPICS](www.aps.anl.gov/epics) [areaDetector](https://github.com/areaDetector/areaDetector/blob/master/README.md) driver for communicating with USB Video Class (UVC) devices, including consumer webcams and some industrial cameras, using the open source [libuvc library](https://github.com/libuvc/libuvc). -The driver has been tested on 64 bit linux only, but it is possible that it will also work on windows and other architectures as well. +The driver has been tested on 64 bit linux only, but it is possible that it will also work on windows and other architectures as well. It was tested with many devices, including the following: diff --git a/RELEASE.md b/RELEASE.md index 5429e95..0b6c91e 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,6 +1,6 @@ # ADUVC RELEASES -Author: Jakub Wlodek +Author: Jakub Wlodek ADUVC requires libusb, libuvc, epics-base, epics-modules, ADCore, and ADSupport. Further installation information can be found in the README file. @@ -30,7 +30,7 @@ R1-7 (27-January-2023) * Fixes * Minor bug with continuous acquisition mode fixed * Avoid "Auto Adjust" as default behavior - + R1-6 (1-December-2020) ---- @@ -64,9 +64,9 @@ R1-4 (18-August-2020) * Allow for helper utilities to compile with non-system installed libuvc * Known Issues - * `libuvc` relies on `libusb-1.0`, not `libusb`. + * `libuvc` relies on `libusb-1.0`, not `libusb`. * When camera is not connected, driver segmentation faults - should be handled more gracefully. - + R1-3 (06-September-2019) ----- @@ -113,7 +113,7 @@ R1-1 (28-January-2019) * Updated documentation with params[in]/[out] * Added LICENSE * Code formatting cleaned up (removed all tab characters) - + R1-0 (7-December-2018) ----- @@ -131,7 +131,7 @@ R1-0 (7-December-2018) R0-1 (Beta) (5-November-2018) ----- -* Key detector features implemented: +* Key detector features implemented: * Image Acquisition supported and tested. * Acquisition mode selection supported and tested * Diagnostic information acquisition diff --git a/configure/CONFIG b/configure/CONFIG index 6054d1a..331fd70 100644 --- a/configure/CONFIG +++ b/configure/CONFIG @@ -25,4 +25,4 @@ include $(TOP)/configure/CONFIG_SITE ifdef T_A -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) -endif \ No newline at end of file +endif diff --git a/configure/CONFIG_SITE b/configure/CONFIG_SITE index dc6e104..4df968f 100644 --- a/configure/CONFIG_SITE +++ b/configure/CONFIG_SITE @@ -39,4 +39,4 @@ CHECK_RELEASE = YES ifdef T_A -include $(AREA_DETECTOR)/configure/CONFIG_SITE.Common.$(T_A) -include $(AREA_DETECTOR)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) -endif \ No newline at end of file +endif diff --git a/configure/Makefile b/configure/Makefile index e9e1078..9254309 100644 --- a/configure/Makefile +++ b/configure/Makefile @@ -5,4 +5,4 @@ include $(TOP)/configure/CONFIG TARGETS = $(CONFIG_TARGETS) CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) -include $(TOP)/configure/RULES \ No newline at end of file +include $(TOP)/configure/RULES diff --git a/configure/RELEASE b/configure/RELEASE index be6b9c3..e835000 100644 --- a/configure/RELEASE +++ b/configure/RELEASE @@ -4,4 +4,4 @@ -include $(TOP)/../configure/RELEASE_LIBS_INCLUDE -include $(TOP)/RELEASE.local --include $(TOP)/configure/RELEASE.local \ No newline at end of file +-include $(TOP)/configure/RELEASE.local diff --git a/configure/RULES b/configure/RULES index b0054ec..6d56e14 100644 --- a/configure/RULES +++ b/configure/RULES @@ -3,4 +3,4 @@ include $(CONFIG)/RULES # Library should be rebuilt because LIBOBJS may have changed. -$(LIBNAME): ../Makefile \ No newline at end of file +$(LIBNAME): ../Makefile diff --git a/configure/RULES.ioc b/configure/RULES.ioc index 151337e..901987c 100644 --- a/configure/RULES.ioc +++ b/configure/RULES.ioc @@ -1,2 +1,2 @@ #RULES.ioc -include $(CONFIG)/RULES.ioc \ No newline at end of file +include $(CONFIG)/RULES.ioc diff --git a/configure/RULES_DIRS b/configure/RULES_DIRS index ad50f9a..3ba269d 100644 --- a/configure/RULES_DIRS +++ b/configure/RULES_DIRS @@ -1,2 +1,2 @@ #RULES_DIRS -include $(CONFIG)/RULES_DIRS \ No newline at end of file +include $(CONFIG)/RULES_DIRS diff --git a/configure/RULES_TOP b/configure/RULES_TOP index 334a29f..2b8cbc6 100644 --- a/configure/RULES_TOP +++ b/configure/RULES_TOP @@ -1,2 +1,2 @@ #RULES_TOP -include $(CONFIG)/RULES_TOP \ No newline at end of file +include $(CONFIG)/RULES_TOP diff --git a/docs/ADUVC/ADUVC.rst b/docs/ADUVC/ADUVC.rst index 1e0cde4..76380dc 100644 --- a/docs/ADUVC/ADUVC.rst +++ b/docs/ADUVC/ADUVC.rst @@ -17,7 +17,7 @@ An EPICS driver for USB Video Class (UVC) devices .. _libuvc: https://github.com/ktossell/libuvc .. _ADUVC: https://github.com/epicsNSLS2-areaDetector/ADUVC .. _areaDetector: https://github.com/areaDetector - + Overview -------- @@ -56,7 +56,7 @@ Issues with root ownership of UVC devices ----------------------------------------- The USB camera device is typically owned by root, which prevents EPICS IOC from running as softioc user, and automatic startup using procServer. To grant access to USB camera device by other users, such as softioc, we wrote udev rules:: - + kgofron@xf17bm-ioc2:/etc/udev/rules.d$ more usb-cams.rules # cam1 f007 SUBSYSTEM=="usb", ATTRS{idVendor}=="f007", OWNER="softioc", GROUP="softioc", MODE="0666", SYMLINK="cam1" @@ -160,7 +160,7 @@ Release Notes - Allow for helper utilities to compile with non-system installed libuvc - Known Issues - + - libuvc relies on libusb-1.0, not libusb. - When camera is not connected, driver segmentation faults; should be handled more gracefully. @@ -293,9 +293,9 @@ Known Issues and pull requests ------------------------------ - To submit an issue or a pull request for ADUVC, please do so at the source fork on `Github `__. -- Many low end vendors do not assign Serial Numbers (S/N), and such cameras must be started using Product Number instead. +- Many low end vendors do not assign Serial Numbers (S/N), and such cameras must be started using Product Number instead. - Some vendors assign same S/N for the same model, and such multiples of such cameras do not work well when connected to same computer USB hub. -- USB cameras have to be accessed by root, and access by other users is enabled by modifying /etc/udev/rules. +- USB cameras have to be accessed by root, and access by other users is enabled by modifying /etc/udev/rules. Important links --------------- @@ -303,5 +303,3 @@ Important links - libuvc_, is a cross-platform library for USB video devices. - ADUVC_ driver on Github. - areaDetector_ on Github. - - diff --git a/docs/ADUVC/lsusb.rst b/docs/ADUVC/lsusb.rst index abe8bff..8d09b9f 100644 --- a/docs/ADUVC/lsusb.rst +++ b/docs/ADUVC/lsusb.rst @@ -2,13 +2,13 @@ kaz@kaz-VirtualBox:~/src/git/camera/pandac$ lsusb Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub - Bus 001 Device 003: ID 80ee:0030 VirtualBox + Bus 001 Device 003: ID 80ee:0030 VirtualBox Bus 001 Device 002: ID 80ee:0021 VirtualBox USB Tablet Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub kaz@kaz-VirtualBox:~/src/git/camera/pandac$ lsusb -s 001:003 -v - Bus 001 Device 003: ID 80ee:0030 VirtualBox + Bus 001 Device 003: ID 80ee:0030 VirtualBox Couldn't open device, some information will be missing Device Descriptor: bLength 18 @@ -19,11 +19,11 @@ bDeviceProtocol 1 Interface Association bMaxPacketSize0 16 idVendor 0x80ee VirtualBox - idProduct 0x0030 + idProduct 0x0030 bcdDevice 1.00 - iManufacturer 1 - iProduct 2 - iSerial 3 + iManufacturer 1 + iProduct 2 + iSerial 3 bNumConfigurations 1 Configuration Descriptor: bLength 9 @@ -31,7 +31,7 @@ wTotalLength 487 bNumInterfaces 2 bConfigurationValue 1 - iConfiguration 0 + iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 500mA @@ -42,8 +42,8 @@ bInterfaceCount 2 bFunctionClass 14 Video bFunctionSubClass 3 Video Interface Collection - bFunctionProtocol 0 - iFunction 2 + bFunctionProtocol 0 + iFunction 2 Interface Descriptor: bLength 9 bDescriptorType 4 @@ -52,8 +52,8 @@ bNumEndpoints 1 bInterfaceClass 14 Video bInterfaceSubClass 1 Video Control - bInterfaceProtocol 0 - iInterface 2 + bInterfaceProtocol 0 + iInterface 2 VideoControl Interface Descriptor: bLength 13 bDescriptorType 36 @@ -70,7 +70,7 @@ bTerminalID 1 wTerminalType 0x0201 Camera Sensor bAssocTerminal 0 - iTerminal 0 + iTerminal 0 wObjectiveFocalLengthMin 0 wObjectiveFocalLengthMax 0 wOcularFocalLength 0 @@ -87,7 +87,7 @@ bControlSize 3 bmControls 0x00000001 Brightness - iProcessing 0 + iProcessing 0 bmVideoStandards 0x 9 None SECAM - 625/50 @@ -99,7 +99,7 @@ wTerminalType 0x0101 USB Streaming bAssocTerminal 0 bSourceID 2 - iTerminal 0 + iTerminal 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 @@ -118,8 +118,8 @@ bNumEndpoints 1 bInterfaceClass 14 Video bInterfaceSubClass 2 Video Streaming - bInterfaceProtocol 0 - iInterface 0 + bInterfaceProtocol 0 + iInterface 0 VideoStreaming Interface Descriptor: bLength 14 bDescriptorType 36 diff --git a/docs/assets/lsusb.txt b/docs/assets/lsusb.txt index e43d44b..1829031 100644 --- a/docs/assets/lsusb.txt +++ b/docs/assets/lsusb.txt @@ -1,12 +1,12 @@ kaz@kaz-VirtualBox:~/src/git/camera/pandac$ lsusb Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub -Bus 001 Device 003: ID 80ee:0030 VirtualBox +Bus 001 Device 003: ID 80ee:0030 VirtualBox Bus 001 Device 002: ID 80ee:0021 VirtualBox USB Tablet Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub kaz@kaz-VirtualBox:~/src/git/camera/pandac$ lsusb -s 001:003 -v -Bus 001 Device 003: ID 80ee:0030 VirtualBox +Bus 001 Device 003: ID 80ee:0030 VirtualBox Couldn't open device, some information will be missing Device Descriptor: bLength 18 @@ -17,11 +17,11 @@ Device Descriptor: bDeviceProtocol 1 Interface Association bMaxPacketSize0 16 idVendor 0x80ee VirtualBox - idProduct 0x0030 + idProduct 0x0030 bcdDevice 1.00 - iManufacturer 1 - iProduct 2 - iSerial 3 + iManufacturer 1 + iProduct 2 + iSerial 3 bNumConfigurations 1 Configuration Descriptor: bLength 9 @@ -29,7 +29,7 @@ Device Descriptor: wTotalLength 487 bNumInterfaces 2 bConfigurationValue 1 - iConfiguration 0 + iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 500mA @@ -40,8 +40,8 @@ Device Descriptor: bInterfaceCount 2 bFunctionClass 14 Video bFunctionSubClass 3 Video Interface Collection - bFunctionProtocol 0 - iFunction 2 + bFunctionProtocol 0 + iFunction 2 Interface Descriptor: bLength 9 bDescriptorType 4 @@ -50,8 +50,8 @@ Device Descriptor: bNumEndpoints 1 bInterfaceClass 14 Video bInterfaceSubClass 1 Video Control - bInterfaceProtocol 0 - iInterface 2 + bInterfaceProtocol 0 + iInterface 2 VideoControl Interface Descriptor: bLength 13 bDescriptorType 36 @@ -68,7 +68,7 @@ Device Descriptor: bTerminalID 1 wTerminalType 0x0201 Camera Sensor bAssocTerminal 0 - iTerminal 0 + iTerminal 0 wObjectiveFocalLengthMin 0 wObjectiveFocalLengthMax 0 wOcularFocalLength 0 @@ -85,7 +85,7 @@ Device Descriptor: bControlSize 3 bmControls 0x00000001 Brightness - iProcessing 0 + iProcessing 0 bmVideoStandards 0x 9 None SECAM - 625/50 @@ -97,7 +97,7 @@ Device Descriptor: wTerminalType 0x0101 USB Streaming bAssocTerminal 0 bSourceID 2 - iTerminal 0 + iTerminal 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 @@ -116,8 +116,8 @@ Device Descriptor: bNumEndpoints 1 bInterfaceClass 14 Video bInterfaceSubClass 2 Video Streaming - bInterfaceProtocol 0 - iInterface 0 + bInterfaceProtocol 0 + iInterface 0 VideoStreaming Interface Descriptor: bLength 14 bDescriptorType 36 diff --git a/docs/index.html b/docs/index.html index 1268e7a..6dc7e5f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -16,7 +16,7 @@

Corresponding author: Kazimierz Gofron


Introduction:

- UVC, or USB Video Class is an open Video connection standard used for USB based cameras and webcams. Almost all consumer webcams support + UVC, or USB Video Class is an open Video connection standard used for USB based cameras and webcams. Almost all consumer webcams support UVC, along with a large number of other consumer USB cameras of different form factors, ranging from pencil cameras to micro cameras. Some industrial cameras support the format as well. ADUVC is an area detector driver that adds support for UVC based cameras. It also includes some useful test programs to check if your UVC device is being recognized correctly. @@ -28,8 +28,8 @@

Installation:

file. To install ADUVC, you must first install libuvc and its dependancies. The simplest way to do this is to run the provided bash script in the adUVCSupport directory of the repository. This installs libusub, libjpeg, and cmake, clones the libuvc repository on github, and then builds it using cmake. The dynamic library files - resulting from the build are placed in the /usr/local directory (on Linux), and include files must be placed in adUVCSupport/include. - From here you may compile the support programs or the driver itself by entering the appropriate directory (the top ADUVC dir. for the + resulting from the build are placed in the /usr/local directory (on Linux), and include files must be placed in adUVCSupport/include. + From here you may compile the support programs or the driver itself by entering the appropriate directory (the top ADUVC dir. for the driver), and compiling by switching to root and typing 'make'. The driver is now installed.


@@ -37,7 +37,7 @@

Driver Contents:

  • install-libuvc.sh -> Installation script for libuvc and its dependancies.
  • cameraDetector -> C++ program that detects all connected UVC devices. Useful for finding serial/product number for IOC
  • -
  • imageCaptureTest -> C++ program that uses OpenCV to capture 200 frames from the camera to test if libuvc has been installed and the +
  • imageCaptureTest -> C++ program that uses OpenCV to capture 200 frames from the camera to test if libuvc has been installed and the camera is connected.
  • ADUVC driver -> The source code for the area detector driver itself in the uvcApp/src directory.
  • @@ -286,6 +286,6 @@

    Important links:

  • ADUVC on Github
  • areaDetector on Github
- + diff --git a/docs/scripts/insertMarkdown.py b/docs/scripts/insertMarkdown.py deleted file mode 100755 index dd60c2b..0000000 --- a/docs/scripts/insertMarkdown.py +++ /dev/null @@ -1,63 +0,0 @@ -# Python script that replaces the old release notes with notes converted from markdown into the docs -# -# Author: Jakub Wlodek -# Created on: January 10, 2019 -# -# Copyright(c): Brookhaven National Laboratory 2018-2019 -# - -import os - - -# function that changes

tags to

tags -def fix_header_sizes(): - with open("output.html") as f: - newText = f.read().replace('h2', 'h4') - - with open("output.html", "w") as f: - f.write(newText) - - -# function that inserts new release notes -def insert_new_notes(tempIndex): - newNotes = open("output.html", "r") - line = newNotes.readline() - line_counter = 0 - while line: - if line_counter > 3: - tempIndex.write(line) - line_counter = line_counter + 1 - line = newNotes.readline() - newNotes.close() - - -# function that copies unchanged html from file -def create_updated_doc(): - htmlDoc = open("../index.html", "r") - tempIndex = open("../tempIndex.html", "w") - line = htmlDoc.readline() - isReleases = False - while line: - if isReleases == False: - tempIndex.write(line) - if "" in line: - isReleases = True - elif "" in line: - insert_new_notes(tempIndex) - isReleases = False - tempIndex.write(line) - line = htmlDoc.readline() - htmlDoc.close() - tempIndex.close() - - -# Main driver function -def update_release_notes(): - fix_header_sizes() - create_updated_doc() - os.remove("../index.html") - os.remove("output.html") - os.rename("../tempIndex.html", "../index.html") - - -update_release_notes() diff --git a/docs/scripts/updateReleaseNotes.sh b/docs/scripts/updateReleaseNotes.sh deleted file mode 100755 index a553aa6..0000000 --- a/docs/scripts/updateReleaseNotes.sh +++ /dev/null @@ -1,12 +0,0 @@ -# Simple bash script that converts the RELEASE.md file from markdown to html using the markdown python package -# -# To install this package run: -# -# sudo pip install markdown -# -# Author: Jakub Wlodek -# Created on: January 10, 2019 -# - -python3 -m markdown ../../RELEASE.md > output.html -python3 insertMarkdown.py diff --git a/docs/uvcDoc.css b/docs/uvcDoc.css index 123f641..b56aaed 100644 --- a/docs/uvcDoc.css +++ b/docs/uvcDoc.css @@ -3,4 +3,4 @@ .text-section-local { /*padding-left: 30px;*/ width: 70%; -} \ No newline at end of file +} diff --git a/iocs/uvcIOC/configure/CONFIG b/iocs/uvcIOC/configure/CONFIG index c1a4703..331fd70 100644 --- a/iocs/uvcIOC/configure/CONFIG +++ b/iocs/uvcIOC/configure/CONFIG @@ -26,4 +26,3 @@ ifdef T_A -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) endif - diff --git a/iocs/uvcIOC/iocBoot/iocADUVC/auto_settings.req b/iocs/uvcIOC/iocBoot/iocADUVC/auto_settings.req index 8ab8c82..d001d6b 100644 --- a/iocs/uvcIOC/iocBoot/iocADUVC/auto_settings.req +++ b/iocs/uvcIOC/iocBoot/iocADUVC/auto_settings.req @@ -1,4 +1,3 @@ file "ADUVC_settings.req", P=$(P), R=cam1: file "NDStdArrays_settings.req", P=$(P), R=image1: file "commonPlugin_settings.req", P=$(P) - diff --git a/iocs/uvcIOC/iocBoot/iocADUVC/autosave/README b/iocs/uvcIOC/iocBoot/iocADUVC/autosave/README index c208111..e226264 100644 --- a/iocs/uvcIOC/iocBoot/iocADUVC/autosave/README +++ b/iocs/uvcIOC/iocBoot/iocADUVC/autosave/README @@ -1 +1 @@ -Folder that allows for IOC autosave functionality \ No newline at end of file +Folder that allows for IOC autosave functionality diff --git a/iocs/uvcIOC/iocBoot/iocADUVC/st.cmd b/iocs/uvcIOC/iocBoot/iocADUVC/st.cmd index ad06442..c848097 100755 --- a/iocs/uvcIOC/iocBoot/iocADUVC/st.cmd +++ b/iocs/uvcIOC/iocBoot/iocADUVC/st.cmd @@ -5,7 +5,7 @@ errlogInit(20000) < envPaths #epicsThreadSleep(20) dbLoadDatabase("$(TOP)/dbd/uvcApp.dbd") -uvcApp_registerRecordDeviceDriver(pdbbase) +uvcApp_registerRecordDeviceDriver(pdbbase) # Prefix for all records epicsEnvSet("PREFIX", "XF:10IDC-BI{UVC-Cam:1}") @@ -23,14 +23,14 @@ epicsEnvSet("NCHANS", "2048") epicsEnvSet("CBUFFS", "500") # The search path for database files epicsEnvSet("EPICS_DB_INCLUDE_PATH", "$(ADCORE)/db") -# Size of data allowed +# Size of data allowed epicsEnvSet("EPICS_CA_MAX_ARRAY_BYTES", 20000000) #epicsThreadSleep(15) #/* -# * Constructor for ADUVC driver. Most params are passed to the parent ADDriver constructor. +# * Constructor for ADUVC driver. Most params are passed to the parent ADDriver constructor. # * Connects to the camera, then gets device information, and is ready to aquire images. -# * +# * # * @params: portName -> port for NDArray recieved from camera # * @params: serial -> serial number of device to connect to # * @params: productID -> Product id number for device to connect to @@ -52,7 +52,7 @@ epicsEnvSet("EPICS_CA_MAX_ARRAY_BYTES", 20000000) #ADUVCConfig("$(PORT)", "", 25344, 0, $(XSIZE), $(YSIZE), 0, 0, 0, 0) #epicsThreadSleep(2) -# If opening device by index, simply set a an empty string for the serial, and a 0 for productID. An index of 0 will open the first UVC +# If opening device by index, simply set a an empty string for the serial, and a 0 for productID. An index of 0 will open the first UVC # camera detected. See the output of the uvc_locater command for index values (first -> 0, second -> 1, etc) ADUVCConfig("$(PORT)", "", 0, 0, $(XSIZE), $(YSIZE), 0, 0, 0, 0) epicsThreadSleep(2) diff --git a/iocs/uvcIOC/uvcApp/src/Makefile b/iocs/uvcIOC/uvcApp/src/Makefile index f5ea4d8..5409730 100644 --- a/iocs/uvcIOC/uvcApp/src/Makefile +++ b/iocs/uvcIOC/uvcApp/src/Makefile @@ -30,4 +30,3 @@ include $(ADCORE)/ADApp/commonDriverMakefile include $(TOP)/configure/RULES #---------------------------------------- # ADD RULES AFTER THIS LINE - diff --git a/iocs/uvcIOC/uvcApp/src/uvcAppMain.cpp b/iocs/uvcIOC/uvcApp/src/uvcAppMain.cpp index 0162b29..c4652ba 100644 --- a/iocs/uvcIOC/uvcApp/src/uvcAppMain.cpp +++ b/iocs/uvcIOC/uvcApp/src/uvcAppMain.cpp @@ -2,22 +2,20 @@ /* Author: Marty Kraimer Date: 17MAR2000 */ #include +#include #include -#include #include -#include #include "epicsExit.h" #include "epicsThread.h" #include "iocsh.h" -int main(int argc,char *argv[]) -{ - if(argc>=2) { +int main(int argc, char *argv[]) { + if (argc >= 2) { iocsh(argv[1]); epicsThreadSleep(.2); } iocsh(NULL); epicsExit(0); - return(0); + return (0); } diff --git a/uvcApp/Db/ADUVC.template b/uvcApp/Db/ADUVC.template index 88af298..ca1068c 100644 --- a/uvcApp/Db/ADUVC.template +++ b/uvcApp/Db/ADUVC.template @@ -489,5 +489,3 @@ record(ao, "$(P)$(R)UVCZoomOut"){ field(DTYP, "asynInt32") field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))UVC_ZOOM_OUT") } - - diff --git a/uvcApp/Db/Makefile b/uvcApp/Db/Makefile index 7a60308..896f1c9 100644 --- a/uvcApp/Db/Makefile +++ b/uvcApp/Db/Makefile @@ -8,7 +8,7 @@ include $(TOP)/configure/CONFIG #DB_OPT = YES #------------------------------------------- -# Create and install (or just install) +# Create and install (or just install) # databases, templates, subtitutions DB += ADUVC.template diff --git a/uvcApp/op/opi/ADUVC.opi b/uvcApp/op/opi/ADUVC.opi index 1876a3b..198b71e 100644 --- a/uvcApp/op/opi/ADUVC.opi +++ b/uvcApp/op/opi/ADUVC.opi @@ -5961,8 +5961,8 @@ $(pv_value) false - When Auto Adjust is toggled on, ADUVC will attempt to -match Data type and Color mode to frame recieved + 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 @@ -7254,4 +7254,4 @@ $(pv_value) 845 345 - \ No newline at end of file + diff --git a/uvcApp/src/ADUVC.cpp b/uvcApp/src/ADUVC.cpp index d861683..e2cc5bb 100644 --- a/uvcApp/src/ADUVC.cpp +++ b/uvcApp/src/ADUVC.cpp @@ -11,49 +11,40 @@ * */ - // Standard includes -#include #include +#include #include - // EPICS includes -#include -#include #include -#include +#include #include +#include +#include +#include #include -#include - // Local ADUVC include #include "ADUVC.h" - // libuvc includes #include #include - // standard namespace using namespace std; - // define driver name for logging static const char* driverName = "ADUVC"; // Constants static const double ONE_BILLION = 1.E9; - - //--------------------------------------------------------- // ADUVC Utility functions //--------------------------------------------------------- - /** * External configuration function for ADUVC. * Envokes the constructor to create a new ADUVC object @@ -62,26 +53,23 @@ static const double ONE_BILLION = 1.E9; * @params[in]: all passed into constructor * @return: status */ -extern "C" int ADUVCConfig(const char* portName, const char* serialOrProductID){ - +extern "C" int ADUVCConfig(const char* portName, const char* serialOrProductID) { new ADUVC(portName, serialOrProductID); return asynSuccess; } - /** * Callback function called when IOC is terminated. * Deletes created object and frees UVC context * * @params[in]: pPvt -> pointer to the ADUVC object created in ADUVCConfig */ -static void exitCallbackC(void* pPvt){ +static void exitCallbackC(void* pPvt) { ADUVC* pUVC = (ADUVC*) pPvt; - delete(pUVC); + delete (pUVC); } - /** * Function used to display UVC errors * @@ -89,26 +77,24 @@ static void exitCallbackC(void* pPvt){ * @params[in]: functionName -> name of function in which uvc error occurred * return: void */ -void ADUVC::reportUVCError(uvc_error_t status, const char* functionName){ - ERR_ARGS("%s", uvc_strerror(status)); +void ADUVC::reportUVCError(uvc_error_t status, const char* functionName) { + ERR_ARGS("%s", uvc_strerror(status)); - if(status != UVC_ERROR_OTHER){ + if (status != UVC_ERROR_OTHER) { char errorMessage[25]; - epicsSnprintf(errorMessage, sizeof(errorMessage), - "UVC Error: %s", uvc_strerror(status)); + epicsSnprintf(errorMessage, sizeof(errorMessage), "UVC Error: %s", uvc_strerror(status)); updateStatus(errorMessage); } } - /** * Function that writes to ADStatus PV - * + * * @params[in]: status -> message to write to ADStatus PV */ -void ADUVC::updateStatus(const char* status){ - if(strlen(status) >= 25) return; +void ADUVC::updateStatus(const char* status) { + if (strlen(status) >= 25) return; char statusMessage[25]; epicsSnprintf(statusMessage, sizeof(statusMessage), "%s", status); @@ -116,16 +102,14 @@ void ADUVC::updateStatus(const char* status){ callParamCallbacks(); } - //----------------------------------------------- // ADUVC Camera Format selector functions //----------------------------------------------- - /** * External C function pulled from libuvc_internal diagnostics. * Simply returns a string for a given subtype - * + * * @return: string representing certain subtype identifier */ extern "C" const char* get_string_for_subtype(uint8_t subtype) { @@ -139,37 +123,36 @@ extern "C" const char* get_string_for_subtype(uint8_t subtype) { } } - /** * Function that updates the description for a selected camera format */ -void ADUVC::updateCameraFormatDesc(){ +void ADUVC::updateCameraFormatDesc() { const char* functionName = "updateCameraFormatDesc"; int selectedFormat; getIntegerParam(ADUVC_CameraFormat, &selectedFormat); INFO("Updating format description..."); char description[256]; - epicsSnprintf(description, sizeof(description), "%s", this->supportedFormats[selectedFormat].formatDesc); + epicsSnprintf(description, sizeof(description), "%s", + this->supportedFormats[selectedFormat].formatDesc); setStringParam(ADUVC_FormatDescription, description); updateStatus("Updated format Desc."); callParamCallbacks(); INFO("Done."); } - /** * Function that handles applying a selected supported camera format to the approptiate PVs. * Sets the data type, color mode, framerate, xsize, ysize, and frame format PVs. */ -void ADUVC::applyCameraFormat(){ +void ADUVC::applyCameraFormat() { const char* functionName = "applyCameraFormat"; int selectedFormat; getIntegerParam(ADUVC_CameraFormat, &selectedFormat); INFO("Applying Format..."); ADUVC_CamFormat_t format = this->supportedFormats[selectedFormat]; - if( (int) format.frameFormat < 0){ + if ((int) format.frameFormat < 0) { ERR("Cannot apply selected format!"); } else { setIntegerParam(NDDataType, format.dataType); @@ -186,28 +169,29 @@ void ADUVC::applyCameraFormat(){ callParamCallbacks(); } - /** * Function that reads all supported camera formats into a ADUVC_CamFormat_t struct, and then * selects the ones that are most likely to be useful for easy selection. - * + * * @return: asynSuccess if successful, asynError if error */ -asynStatus ADUVC::readSupportedCameraFormats(){ +asynStatus ADUVC::readSupportedCameraFormats() { const char* functionName = "readSupportedCameraFormats"; INFO("Parsing supported camera formats..."); asynStatus status = asynSuccess; - ADUVC_CamFormat_t* formatBuffer = (ADUVC_CamFormat_t*) calloc(1, 64 * 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){ + if (this->pdeviceHandle != NULL) { uvc_streaming_interface_t* interfaces = this->pdeviceHandle->info->stream_ifs; - while(interfaces != NULL){ + while (interfaces != NULL) { uvc_format_desc_t* interfaceFormats = interfaces->format_descs; - while(interfaceFormats != NULL) { + while (interfaceFormats != NULL) { uvc_frame_desc_t* frameFormats = interfaceFormats->frame_descs; - while(frameFormats != NULL) { - populateCameraFormat(&formatBuffer[bufferIndex], interfaceFormats, frameFormats); + while (frameFormats != NULL) { + populateCameraFormat(&formatBuffer[bufferIndex], interfaceFormats, + frameFormats); bufferIndex++; frameFormats = frameFormats->next; } @@ -215,8 +199,7 @@ asynStatus ADUVC::readSupportedCameraFormats(){ } interfaces = interfaces->next; } - } - else{ + } else { status = asynError; } @@ -224,7 +207,7 @@ asynStatus ADUVC::readSupportedCameraFormats(){ free(formatBuffer); int i; - for(i = formatIndex; i < SUPPORTED_FORMAT_COUNT; i++){ + for (i = formatIndex; i < SUPPORTED_FORMAT_COUNT; i++) { initEmptyCamFormat(i); } INFO("Done."); @@ -232,31 +215,29 @@ asynStatus ADUVC::readSupportedCameraFormats(){ return status; } - /** * Function that takes a format descriptor and a frame descriptor, and populates a camera format * structure with the appropriate values. - * + * * @params[out]: camFormat -> Output camFormat struct * @params[in]: format_desc -> Format descriptor struct * @params[in]: frame_desc -> Frame descriptor struct * @return: void */ -void ADUVC:: populateCameraFormat(ADUVC_CamFormat_t* camFormat, - uvc_format_desc_t* format_desc, uvc_frame_desc_t* frame_desc){ - +void ADUVC::populateCameraFormat(ADUVC_CamFormat_t* camFormat, uvc_format_desc_t* format_desc, + uvc_frame_desc_t* frame_desc) { const char* functionName = "populateCameraFormat"; - switch(format_desc->bDescriptorSubtype){ + 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: ERR("Unsupported format desc!"); @@ -267,129 +248,125 @@ void ADUVC:: populateCameraFormat(ADUVC_CamFormat_t* camFormat, camFormat->ySize = frame_desc->wHeight; camFormat->framerate = 10000000 / frame_desc->dwDefaultFrameInterval; - 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); + 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); } - /** * Function that initializes a Camera Format struct with empty placeholder - * - * @params[in]: arrayIndex -> index in array of supported formats + * + * @params[in]: arrayIndex -> index in array of supported formats * @return: void */ -void ADUVC::initEmptyCamFormat(int arrayIndex){ - epicsSnprintf(this->supportedFormats[arrayIndex].formatDesc, SUPPORTED_FORMAT_DESC_BUFF, "Unused Camera Format"); +void ADUVC::initEmptyCamFormat(int arrayIndex) { + epicsSnprintf(this->supportedFormats[arrayIndex].formatDesc, SUPPORTED_FORMAT_DESC_BUFF, + "Unused Camera Format"); this->supportedFormats[arrayIndex].frameFormat = ADUVC_FrameUnsupported; } - /** * Function that compares two camera format structs against one another - * + * * @params[in]: cameraFormat1 -> first camera format struct * @params[in]: cameraFormat2 -> second camera format struct * @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; +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; return 0; } - /** * Function that checks if a Cam format struct is already in the camera's format array - * + * * @params[in]: camFormat -> format to test * @return: true if it is in the supportedFormats array, false otherwise */ -bool ADUVC::formatAlreadySaved(ADUVC_CamFormat_t camFormat){ +bool ADUVC::formatAlreadySaved(ADUVC_CamFormat_t camFormat) { int i; - for(i = 0; i< SUPPORTED_FORMAT_COUNT; i++){ - if(compareFormats(camFormat, this->supportedFormats[i]) == 0){ + for (i = 0; i < SUPPORTED_FORMAT_COUNT; i++) { + if (compareFormats(camFormat, this->supportedFormats[i]) == 0) { return true; } } return false; } - - /** * 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, - * and lower end devices exhibit poor performance when using Uncompressed), then image resolution, - * then framerate. - * + * The current order of importance is MJPEG > Uncompressed (Higher end devices only have + * uncompressed, and lower end devices exhibit poor performance when using Uncompressed), then image + * resolution, then framerate. + * * @params[in]: formatBuffer -> Buffer containing all detected camera formats * @params[in]: numFormats -> counter for how many formats were detected * @return: readFormats -> The number of formats read from the formatBuffer */ -int ADUVC::selectBestCameraFormats(ADUVC_CamFormat_t* formatBuffer, int numFormats){ +int ADUVC::selectBestCameraFormats(ADUVC_CamFormat_t* formatBuffer, int numFormats) { const char* functionName = "selectBestCameraFormats"; INFO("Selecting best camera formats..."); int readFormats = 0; - while(readFormats < SUPPORTED_FORMAT_COUNT && readFormats != numFormats){ + while (readFormats < SUPPORTED_FORMAT_COUNT && readFormats != numFormats) { int bestFormatIndex = 0; int i; - for(i = 0; i< numFormats; i++){ - if(!formatAlreadySaved(formatBuffer[i])){ - if(formatBuffer[i].frameFormat == ADUVC_FrameMJPEG && formatBuffer[bestFormatIndex].frameFormat != ADUVC_FrameMJPEG){ + for (i = 0; i < numFormats; i++) { + if (!formatAlreadySaved(formatBuffer[i])) { + if (formatBuffer[i].frameFormat == ADUVC_FrameMJPEG && + formatBuffer[bestFormatIndex].frameFormat != ADUVC_FrameMJPEG) { bestFormatIndex = i; - } - else if(formatBuffer[i].xSize > formatBuffer[bestFormatIndex].xSize){ + } else if (formatBuffer[i].xSize > formatBuffer[bestFormatIndex].xSize) { bestFormatIndex = i; - } - else if(formatBuffer[i].framerate > formatBuffer[bestFormatIndex].framerate){ + } else if (formatBuffer[i].framerate > formatBuffer[bestFormatIndex].framerate) { bestFormatIndex = i; } } } - 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); - if(readFormats == 0){ + 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); + if (readFormats == 0) { setIntegerParam(ADMaxSizeX, formatBuffer[bestFormatIndex].xSize); setIntegerParam(ADMaxSizeY, formatBuffer[bestFormatIndex].ySize); } - + readFormats++; } INFO("Done."); return readFormats; } - /** * Function responsible for getting image acquisition information - * Gets the exposure, gamma, backlight comp, brightness, contrast, gain, hue, power line, saturation, and - * sharpness from the camera, and sets the values to the appopriate PVs. Then it refreshes the PVs - * + * Gets the exposure, gamma, backlight comp, brightness, contrast, gain, hue, power line, + * saturation, and sharpness from the camera, and sets the values to the appopriate PVs. Then it + * refreshes the PVs + * * @return: void */ -void ADUVC::getDeviceImageInformation(){ +void ADUVC::getDeviceImageInformation() { const char* functionName = "getDeviceImageInformation"; uint32_t exposure; - uint16_t gamma, backlightCompensation, contrast, gain, saturation, sharpness; + uint16_t gamma, backlightCompensation, contrast, gain, saturation, sharpness; int16_t brightness, hue; uint8_t powerLineFrequency, panSpeed, tiltSpeed; int8_t pan, tilt; DEBUG("Population camera image information for PVs"); - //get values from UVC camera + // get values from UVC camera uvc_get_exposure_abs(pdeviceHandle, &exposure, UVC_GET_CUR); uvc_get_gamma(pdeviceHandle, &gamma, UVC_GET_CUR); uvc_get_backlight_compensation(pdeviceHandle, &backlightCompensation, UVC_GET_CUR); @@ -406,8 +383,7 @@ void ADUVC::getDeviceImageInformation(){ this->zoomStepSize = (int) ((this->zoomMax - this->zoomMin) / this->zoomSteps); this->currentZoom = this->zoomMin; - - //put values into appropriate PVs + // put values into appropriate PVs setDoubleParam(ADAcquireTime, (double) exposure); setIntegerParam(ADUVC_Gamma, (int) gamma); setIntegerParam(ADUVC_BacklightCompensation, (int) backlightCompensation); @@ -421,11 +397,10 @@ void ADUVC::getDeviceImageInformation(){ setIntegerParam(ADUVC_PanSpeed, (int) panSpeed); setIntegerParam(ADUVC_TiltSpeed, (int) tiltSpeed); - //refresh PV values + // refresh PV values callParamCallbacks(); } - /* * Function responsible for getting device information once device has been connected. * Calls the uvc_get_device_descriptor function from libuvc, and gets the manufacturer, @@ -433,13 +408,14 @@ void ADUVC::getDeviceImageInformation(){ * * @return: void */ -void ADUVC::getDeviceInformation(){ +void ADUVC::getDeviceInformation() { static const char* functionName = "getDeviceInformation"; DEBUG("Getting device information"); - + char modelName[50]; - if(pdeviceInfo->manufacturer!=NULL) setStringParam(ADManufacturer, pdeviceInfo->manufacturer); - if(pdeviceInfo->serialNumber!=NULL) { + if (pdeviceInfo->manufacturer != NULL) + setStringParam(ADManufacturer, pdeviceInfo->manufacturer); + if (pdeviceInfo->serialNumber != NULL) { setStringParam(ADSerialNumber, pdeviceInfo->serialNumber); } else { // If serial number is not available, fall back to product ID @@ -457,19 +433,18 @@ void ADUVC::getDeviceInformation(){ callParamCallbacks(); } - /** * Function responsible for converting value from PV into UVC frame format type - * + * * @return: uvc_frame_format -> conversion if valid, unknown if invalid */ -uvc_frame_format ADUVC::getFormatFromPV(){ +uvc_frame_format ADUVC::getFormatFromPV() { const char* functionName = "getFormatFromPV"; int format; getIntegerParam(ADUVC_ImageFormat, &format); ADUVC_FrameFormat_t frameFormat = (ADUVC_FrameFormat_t) format; - switch(frameFormat){ + switch (frameFormat) { case ADUVC_FrameMJPEG: return UVC_FRAME_FORMAT_MJPEG; case ADUVC_FrameRGB: @@ -490,8 +465,6 @@ uvc_frame_format ADUVC::getFormatFromPV(){ } } - - //---------------------------------------------------------------------- // UVC acquisition start and stop functions //---------------------------------------------------------------------- @@ -499,13 +472,13 @@ uvc_frame_format ADUVC::getFormatFromPV(){ /* * Function that starts the acquisition of the camera. * In the case of UVC devices, a function is called to first negotiate a stream with the camera at - * a particular resolution and frame rate. Then the uvc_start_streaming function is called, with a + * a particular resolution and frame rate. Then the uvc_start_streaming function is called, with a * function name being passed as a parameter as the callback function. * * @params[in]: imageFormat -> type of image format to use * @return: uvc_error_t -> return 0 if successful, otherwise return error code */ -uvc_error_t ADUVC::acquireStart(uvc_frame_format imageFormat){ +uvc_error_t ADUVC::acquireStart(uvc_frame_format imageFormat) { static const char* functionName = "acquireStart"; // get values for image format from PVs set in IOC shell @@ -516,39 +489,38 @@ uvc_error_t ADUVC::acquireStart(uvc_frame_format imageFormat){ getIntegerParam(ADSizeX, &xsize); getIntegerParam(ADSizeY, &ysize); - INFO_ARGS("Starting acquisition: x-size: %d, y-size %d, framerate %d", - xsize, ysize, framerate); - - deviceStatus = uvc_get_stream_ctrl_format_size(pdeviceHandle, &deviceStreamCtrl, - imageFormat, xsize, ysize, framerate); + INFO_ARGS("Starting acquisition: x-size: %d, y-size %d, framerate %d", xsize, ysize, framerate); + + deviceStatus = uvc_get_stream_ctrl_format_size(pdeviceHandle, &deviceStreamCtrl, imageFormat, + xsize, ysize, framerate); - if(imageFormat == UVC_FRAME_FORMAT_UNCOMPRESSED) INFO("Opening uncompressed stream..."); + if (imageFormat == UVC_FRAME_FORMAT_UNCOMPRESSED) INFO("Opening uncompressed stream..."); - if(deviceStatus<0){ + if (deviceStatus < 0) { ERR("Cannot start acquisition! Invalid frame format"); deviceStatus = UVC_ERROR_NOT_SUPPORTED; reportUVCError(deviceStatus, functionName); acquireStop(); callParamCallbacks(); return deviceStatus; - } - else{ + } else { setIntegerParam(ADNumImagesCounter, 0); callParamCallbacks(); - - // Here is where we initialize the stream and set the callback function + + // Here is where we initialize the stream and set the callback function // to the static wrapper and pass 'this' as the void pointer. // This function is in the form: // uvc_start_streaming(device_handle, device_stream_ctrl*, Callback Function* , void*, int) INFO("Starting image stream callback..."); - deviceStatus = uvc_start_streaming(pdeviceHandle, &deviceStreamCtrl, ADUVC::newFrameCallbackWrapper, this, 0); - - if(deviceStatus != UVC_SUCCESS){ + deviceStatus = uvc_start_streaming(pdeviceHandle, &deviceStreamCtrl, + ADUVC::newFrameCallbackWrapper, this, 0); + + if (deviceStatus != UVC_SUCCESS) { reportUVCError(deviceStatus, functionName); setIntegerParam(ADAcquire, 0); setIntegerParam(ADStatus, ADStatusIdle); callParamCallbacks(); - } else{ + } else { setIntegerParam(ADStatus, ADStatusAcquire); updateStatus("Started acquisition"); callParamCallbacks(); @@ -558,15 +530,13 @@ uvc_error_t ADUVC::acquireStart(uvc_frame_format imageFormat){ return deviceStatus; } - /* * Function responsible for stopping aquisition of images from UVC camera * Calls uvc_stop_streaming function * * @return: void */ -void ADUVC::acquireStop(){ - +void ADUVC::acquireStop() { static const char* functionName = "acquireStop"; INFO("Stopping acquisition..."); @@ -576,7 +546,7 @@ void ADUVC::acquireStop(){ // reset the validatedFrameSize flag this->validatedFrameSize = false; - //update PV values + // update PV values setIntegerParam(ADStatus, ADStatusIdle); setIntegerParam(ADAcquire, 0); callParamCallbacks(); @@ -585,27 +555,24 @@ void ADUVC::acquireStop(){ INFO("Done."); } - - //------------------------------------------------------- // 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){ +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){ + if (adjust == 0) { this->validatedFrameSize = true; return; } @@ -618,13 +585,12 @@ void ADUVC::checkValidFrameSize(uvc_frame_t* frame){ getIntegerParam(ADSizeY, ®_sizey); int computedBytes = reg_sizex * reg_sizey; - if((NDDataType_t) dataType == NDUInt16 || (NDDataType_t) dataType == NDInt16) + if ((NDDataType_t) dataType == NDUInt16 || (NDDataType_t) dataType == NDInt16) computedBytes = computedBytes * 2; - if((NDColorMode_t) colorMode == NDColorModeRGB1) - computedBytes = computedBytes * 3; + if ((NDColorMode_t) colorMode == NDColorModeRGB1) computedBytes = computedBytes * 3; int num_bytes = frame->data_bytes; - if(computedBytes == num_bytes){ + if (computedBytes == num_bytes) { this->validatedFrameSize = true; return; } @@ -633,23 +599,24 @@ void ADUVC::checkValidFrameSize(uvc_frame_t* frame){ int xsize = frame->width; int ysize = frame->height; - int res = num_bytes / xsize; - res = res / ysize; - switch(res) { + 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); + 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); + 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); + // 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: ERR("Couldn't validate frame size."); @@ -659,29 +626,30 @@ void ADUVC::checkValidFrameSize(uvc_frame_t* frame){ 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 - * inside the callback function can only be run by using the driver name. Because libuvc allows for a void* - * to be passed through the callback function, however, the solution is to pass 'this' as the void pointer, - * cast it as an ADUVC pointer, and simply run the non-static callback function with that object. - * + * This is necessary beacuse the callback function must be static for libuvc, meaning that function + * calls inside the callback function can only be run by using the driver name. Because libuvc + * allows for a void* to be passed through the callback function, however, the solution is to pass + * 'this' as the void pointer, cast it as an ADUVC pointer, and simply run the non-static callback + * function with that object. + * * @params[in]: frame -> pointer to uvc_frame received - * @params[out]: ptr -> 'this' cast as a void pointer. It is cast back to ADUVC object and then new frame callback is called + * @params[out]: ptr -> 'this' cast as a void pointer. It is cast back to ADUVC object and then + * new frame callback is called * @return: void */ -void ADUVC::newFrameCallbackWrapper(uvc_frame_t* frame, void* ptr){ +void ADUVC::newFrameCallbackWrapper(uvc_frame_t* frame, void* ptr) { ADUVC* pPvt = ((ADUVC*) ptr); pPvt->newFrameCallback(frame, pPvt); } - /* * Function responsible for converting between a uvc_frame_t type image to * the EPICS area detector standard NDArray type. First, we convert any given uvc_frame to * the rgb format. This is because all of the supported uvc formats can be converted into this type, - * simplyfying the conversion process. Then, the NDDataType is taken into account, and a scaling factor is used + * simplyfying the conversion process. Then, the NDDataType is taken into account, and a scaling + * factor is used * * @params[in]: frame -> frame collected from the uvc camera * @params[out]: pArray -> output of function. NDArray conversion of uvc frame @@ -690,39 +658,36 @@ void ADUVC::newFrameCallbackWrapper(uvc_frame_t* frame, void* ptr){ * @params[in]: imBytes -> number of bytes in the image * @return: void, but output into pArray */ -asynStatus ADUVC::uvc2NDArray(uvc_frame_t* frame, NDArray* pArray, - NDDataType_t dataType, NDColorMode_t colorMode, size_t imBytes){ - +asynStatus ADUVC::uvc2NDArray(uvc_frame_t* frame, NDArray* pArray, NDDataType_t dataType, + NDColorMode_t colorMode, size_t imBytes) { static const char* functionName = "uvc2NDArray"; asynStatus status = asynSuccess; // if data is grayscale, we do not need to convert it, we just copy over the data. - - if(colorMode == NDColorModeMono){ - if(frame->data_bytes != imBytes){ + + if (colorMode == NDColorModeMono) { + if (frame->data_bytes != imBytes) { ERR_ARGS("Error invalid frame size. Frame has %d bytes and array has %d bytes", - (int) frame->data_bytes, (int) imBytes); + (int) frame->data_bytes, (int) imBytes); status = asynError; + } else { + if (dataType == NDUInt8 || dataType == NDInt8) { + memcpy((unsigned char*) pArray->pData, (unsigned char*) frame->data, imBytes); + } else + memcpy((uint16_t*) pArray->pData, (uint16_t*) frame->data, imBytes); } - else{ - if(dataType == NDUInt8 || dataType == NDInt8){ - memcpy((unsigned char*) pArray->pData,(unsigned char*) frame->data, imBytes); - } - else memcpy((uint16_t*) pArray->pData, (uint16_t*) frame->data, imBytes); - } - } else{ - //otherwise we need to convert to a common type (rgb) - // non grayscale images have 3 channels, so frame size * 3 - uvc_frame_t* rgb = uvc_allocate_frame(frame->width * frame->height *3); - - if(!rgb){ + } else { + // otherwise we need to convert to a common type (rgb) + // non grayscale images have 3 channels, so frame size * 3 + uvc_frame_t* rgb = uvc_allocate_frame(frame->width * frame->height * 3); + + if (!rgb) { ERR("Unable to allocate frame!"); status = asynError; - } - else{ + } else { // convert any uvc frame format to rgb uvc_frame_format frameFormat = frame->frame_format; - switch(frameFormat){ + switch (frameFormat) { case UVC_FRAME_FORMAT_YUYV: deviceStatus = uvc_any2rgb(frame, rgb); break; @@ -737,24 +702,22 @@ asynStatus ADUVC::uvc2NDArray(uvc_frame_t* frame, NDArray* pArray, break; default: ERR("Unsupported UVC format!"); - + uvc_free_frame(rgb); status = asynError; } - - if(status != asynError){ - if(deviceStatus<0){ + + if (status != asynError) { + if (deviceStatus < 0) { reportUVCError(deviceStatus, functionName); status = asynError; - } - else{ - if(rgb->data_bytes != imBytes){ + } else { + if (rgb->data_bytes != imBytes) { ERR_ARGS("Invalid frame sizeFrame has %d bytes and array has %d bytes\n", - (int) rgb->data_bytes, (int) imBytes); + (int) rgb->data_bytes, (int) imBytes); status = asynError; - } - else{ + } else { memcpy(pArray->pData, rgb->data, imBytes); } } @@ -764,19 +727,19 @@ asynStatus ADUVC::uvc2NDArray(uvc_frame_t* frame, NDArray* pArray, } // only push image if the data transfer was successful - if(status == asynSuccess){ + if (status == asynSuccess) { pArray->pAttributeList->add("ColorMode", "Color Mode", NDAttrInt32, &colorMode); - - //increment the array counter + + // increment the array counter int arrayCounter; getIntegerParam(NDArrayCounter, &arrayCounter); arrayCounter++; setIntegerParam(NDArrayCounter, arrayCounter); - - //refresh PVs + + // refresh PVs callParamCallbacks(); - - //Sends image to the ArrayDataPV + + // Sends image to the ArrayDataPV getAttributes(pArray->pAttributeList); doCallbacksGenericPointer(pArray, NDArrayData, 0); } @@ -786,46 +749,46 @@ asynStatus ADUVC::uvc2NDArray(uvc_frame_t* frame, NDArray* pArray, return status; } - /* * Function that performs the callbacks onto new frames generated by the camera. * First, a new NDArray pointer is allocated, then the given uvc_frame pointer is converted - * into this allocated NDArray. Then, based on the operating mode, the acquisition moves to the + * into this allocated NDArray. Then, based on the operating mode, the acquisition moves to the * next frame, or stops. The NDArray is passed on to the doCallbacksGenericPointer function. * * @params[in]: frame -> uvc_frame recieved from the camera * @params[in]: ptr -> void pointer with data from the frame * @return: void */ -void ADUVC::newFrameCallback(uvc_frame_t* frame, void* ptr){ +void ADUVC::newFrameCallback(uvc_frame_t* frame, void* ptr) { NDArray* pArray; int dataType; int operatingMode; int colorMode; int ndims; - //TODO: Timestamps for images - //epicsTimeStamp currentTime; + // TODO: Timestamps for images + // 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) + if (!this->validatedFrameSize && getFormatFromPV() == UVC_FRAME_FORMAT_UNCOMPRESSED) checkValidFrameSize(frame); getIntegerParam(NDColorMode, &colorMode); getIntegerParam(NDDataType, &dataType); - if((NDColorMode_t) colorMode == NDColorModeMono) ndims = 2; - else ndims = 3; - + if ((NDColorMode_t) colorMode == NDColorModeMono) + ndims = 2; + else + ndims = 3; + size_t dims[ndims]; - if(ndims == 2){ + if (ndims == 2) { dims[0] = frame->width; dims[1] = frame->height; - } - else{ + } else { dims[0] = 3; dims[1] = frame->width; dims[2] = frame->height; @@ -835,11 +798,10 @@ void ADUVC::newFrameCallback(uvc_frame_t* frame, void* ptr){ // allocate memory for a new NDArray, and set pArray to a pointer for this memory this->pArrays[0] = pNDArrayPool->alloc(ndims, dims, (NDDataType_t) dataType, 0, NULL); - - if(this->pArrays[0]!=NULL){ - pArray = this->pArrays[0]; - } - else{ + + if (this->pArrays[0] != NULL) { + pArray = this->pArrays[0]; + } else { ERR("Unable to allocate array!"); return; } @@ -847,7 +809,7 @@ void ADUVC::newFrameCallback(uvc_frame_t* frame, void* ptr){ updateTimeStamp(&pArray->epicsTS); int pixelSize = 1; - switch(dataType){ + switch (dataType) { case NDUInt8: case NDInt8: pixelSize = 1; @@ -861,7 +823,7 @@ void ADUVC::newFrameCallback(uvc_frame_t* frame, void* ptr){ // Update camera image parameters size_t dataSize = dims[0] * dims[1] * pixelSize; if (ndims == 3) dataSize *= dims[2]; - setIntegerParam(NDArraySize, (int)dataSize); + setIntegerParam(NDArraySize, (int) dataSize); setIntegerParam(NDArraySizeX, frame->width); setIntegerParam(NDArraySizeY, frame->height); @@ -870,27 +832,27 @@ void ADUVC::newFrameCallback(uvc_frame_t* frame, void* ptr){ numImages++; setIntegerParam(ADNumImagesCounter, numImages); pArray->uniqueId = numImages; - + // Copy data from our uvc frame into our NDArray uvc2NDArray(frame, pArray, (NDDataType_t) dataType, (NDColorMode_t) colorMode, dataSize); - //single shot mode stops after one images - if(operatingMode == ADImageSingle){ + // single shot mode stops after one images + if (operatingMode == ADImageSingle) { acquireStop(); } // block shot mode stops once numImages reaches the number of desired images - else if(operatingMode == ADImageMultiple){ + else if (operatingMode == ADImageMultiple) { int desiredImages; getIntegerParam(ADNumImages, &desiredImages); - - if(numImages>=desiredImages){ + + if (numImages >= desiredImages) { acquireStop(); } } // Otherwise, if continuous mode, just keep looping, if not then we have an unsupported mode - else if(operatingMode != ADImageContinuous){ + else if (operatingMode != ADImageContinuous) { ERR("Unsupported operating mode"); acquireStop(); @@ -899,40 +861,39 @@ void ADUVC::newFrameCallback(uvc_frame_t* frame, void* ptr){ /** * Function that adjust camera pan/tilt options if supported - * + * * @params[in]: panDirection -> -1, 0, 1 - left, stay, right * @params[in]: tiltDirection -> -1, 0, 1 - up stay down * @return: status */ -asynStatus ADUVC::processPanTilt(int panDirection, int tiltDirection){ - +asynStatus ADUVC::processPanTilt(int panDirection, int tiltDirection) { int panSpeed, tiltSpeed; double panTiltStepTime; getIntegerParam(ADUVC_PanSpeed, &panSpeed); getIntegerParam(ADUVC_TiltSpeed, &tiltSpeed); getDoubleParam(ADUVC_PanTiltStep, &panTiltStepTime); - if(this->pdevice == NULL) return asynError; - + if (this->pdevice == NULL) return asynError; + const char* functionName = "processPanTilt"; asynStatus status = asynSuccess; - + deviceStatus = uvc_set_pantilt_rel(pdeviceHandle, (int8_t) panDirection, (uint8_t) panSpeed, - (int8_t) tiltDirection, (uint8_t) tiltSpeed); - - if(deviceStatus < 0){ + (int8_t) tiltDirection, (uint8_t) tiltSpeed); + + if (deviceStatus < 0) { reportUVCError(deviceStatus, functionName); status = asynError; } - else{ + else { epicsThreadSleep(panTiltStepTime); - deviceStatus = uvc_set_pantilt_rel(pdeviceHandle, 0, (uint8_t) panSpeed, - 0, (uint8_t) tiltSpeed); - + deviceStatus = + uvc_set_pantilt_rel(pdeviceHandle, 0, (uint8_t) panSpeed, 0, (uint8_t) tiltSpeed); - if(deviceStatus == UVC_SUCCESS) updateStatus("Processed Pan/Tilt"); - else{ + if (deviceStatus == UVC_SUCCESS) + updateStatus("Processed Pan/Tilt"); + else { reportUVCError(deviceStatus, functionName); status = asynError; } @@ -941,52 +902,44 @@ asynStatus ADUVC::processPanTilt(int panDirection, int tiltDirection){ return status; } - /** * Function that sets the degree of sharpening. Too high will cause oversharpening - * + * * @params[in]: sharpness -> degree of sharpening * @return: status */ -asynStatus ADUVC::processZoom(int zoomDirection){ +asynStatus ADUVC::processZoom(int zoomDirection) { + if (this->pdevice == NULL) return asynError; - if(this->pdevice == NULL) return asynError; - const char* functionName = "processZoom"; - + asynStatus status = asynSuccess; - if(zoomDirection == 1){ + if (zoomDirection == 1) { currentZoom += zoomStepSize; - if(currentZoom > zoomMax) currentZoom = zoomMax; - } - else{ + if (currentZoom > zoomMax) currentZoom = zoomMax; + } else { currentZoom -= zoomStepSize; - if(currentZoom < zoomMin) currentZoom = zoomMin; + if (currentZoom < zoomMin) currentZoom = zoomMin; } - - //deviceStatus = uvc_set_zoom_rel(pdeviceHandle, 1, , 10); - deviceStatus = uvc_set_zoom_abs(pdeviceHandle, currentZoom); + // deviceStatus = uvc_set_zoom_rel(pdeviceHandle, 1, , 10); + deviceStatus = uvc_set_zoom_abs(pdeviceHandle, currentZoom); - if(deviceStatus < 0){ + if (deviceStatus < 0) { reportUVCError(deviceStatus, functionName); status = asynError; - } - else{ + } else { updateStatus("Processed Zoom"); } - + return status; } - - //------------------------------------------------------------------------- // ADDriver function overwrites //------------------------------------------------------------------------- - /* * Function overwriting ADDriver base function. * Takes in a function (PV) changes, and a value it is changing to, and processes the input @@ -995,7 +948,7 @@ asynStatus ADUVC::processZoom(int zoomDirection){ * @params[in]: value -> int32 value to write * @return: asynStatus -> success if write was successful, else failure */ -asynStatus ADUVC::writeInt32(asynUser* pasynUser, epicsInt32 value){ +asynStatus ADUVC::writeInt32(asynUser* pasynUser, epicsInt32 value) { int function = pasynUser->reason; int acquiring; asynStatus status = asynSuccess; @@ -1008,52 +961,69 @@ asynStatus ADUVC::writeInt32(asynUser* pasynUser, epicsInt32 value){ status = setIntegerParam(function, value); // Start/Stop acquisition if corresponding button is pressed - if(function == ADAcquire){ - if(value && !acquiring){ + if (function == ADAcquire) { + if (value && !acquiring) { deviceStatus = acquireStart(getFormatFromPV()); - if(deviceStatus < 0){ + if (deviceStatus < 0) { reportUVCError(deviceStatus, functionName); return asynError; } } - if(!value && acquiring){ + if (!value && acquiring) { acquireStop(); } } // Stop acquistion and apply selected format if the apply format button is pressed. - else if(function == ADUVC_ApplyFormat && value == 1){ - if(acquiring) - acquireStop(); + else if (function == ADUVC_ApplyFormat && value == 1) { + if (acquiring) acquireStop(); applyCameraFormat(); } // Update description if camera format selection is changed - else if(function == ADUVC_CameraFormat) updateCameraFormatDesc(); - else if(function == ADUVC_LogLevel) this->logLevel = (ADUVC_LogLevel_t) value; + else if (function == ADUVC_CameraFormat) + updateCameraFormatDesc(); + else if (function == ADUVC_LogLevel) + this->logLevel = (ADUVC_LogLevel_t) value; // Stop acqusition if image mode is changed - else if(function == ADImageMode && acquiring == 1) acquireStop(); + else if (function == ADImageMode && acquiring == 1) + acquireStop(); // Stop acquisition if image format or framerate are changed - else if((function == ADUVC_ImageFormat || function == ADUVC_Framerate) && acquiring == 1) acquireStop(); - else if(function == ADUVC_ZoomIn) processZoom(1); - else if(function == ADUVC_ZoomOut) processZoom(-1); - else if(function == ADUVC_PanLeft) processPanTilt(-1, 0); - else if(function == ADUVC_PanRight) processPanTilt(1, 0); - else if(function == ADUVC_TiltUp) processPanTilt(0, 1); - else if(function == ADUVC_TiltDown) processPanTilt(0, -1); + else if ((function == ADUVC_ImageFormat || function == ADUVC_Framerate) && acquiring == 1) + acquireStop(); + else if (function == ADUVC_ZoomIn) + processZoom(1); + else if (function == ADUVC_ZoomOut) + processZoom(-1); + else if (function == ADUVC_PanLeft) + processPanTilt(-1, 0); + else if (function == ADUVC_PanRight) + processPanTilt(1, 0); + else if (function == ADUVC_TiltUp) + processPanTilt(0, 1); + else if (function == ADUVC_TiltDown) + processPanTilt(0, -1); else { if (function >= ADUVC_FIRST_PARAM) { uvc_error_t deviceStatus = UVC_SUCCESS; - if(function == ADUVC_Gamma) deviceStatus = uvc_set_gamma(this->pdeviceHandle, value); - else if(function == ADUVC_BacklightCompensation) deviceStatus = uvc_set_backlight_compensation(this->pdeviceHandle, value); - else if(function == ADUVC_Brightness) deviceStatus = uvc_set_brightness(this->pdeviceHandle, value); - else if(function == ADUVC_Contrast) deviceStatus = uvc_set_contrast(this->pdeviceHandle, value); - else if(function == ADUVC_Hue) deviceStatus = uvc_set_hue(this->pdeviceHandle, value); - else if(function == ADUVC_PowerLine) deviceStatus = uvc_set_power_line_frequency(this->pdeviceHandle, value); - else if(function == ADUVC_Saturation) deviceStatus = uvc_set_saturation(this->pdeviceHandle, value); - else if(function == ADUVC_Sharpness) deviceStatus = uvc_set_sharpness(this->pdeviceHandle, value); + if (function == ADUVC_Gamma) + deviceStatus = uvc_set_gamma(this->pdeviceHandle, value); + else if (function == ADUVC_BacklightCompensation) + deviceStatus = uvc_set_backlight_compensation(this->pdeviceHandle, value); + else if (function == ADUVC_Brightness) + deviceStatus = uvc_set_brightness(this->pdeviceHandle, value); + else if (function == ADUVC_Contrast) + deviceStatus = uvc_set_contrast(this->pdeviceHandle, value); + else if (function == ADUVC_Hue) + deviceStatus = uvc_set_hue(this->pdeviceHandle, value); + else if (function == ADUVC_PowerLine) + deviceStatus = uvc_set_power_line_frequency(this->pdeviceHandle, value); + else if (function == ADUVC_Saturation) + deviceStatus = uvc_set_saturation(this->pdeviceHandle, value); + else if (function == ADUVC_Sharpness) + deviceStatus = uvc_set_sharpness(this->pdeviceHandle, value); if (deviceStatus != UVC_SUCCESS) { reportUVCError(deviceStatus, functionName); status = asynError; @@ -1067,14 +1037,14 @@ asynStatus ADUVC::writeInt32(asynUser* pasynUser, epicsInt32 value){ callParamCallbacks(); // Log status updates - if(status) { + if (status) { ERR_ARGS("Failed to write %d to function %d", value, function); - } else DEBUG_ARGS("Wrote %d to function %d", value, function); + } else + DEBUG_ARGS("Wrote %d to function %d", value, function); return status; } - /* * Function overwriting ADDriver base function. * Takes in a function (PV) changes, and a value it is changing to, and processes the input @@ -1084,7 +1054,7 @@ asynStatus ADUVC::writeInt32(asynUser* pasynUser, epicsInt32 value){ * @params[in]: value -> int32 value to write * @return: asynStatus -> success if write was successful, else failure */ -asynStatus ADUVC::writeFloat64(asynUser* pasynUser, epicsFloat64 value){ +asynStatus ADUVC::writeFloat64(asynUser* pasynUser, epicsFloat64 value) { int function = pasynUser->reason; int acquiring; asynStatus status = asynSuccess; @@ -1095,41 +1065,41 @@ asynStatus ADUVC::writeFloat64(asynUser* pasynUser, epicsFloat64 value){ status = setDoubleParam(function, value); uvc_error_t deviceStatus = UVC_SUCCESS; - if(function == ADAcquireTime){ - if(acquiring) acquireStop(); + if (function == ADAcquireTime) { + if (acquiring) acquireStop(); deviceStatus = uvc_set_exposure_abs(this->pdeviceHandle, (uint32_t) value / 0.0001); - } - else if(function == ADGain) deviceStatus = uvc_set_gain(this->pdeviceHandle, (int) value); - else{ - if(function < ADUVC_FIRST_PARAM){ + } else if (function == ADGain) + deviceStatus = uvc_set_gain(this->pdeviceHandle, (int) value); + else { + if (function < ADUVC_FIRST_PARAM) { status = ADDriver::writeFloat64(pasynUser, value); } } - if (deviceStatus != UVC_SUCCESS){ + if (deviceStatus != UVC_SUCCESS) { reportUVCError(deviceStatus, functionName); status = asynError; } callParamCallbacks(); - if(status){ + if (status) { ERR_ARGS("Failed to write %lf to function %d", value, function); - } else DEBUG_ARGS("Wrote %lf to function %d", value, function); + } else + DEBUG_ARGS("Wrote %lf to function %d", value, function); return status; } - /* * Function used for reporting ADUVC device and library information to a external * log file. The function first prints all libuvc specific information to the file, * then continues on to the base ADDriver 'report' function - * + * * @params[in]: fp -> pointer to log file * @params[in]: details -> number of details to write to the file * @return: void */ -void ADUVC::report(FILE* fp, int details){ +void ADUVC::report(FILE* fp, int details) { const char* functionName = "report"; int framerate; int height; @@ -1137,17 +1107,17 @@ void ADUVC::report(FILE* fp, int details){ DEBUG("Reporting to external log file"); - if(details > 0){ - fprintf(fp, " LIBUVC Version -> %d.%d.%d\n", - LIBUVC_VERSION_MAJOR, LIBUVC_VERSION_MINOR, LIBUVC_VERSION_PATCH); + if (details > 0) { + fprintf(fp, " LIBUVC Version -> %d.%d.%d\n", LIBUVC_VERSION_MAJOR, + LIBUVC_VERSION_MINOR, LIBUVC_VERSION_PATCH); fprintf(fp, " -----------------------------------------------------\n"); - - if(!connected){ + + if (!connected) { fprintf(fp, " No connected devices\n"); ADDriver::report(fp, details); return; } - + fprintf(fp, " Connected Device Information\n"); fprintf(fp, " Serial number -> %s\n", pdeviceInfo->serialNumber); fprintf(fp, " VendorID -> %d\n", pdeviceInfo->idVendor); @@ -1157,24 +1127,21 @@ void ADUVC::report(FILE* fp, int details){ getIntegerParam(ADUVC_Framerate, &framerate); getIntegerParam(ADSizeX, &width); getIntegerParam(ADSizeY, &height); - + fprintf(fp, " Camera Framerate -> %d\n", framerate); fprintf(fp, " Image Width -> %d\n", width); fprintf(fp, " Image Height -> %d\n", height); fprintf(fp, " --------------------------------------------\n\n"); - + ADDriver::report(fp, details); } } - - //---------------------------------------------------------------------------- // ADUVC Constructor/Destructor //---------------------------------------------------------------------------- - /* * Constructor for ADUVC driver. Most params are passed to the parent ADDriver constructor. * Connects to the camera, then gets device information, and is ready to aquire images. @@ -1183,50 +1150,48 @@ void ADUVC::report(FILE* fp, int details){ * @params[in]: serialOrProductID -> serial number of device to connect to */ ADUVC::ADUVC(const char* portName, const char* serialOrProductID) - : ADDriver(portName, 1, NUM_UVC_PARAMS, 0, 0, 0, 0, 0, 1, 0, 0){ - + : ADDriver(portName, 1, NUM_UVC_PARAMS, 0, 0, 0, 0, 0, 1, 0, 0) { static const char* functionName = "ADUVC"; // Create PV Params - createParam(ADUVC_UVCComplianceLevelString, asynParamInt32, &ADUVC_UVCComplianceLevel); - createParam(ADUVC_ReferenceCountString, asynParamInt32, &ADUVC_ReferenceCount); - createParam(ADUVC_FramerateString, asynParamInt32, &ADUVC_Framerate); - createParam(ADUVC_ImageFormatString, asynParamInt32, &ADUVC_ImageFormat); - createParam(ADUVC_CameraFormatString, asynParamInt32, &ADUVC_CameraFormat); - createParam(ADUVC_LogLevelString, asynParamInt32, &ADUVC_LogLevel); - 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); - createParam(ADUVC_HueString, asynParamInt32, &ADUVC_Hue); - createParam(ADUVC_SaturationString, asynParamInt32, &ADUVC_Saturation); - createParam(ADUVC_GammaString, asynParamInt32, &ADUVC_Gamma); - createParam(ADUVC_BacklightCompensationString, asynParamInt32, &ADUVC_BacklightCompensation); - createParam(ADUVC_SharpnessString, asynParamInt32, &ADUVC_Sharpness); - createParam(ADUVC_PanLeftString, asynParamInt32, &ADUVC_PanLeft); - createParam(ADUVC_PanRightString, asynParamInt32, &ADUVC_PanRight); - createParam(ADUVC_TiltUpString, asynParamInt32, &ADUVC_TiltUp); - createParam(ADUVC_TiltDownString, asynParamInt32, &ADUVC_TiltDown); - createParam(ADUVC_ZoomInString, asynParamInt32, &ADUVC_ZoomIn); - createParam(ADUVC_ZoomOutString, asynParamInt32, &ADUVC_ZoomOut); - createParam(ADUVC_PanSpeedString, asynParamInt32, &ADUVC_PanSpeed); - createParam(ADUVC_TiltSpeedString, asynParamInt32, &ADUVC_TiltSpeed); - createParam(ADUVC_PanTiltStepString, asynParamFloat64, &ADUVC_PanTiltStep); - - //sets libuvc version + createParam(ADUVC_UVCComplianceLevelString, asynParamInt32, &ADUVC_UVCComplianceLevel); + createParam(ADUVC_ReferenceCountString, asynParamInt32, &ADUVC_ReferenceCount); + createParam(ADUVC_FramerateString, asynParamInt32, &ADUVC_Framerate); + createParam(ADUVC_ImageFormatString, asynParamInt32, &ADUVC_ImageFormat); + createParam(ADUVC_CameraFormatString, asynParamInt32, &ADUVC_CameraFormat); + createParam(ADUVC_LogLevelString, asynParamInt32, &ADUVC_LogLevel); + 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); + createParam(ADUVC_HueString, asynParamInt32, &ADUVC_Hue); + createParam(ADUVC_SaturationString, asynParamInt32, &ADUVC_Saturation); + createParam(ADUVC_GammaString, asynParamInt32, &ADUVC_Gamma); + createParam(ADUVC_BacklightCompensationString, asynParamInt32, &ADUVC_BacklightCompensation); + createParam(ADUVC_SharpnessString, asynParamInt32, &ADUVC_Sharpness); + createParam(ADUVC_PanLeftString, asynParamInt32, &ADUVC_PanLeft); + createParam(ADUVC_PanRightString, asynParamInt32, &ADUVC_PanRight); + createParam(ADUVC_TiltUpString, asynParamInt32, &ADUVC_TiltUp); + createParam(ADUVC_TiltDownString, asynParamInt32, &ADUVC_TiltDown); + createParam(ADUVC_ZoomInString, asynParamInt32, &ADUVC_ZoomIn); + createParam(ADUVC_ZoomOutString, asynParamInt32, &ADUVC_ZoomOut); + createParam(ADUVC_PanSpeedString, asynParamInt32, &ADUVC_PanSpeed); + createParam(ADUVC_TiltSpeedString, asynParamInt32, &ADUVC_TiltSpeed); + createParam(ADUVC_PanTiltStepString, asynParamFloat64, &ADUVC_PanTiltStep); + + // sets libuvc version char uvcVersionString[25]; - epicsSnprintf(uvcVersionString, sizeof(uvcVersionString), - "%d.%d.%d", LIBUVC_VERSION_MAJOR, - LIBUVC_VERSION_MINOR, LIBUVC_VERSION_PATCH); + epicsSnprintf(uvcVersionString, sizeof(uvcVersionString), "%d.%d.%d", LIBUVC_VERSION_MAJOR, + LIBUVC_VERSION_MINOR, LIBUVC_VERSION_PATCH); setStringParam(ADSDKVersion, uvcVersionString); - //sets driver version + // sets driver version char versionString[25]; - epicsSnprintf(versionString, sizeof(versionString), - "%d.%d.%d", ADUVC_VERSION, ADUVC_REVISION, ADUVC_MODIFICATION); + epicsSnprintf(versionString, sizeof(versionString), "%d.%d.%d", ADUVC_VERSION, ADUVC_REVISION, + ADUVC_MODIFICATION); setStringParam(NDDriverVersion, versionString); @@ -1236,42 +1201,42 @@ ADUVC::ADUVC(const char* portName, const char* serialOrProductID) ADUVC_ConnectionType_t connectionType = UVC_SERIAL; this->pdevice = (uvc_device_t*) calloc(1, sizeof(uvc_device_t)); - uvc_error_t deviceStatus; deviceStatus = uvc_init(&pdeviceContext, NULL); - if(deviceStatus == UVC_SUCCESS){ - + if (deviceStatus == UVC_SUCCESS) { INFO("Initialized UVC context..."); uvc_device_t** deviceList; deviceStatus = uvc_get_device_list(pdeviceContext, &deviceList); int deviceIndex = 0; - while(*(deviceList + deviceIndex) != NULL){ - // Create copy of the device struct, so when we free the list we still have the single device available. + while (*(deviceList + deviceIndex) != NULL) { + // Create copy of the device struct, so when we free the list we still have the single + // device available. memcpy(this->pdevice, *(deviceList + deviceIndex), sizeof(uvc_device_t)); deviceStatus = uvc_get_device_descriptor(this->pdevice, &pdeviceInfo); - if(deviceStatus < 0){ + if (deviceStatus < 0) { reportUVCError(deviceStatus, functionName); } else { // Try checking serial number first, then product ID - if(this->pdeviceInfo->serialNumber != NULL && strcmp(this->pdeviceInfo->serialNumber, serialOrProductID) == 0){ + if (this->pdeviceInfo->serialNumber != NULL && + strcmp(this->pdeviceInfo->serialNumber, serialOrProductID) == 0) { deviceStatus = uvc_open(this->pdevice, &pdeviceHandle); - if(deviceStatus == UVC_SUCCESS){ + if (deviceStatus == UVC_SUCCESS) { connected = true; break; - } else if (deviceStatus == UVC_ERROR_BUSY){ + } else if (deviceStatus == UVC_ERROR_BUSY) { DEBUG("Found device with matching ID, but it was already open!"); foundMatchingDeviceButBusy = true; } - } else if (atoi(serialOrProductID) == this->pdeviceInfo->idProduct){ + } else if (atoi(serialOrProductID) == this->pdeviceInfo->idProduct) { deviceStatus = uvc_open(this->pdevice, &pdeviceHandle); - if(deviceStatus == UVC_SUCCESS) { + if (deviceStatus == UVC_SUCCESS) { connected = true; connectionType = UVC_PRODUCT_ID; break; - } else if (deviceStatus == UVC_ERROR_BUSY){ + } else if (deviceStatus == UVC_ERROR_BUSY) { DEBUG("Found device with matching ID, but it was already open!"); foundMatchingDeviceButBusy = true; } @@ -1282,86 +1247,74 @@ ADUVC::ADUVC(const char* portName, const char* serialOrProductID) } uvc_free_device_list(deviceList, 0); if (connected && connectionType == UVC_SERIAL) { - INFO_ARGS("Connected to UVC device with serial number: %s", this->pdeviceInfo->serialNumber); + INFO_ARGS("Connected to UVC device with serial number: %s", + this->pdeviceInfo->serialNumber); } else if (connected && connectionType == UVC_PRODUCT_ID) { INFO_ARGS("Connected to UVC device with Product ID: %d", this->pdeviceInfo->idProduct); } else if (!connected && foundMatchingDeviceButBusy) { - ERR_ARGS("Found UVC device with serial number or Product ID: %s, but it is busy!", serialOrProductID); + ERR_ARGS("Found UVC device with serial number or Product ID: %s, but it is busy!", + serialOrProductID); } else { - ERR_ARGS("No UVC device found with serial number or Product ID: %s!", serialOrProductID); + ERR_ARGS("No UVC device found with serial number or Product ID: %s!", + serialOrProductID); } - if(connected){ + if (connected) { INFO("Collecting device information and supported acquisition modes..."); readSupportedCameraFormats(); getDeviceInformation(); } else { - free(this->pdevice); uvc_exit(this->pdeviceContext); } - } else{ + } else { ERR("Failed to initialize UVC context!"); } // when epics is exited, delete the instance of this class epicsAtExit(exitCallbackC, this); - } - /* * ADUVC destructor. Called by the exitCallbackC function when IOC is shut down */ -ADUVC::~ADUVC(){ +ADUVC::~ADUVC() { static const char* functionName = "~ADUVC"; INFO("Shutting down ADUVC driver..."); - if(this->pdevice != NULL){ + if (this->pdevice != NULL) { INFO("Disconnecting from UVC device..."); uvc_close(pdeviceHandle); uvc_unref_device(pdevice); } - if(this->pdeviceContext != NULL){ + if (this->pdeviceContext != NULL) { INFO("Exiting UVC context..."); uvc_exit(pdeviceContext); } INFO("Done."); } - //------------------------------------------------------------- // ADUVC ioc shell registration //------------------------------------------------------------- - /* UVCConfig -> These are the args passed to the constructor in the epics config function */ -static const iocshArg UVCConfigArg0 = { "Port name", iocshArgString }; -static const iocshArg UVCConfigArg1 = { "Serial number/Product ID", iocshArgString }; +static const iocshArg UVCConfigArg0 = {"Port name", iocshArgString}; +static const iocshArg UVCConfigArg1 = {"Serial number/Product ID", iocshArgString}; /* Array of config args */ -static const iocshArg * const UVCConfigArgs[] = - { &UVCConfigArg0, &UVCConfigArg1}; - +static const iocshArg* const UVCConfigArgs[] = {&UVCConfigArg0, &UVCConfigArg1}; /* what function to call at config */ -static void configUVCCallFunc(const iocshArgBuf *args) { - ADUVCConfig(args[0].sval, args[1].sval); -} - +static void configUVCCallFunc(const iocshArgBuf* args) { ADUVCConfig(args[0].sval, args[1].sval); } /* information about the configuration function */ -static const iocshFuncDef configUVC = { "ADUVCConfig", 2, UVCConfigArgs }; - +static const iocshFuncDef configUVC = {"ADUVCConfig", 2, UVCConfigArgs}; /* IOC register function */ -static void UVCRegister(void) { - iocshRegister(&configUVC, configUVCCallFunc); -} - +static void UVCRegister(void) { iocshRegister(&configUVC, configUVCCallFunc); } /* external function for IOC register */ extern "C" { - epicsExportRegistrar(UVCRegister); +epicsExportRegistrar(UVCRegister); } - diff --git a/uvcApp/src/ADUVC.h b/uvcApp/src/ADUVC.h index c998e54..eb70d1d 100644 --- a/uvcApp/src/ADUVC.h +++ b/uvcApp/src/ADUVC.h @@ -1,7 +1,8 @@ /* * Header file for the ADUVC EPICS driver * - * This file contains the definitions of PV params, and the definition of the ADUVC class and functions. + * This file contains the definitions of PV params, and the definition of the ADUVC class and + * functions. * * Author: Jakub Wlodek * Created: July 2018 @@ -15,19 +16,16 @@ #define ADUVC_H // version numbers -#define ADUVC_VERSION 2 -#define ADUVC_REVISION 0 +#define ADUVC_VERSION 2 +#define ADUVC_REVISION 0 #define ADUVC_MODIFICATION 0 - // Unless specified during compilation, use 16 as number of supported formats #ifndef SUPPORTED_FORMAT_COUNT #define SUPPORTED_FORMAT_COUNT 16 #endif - -#define SUPPORTED_FORMAT_DESC_BUFF 256 - +#define SUPPORTED_FORMAT_DESC_BUFF 256 // includes extern "C" { @@ -46,87 +44,85 @@ typedef enum ADUVC_LOG_LEVEL { } ADUVC_LogLevel_t; // Error message formatters -#define ERR(msg) \ +#define ERR(msg) \ if (this->logLevel >= ADUVC_LOG_LEVEL_ERROR) \ printf("ERROR | %s::%s: %s\n", driverName, functionName, msg); -#define ERR_ARGS(fmt, ...) \ +#define ERR_ARGS(fmt, ...) \ if (this->logLevel >= ADUVC_LOG_LEVEL_ERROR) \ printf("ERROR | %s::%s: " fmt "\n", driverName, functionName, __VA_ARGS__); // Warning message formatters -#define WARN(msg) \ +#define WARN(msg) \ if (this->logLevel >= ADUVC_LOG_LEVEL_WARNING) \ printf("WARNING | %s::%s: %s\n", driverName, functionName, msg); -#define WARN_ARGS(fmt, ...) \ +#define WARN_ARGS(fmt, ...) \ if (this->logLevel >= ADUVC_LOG_LEVEL_WARNING) \ printf("WARNING | %s::%s: " fmt "\n", driverName, functionName, __VA_ARGS__); // Info message formatters. Because there is no ASYN trace for info messages, we just use `printf` // here. -#define INFO(msg) \ +#define INFO(msg) \ if (this->logLevel >= ADUVC_LOG_LEVEL_INFO) \ printf("INFO | %s::%s: %s\n", driverName, functionName, msg); -#define INFO_ARGS(fmt, ...) \ +#define INFO_ARGS(fmt, ...) \ if (this->logLevel >= ADUVC_LOG_LEVEL_INFO) \ printf("INFO | %s::%s: " fmt "\n", driverName, functionName, __VA_ARGS__); // Debug message formatters -#define DEBUG(msg) \ +#define DEBUG(msg) \ if (this->logLevel >= ADUVC_LOG_LEVEL_DEBUG) \ printf("DEBUG | %s::%s: %s\n", driverName, functionName, msg); -#define DEBUG_ARGS(fmt, ...) \ +#define DEBUG_ARGS(fmt, ...) \ if (this->logLevel >= ADUVC_LOG_LEVEL_DEBUG) \ printf("DEBUG | %s::%s: " fmt "\n", driverName, functionName, __VA_ARGS__); - - // PV String definitions -#define ADUVC_UVCComplianceLevelString "UVC_COMPLIANCE" //asynInt32 -#define ADUVC_ReferenceCountString "UVC_REFCOUNT" //asynInt32 -#define ADUVC_FramerateString "UVC_FRAMERATE" //asynInt32 -#define ADUVC_LogLevelString "UVC_LOG_LEVEL" //asynInt32 -#define ADUVC_ImageFormatString "UVC_FORMAT" //asynInt32 -#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 -#define ADUVC_ContrastString "UVC_CONTRAST" //asynInt32 -#define ADUVC_PowerLineString "UVC_POWER" //asynInt32 -#define ADUVC_HueString "UVC_HUE" //asynInt32 -#define ADUVC_SaturationString "UVC_SATURATION" //asynInt32 -#define ADUVC_SharpnessString "UVC_SHARPNESS" //asynInt32 -#define ADUVC_PanLeftString "UVC_PAN_LEFT" //asynInt32 -#define ADUVC_PanRightString "UVC_PAN_RIGHT" //asynInt32 -#define ADUVC_TiltUpString "UVC_TILT_UP" //asynInt32 -#define ADUVC_TiltDownString "UVC_TILT_DOWN" //asynInt32 -#define ADUVC_ZoomInString "UVC_ZOOM_IN" //asynInt32 -#define ADUVC_ZoomOutString "UVC_ZOOM_OUT" //asynInt32 -#define ADUVC_PanSpeedString "UVC_PAN_SPEED" //asynInt32 -#define ADUVC_TiltSpeedString "UVC_TILT_SPEED" //asynInt32 -#define ADUVC_PanTiltStepString "UVC_PAN_TILT_STEP" //asynFloat64 +#define ADUVC_UVCComplianceLevelString "UVC_COMPLIANCE" // asynInt32 +#define ADUVC_ReferenceCountString "UVC_REFCOUNT" // asynInt32 +#define ADUVC_FramerateString "UVC_FRAMERATE" // asynInt32 +#define ADUVC_LogLevelString "UVC_LOG_LEVEL" // asynInt32 +#define ADUVC_ImageFormatString "UVC_FORMAT" // asynInt32 +#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 +#define ADUVC_ContrastString "UVC_CONTRAST" // asynInt32 +#define ADUVC_PowerLineString "UVC_POWER" // asynInt32 +#define ADUVC_HueString "UVC_HUE" // asynInt32 +#define ADUVC_SaturationString "UVC_SATURATION" // asynInt32 +#define ADUVC_SharpnessString "UVC_SHARPNESS" // asynInt32 +#define ADUVC_PanLeftString "UVC_PAN_LEFT" // asynInt32 +#define ADUVC_PanRightString "UVC_PAN_RIGHT" // asynInt32 +#define ADUVC_TiltUpString "UVC_TILT_UP" // asynInt32 +#define ADUVC_TiltDownString "UVC_TILT_DOWN" // asynInt32 +#define ADUVC_ZoomInString "UVC_ZOOM_IN" // asynInt32 +#define ADUVC_ZoomOutString "UVC_ZOOM_OUT" // asynInt32 +#define ADUVC_PanSpeedString "UVC_PAN_SPEED" // asynInt32 +#define ADUVC_TiltSpeedString "UVC_TILT_SPEED" // asynInt32 +#define ADUVC_PanTiltStepString "UVC_PAN_TILT_STEP" // asynFloat64 /* enum for getting format from PV */ typedef enum ADUVC_FRAME_FORMAT { - ADUVC_FrameUnsupported = -1, - ADUVC_FrameMJPEG = 0, - ADUVC_FrameRGB = 1, - ADUVC_FrameYUYV = 2, - ADUVC_FrameGray8 = 3, - ADUVC_FrameGray16 = 4, - ADUVC_FrameUYVY = 5, - ADUVC_FrameUncompressed = 6, + ADUVC_FrameUnsupported = -1, + ADUVC_FrameMJPEG = 0, + ADUVC_FrameRGB = 1, + ADUVC_FrameYUYV = 2, + ADUVC_FrameGray8 = 3, + ADUVC_FrameGray16 = 4, + ADUVC_FrameUYVY = 5, + ADUVC_FrameUncompressed = 6, } ADUVC_FrameFormat_t; - -/* Struct for individual supported camera format - Used to auto read modes into dropdown for easier operation */ -typedef struct ADUVC_CAM_FORMAT{ +/* Struct for individual supported camera format - Used to auto read modes into dropdown for easier + * operation */ +typedef struct ADUVC_CAM_FORMAT { char formatDesc[SUPPORTED_FORMAT_DESC_BUFF]; size_t xSize; size_t ySize; @@ -136,11 +132,7 @@ typedef struct ADUVC_CAM_FORMAT{ NDDataType_t dataType; } ADUVC_CamFormat_t; - -typedef enum ADUVC_CONNECTION_TYPE{ - UVC_SERIAL = 0, - UVC_PRODUCT_ID = 1 -} ADUVC_ConnectionType_t; +typedef enum ADUVC_CONNECTION_TYPE { UVC_SERIAL = 0, UVC_PRODUCT_ID = 1 } ADUVC_ConnectionType_t; /* * Class definition of the ADUVC driver. It inherits from the base ADDriver class @@ -148,161 +140,157 @@ typedef enum ADUVC_CONNECTION_TYPE{ * Includes constructor/destructor, PV params, function defs and variable defs * */ -class ADUVC : ADDriver{ - - public: - - // Constructor - ADUVC(const char* portName, const char* serialOrProductID); - - - // ADDriver overrides - virtual asynStatus writeInt32(asynUser* pasynUser, epicsInt32 value); - virtual asynStatus writeFloat64(asynUser* pasynUser, epicsFloat64 value); - - // Callback function envoked by the driver object through the wrapper - void newFrameCallback(uvc_frame_t* frame, void* ptr); - - // destructor. Disconnects from camera, deletes the object - ~ADUVC(); - - protected: - - - int ADUVC_UVCComplianceLevel; - #define ADUVC_FIRST_PARAM ADUVC_UVCComplianceLevel - int ADUVC_ReferenceCount; - int ADUVC_Framerate; - int ADUVC_ImageFormat; - int ADUVC_CameraFormat; - int ADUVC_LogLevel; - int ADUVC_FormatDescription; - int ADUVC_ApplyFormat; - int ADUVC_AutoAdjust; - int ADUVC_Gamma; - int ADUVC_BacklightCompensation; - int ADUVC_Brightness; - int ADUVC_Contrast; - int ADUVC_PowerLine; - int ADUVC_Hue; - int ADUVC_Saturation; - int ADUVC_Sharpness; - int ADUVC_PanLeft; - int ADUVC_PanRight; - int ADUVC_TiltUp; - int ADUVC_TiltDown; - int ADUVC_ZoomIn; - int ADUVC_ZoomOut; - int ADUVC_PanSpeed; - int ADUVC_TiltSpeed; - int ADUVC_PanTiltStep; - #define ADUVC_LAST_PARAM ADUVC_PanTiltStep - - private: - - // ---------------------------------------- - // UVC Variables - //----------------------------------------- - - ADUVC_LogLevel_t logLevel = ADUVC_LOG_LEVEL_DEBUG; // Default log level - - // Checks uvc device operations status - uvc_error_t deviceStatus; - - // Pointer to uvc device struct - uvc_device_t* pdevice; - - // Pointer to device context. generated when connecting - uvc_context_t* pdeviceContext; - - // Pointer to device handle. - // Used for controlling device. - // Each UVC device can allow for one handle at a time - uvc_device_handle_t* pdeviceHandle; - - // Device stream controller. used to control streaming from device - uvc_stream_ctrl_t deviceStreamCtrl; - - // Pointer to struct containing device info, such as vendor, product id - uvc_device_descriptor_t* pdeviceInfo; - - // Array of supported formats that will allow for easy switching of operating modes. - ADUVC_CamFormat_t supportedFormats[SUPPORTED_FORMAT_COUNT]; - - // Flag that stores if driver is connected to device - int connected = 0; - - //flag that sees if shutter is on or off - int withShutter = 0; - - // Flag for checking if frame size was validated with selected dtype and color mode - bool validatedFrameSize = false; - - // ---------------------------------------- - // UVC Functions - Logging/Reporting - //----------------------------------------- - - // Function used to report errors in uvc operations - void reportUVCError(uvc_error_t status, const char* functionName); - - // Reports device and driver info into a log file - void report(FILE* fp, int details); - - // Writes to ADStatus PV - void updateStatus(const char* status); - - // ---------------------------------------- - // UVC Functions - Camera Format Detection - //----------------------------------------- - - // Functions for reading camera formats, and linking them to the appropriate PVs - asynStatus readSupportedCameraFormats(); - void populateCameraFormat(ADUVC_CamFormat_t* camFormat, uvc_format_desc_t* format_desc, uvc_frame_desc_t* frame_desc); - int selectBestCameraFormats(ADUVC_CamFormat_t* formatBuffer, int numberInterfaces); - - // Helper functions - void initEmptyCamFormat(int arrayIndex); - bool formatAlreadySaved(ADUVC_CamFormat_t camFormat); - int compareFormats(ADUVC_CamFormat_t camFormat1, ADUVC_CamFormat_t camFormat2); - - // Functions for applying saved camera mode to PVs - void updateCameraFormatDesc(); - void applyCameraFormat(); - - // ---------------------------------------- - // UVC Functions - Camera functions - //----------------------------------------- - - // Functions that allow for PTZ (Pan/Tilt/Zoom) control for supported devices - asynStatus processPanTilt(int panDirection, int tiltDirection); - asynStatus processZoom(int zoomDirection); - - uint16_t zoomMin, zoomMax, currentZoom, zoomStepSize; - int zoomSteps = 10; - - // Functions that start/stop image aquisition - uvc_error_t acquireStart(uvc_frame_format format); - void acquireStop(); +class ADUVC : ADDriver { + public: + // Constructor + ADUVC(const char* portName, const char* serialOrProductID); + + // ADDriver overrides + virtual asynStatus writeInt32(asynUser* pasynUser, epicsInt32 value); + virtual asynStatus writeFloat64(asynUser* pasynUser, epicsFloat64 value); + + // Callback function envoked by the driver object through the wrapper + void newFrameCallback(uvc_frame_t* frame, void* ptr); + + // destructor. Disconnects from camera, deletes the object + ~ADUVC(); + + protected: + int ADUVC_UVCComplianceLevel; +#define ADUVC_FIRST_PARAM ADUVC_UVCComplianceLevel + int ADUVC_ReferenceCount; + int ADUVC_Framerate; + int ADUVC_ImageFormat; + int ADUVC_CameraFormat; + int ADUVC_LogLevel; + int ADUVC_FormatDescription; + int ADUVC_ApplyFormat; + int ADUVC_AutoAdjust; + int ADUVC_Gamma; + int ADUVC_BacklightCompensation; + int ADUVC_Brightness; + int ADUVC_Contrast; + int ADUVC_PowerLine; + int ADUVC_Hue; + int ADUVC_Saturation; + int ADUVC_Sharpness; + int ADUVC_PanLeft; + int ADUVC_PanRight; + int ADUVC_TiltUp; + int ADUVC_TiltDown; + int ADUVC_ZoomIn; + int ADUVC_ZoomOut; + int ADUVC_PanSpeed; + int ADUVC_TiltSpeed; + int ADUVC_PanTiltStep; +#define ADUVC_LAST_PARAM ADUVC_PanTiltStep + + private: + // ---------------------------------------- + // UVC Variables + //----------------------------------------- + + ADUVC_LogLevel_t logLevel = ADUVC_LOG_LEVEL_DEBUG; // Default log level + + // Checks uvc device operations status + uvc_error_t deviceStatus; + + // Pointer to uvc device struct + uvc_device_t* pdevice; + + // Pointer to device context. generated when connecting + uvc_context_t* pdeviceContext; + + // Pointer to device handle. + // Used for controlling device. + // Each UVC device can allow for one handle at a time + uvc_device_handle_t* pdeviceHandle; + + // Device stream controller. used to control streaming from device + uvc_stream_ctrl_t deviceStreamCtrl; + + // Pointer to struct containing device info, such as vendor, product id + uvc_device_descriptor_t* pdeviceInfo; + + // Array of supported formats that will allow for easy switching of operating modes. + ADUVC_CamFormat_t supportedFormats[SUPPORTED_FORMAT_COUNT]; + + // Flag that stores if driver is connected to device + int connected = 0; + + // flag that sees if shutter is on or off + int withShutter = 0; + + // Flag for checking if frame size was validated with selected dtype and color mode + bool validatedFrameSize = false; + + // ---------------------------------------- + // UVC Functions - Logging/Reporting + //----------------------------------------- + + // Function used to report errors in uvc operations + void reportUVCError(uvc_error_t status, const char* functionName); + + // Reports device and driver info into a log file + void report(FILE* fp, int details); + + // Writes to ADStatus PV + void updateStatus(const char* status); + + // ---------------------------------------- + // UVC Functions - Camera Format Detection + //----------------------------------------- + + // Functions for reading camera formats, and linking them to the appropriate PVs + asynStatus readSupportedCameraFormats(); + void populateCameraFormat(ADUVC_CamFormat_t* camFormat, uvc_format_desc_t* format_desc, + uvc_frame_desc_t* frame_desc); + int selectBestCameraFormats(ADUVC_CamFormat_t* formatBuffer, int numberInterfaces); + + // Helper functions + void initEmptyCamFormat(int arrayIndex); + bool formatAlreadySaved(ADUVC_CamFormat_t camFormat); + int compareFormats(ADUVC_CamFormat_t camFormat1, ADUVC_CamFormat_t camFormat2); + + // Functions for applying saved camera mode to PVs + void updateCameraFormatDesc(); + void applyCameraFormat(); + + // ---------------------------------------- + // UVC Functions - Camera functions + //----------------------------------------- + + // Functions that allow for PTZ (Pan/Tilt/Zoom) control for supported devices + asynStatus processPanTilt(int panDirection, int tiltDirection); + asynStatus processZoom(int zoomDirection); + + uint16_t zoomMin, zoomMax, currentZoom, zoomStepSize; + int zoomSteps = 10; + + // Functions that start/stop image aquisition + uvc_error_t acquireStart(uvc_frame_format format); + void acquireStop(); - // 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 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 attempts to fit data type + color mode to frame if size doesn't match + void checkValidFrameSize(uvc_frame_t* frame); - // Functions that get information about device and image - void getDeviceImageInformation(); - void getDeviceInformation(); + // Functions that get information about device and image + void getDeviceImageInformation(); + void getDeviceInformation(); - // Function that converts ADUVC_Format PV value into uvc_frame_format - uvc_frame_format getFormatFromPV(); + // Function that converts ADUVC_Format PV value into uvc_frame_format + uvc_frame_format getFormatFromPV(); - // Static wrapper function for callback. - // Necessary becuase callback in UVC must be static but we want the driver running the callback - static void newFrameCallbackWrapper(uvc_frame_t* frame, void* ptr); + // Static wrapper function for callback. + // Necessary becuase callback in UVC must be static but we want the driver running the callback + static void newFrameCallbackWrapper(uvc_frame_t* frame, void* ptr); }; // Stores number of additional PV parameters are added by the driver -#define NUM_UVC_PARAMS ((int)(&ADUVC_LAST_PARAM - &ADUVC_FIRST_PARAM + 1)) +#define NUM_UVC_PARAMS ((int) (&ADUVC_LAST_PARAM - &ADUVC_FIRST_PARAM + 1)) #endif diff --git a/uvcApp/src/UVC_DTYPES.md b/uvcApp/src/UVC_DTYPES.md index acf9987..71d0f94 100644 --- a/uvcApp/src/UVC_DTYPES.md +++ b/uvcApp/src/UVC_DTYPES.md @@ -7,4 +7,4 @@ UVC_FRAME_FORMAT_YUYV | YUYV/YUV2/YUV422: YUV encoding with one luminance value UVC_FRAME_FORMAT_RGB | Standard RGB image. UVC_FRAME_FORMAT_MJPEG | Motion Jpeg compressed image. can be converted to RGB -**NOTE** BGR images cannot be grabbed directly from UVC cameras, but YUYV type images can be converted to this format. It is also the standard format for the OpenCV open computer vision library \ No newline at end of file +**NOTE** BGR images cannot be grabbed directly from UVC cameras, but YUYV type images can be converted to this format. It is also the standard format for the OpenCV open computer vision library From 8169afba11be511b0b83f1cd89e50d73ee4b5ade Mon Sep 17 00:00:00 2001 From: Jakub Wlodek Date: Fri, 25 Jul 2025 16:09:12 -0400 Subject: [PATCH 3/3] Add pre-commit CI workflow --- .github/workflows/pre-commit.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/pre-commit.yml diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 0000000..12bb9f9 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,30 @@ +name: Lint and Pre-commit Checks +permissions: + contents: read + +on: + push: + branches: + - main + pull_request: + workflow_dispatch: + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.x' + + - name: Install pre-commit + run: pip install pre-commit + + - name: Run pre-commit + run: pre-commit run --all-files