Skip to content

Conversation

@marcomontevechi1
Copy link

@marcomontevechi1 marcomontevechi1 commented Jul 31, 2024

This pull request is a draft with an initial idea about how to improve the usage.
Long story short is: it adds curl as an option (that is, the default operation still uses pure graphicsmagick) to grab the image and pass it as a Blob to GraphicsMagick, but I'm not sure if this is a good design. Another idea would be to simply create another driver (maybe ADCURL?) with just curl functionalities.

If any of these two options make sense, I can keep working on it until it's acceptable for merging. If not, I will close the PR.

Context is: me and Tomasz Brys were trying to integrate a Hikivision Speed Dome camera but were unable to find it's direct image or video stream URL, if there is any available at all. The camera does provide a web service with a video stream, but the url is hidden by some sort of redirection or something that I cannot fully understand. Trying to access it with graphicsmagick didn't work in any way we tried, always yielding:

2024/07/31 10:35:58.044 URLDriver:readImage: error reading URL=softIocPVA: Unable to access configuration file (delegates.mgk) reported by ../supportApp/GraphicsMagickSrc/magick/blob.c:1971 (GetConfigureBlob)
ics-ups-ioc-dev-449425 > dbpf $(PREFIX)cam1:Acquire 1
DBF_STRING:         "Acquire"
ics-ups-ioc-dev-449425 > 2024/07/31 10:36:01.316 URLDriver:readImage: error reading URL=softIocPVA: No decode delegate for this image format (/tmp/gm4WSJW3) reported by ../supportApp/GraphicsMagickSrc/magick/constitute.c:1535 (ReadImage)

but curl managed to get the frame.

Since libCurl is fairly easy to manage, we added it to the driver. All curl options that I needed can be accessed as records and it is relatively easy to add new ones if needed. Only the HTTP authentication password and username options are in a TOML file instead of record, in order to not expose the credentials for everyone in the network.

libcurl and toml used documentation:

https://toruniina.github.io/toml11/docs/
https://curl.se/libcurl/c/

A typical acquisition with this module would be something like:

(...)
URLDriverConfig("$(PORT)", 0, 0)
(...)
iocInit()
dbpf $(PREFIX)cam1:URL1 "http://your_url" # Tell the driver which URL to look for
dbpf $(PREFIX)cam1:URLSelect 0        # Select URL 0 from the list of available URLs
dbpf $(PREFIX)cam1:ArrayCallbacks 1   # Selecting acquisition parameters and plugin configuration
dbpf $(PREFIX)image1:EnableCallbacks 1
dbpf $(PREFIX)image1:ArrayCallbacks 1
dbpf $(PREFIX)cam1:AcquireTime 2
dbpf $(PREFIX)cam1:AcquirePeriod 1
 
dbpf $(PREFIX)cam1:UseCurl 1          # Telling the driver to use Curl instead of GraphicsMagick
dbpf $(PREFIX)cam1:CurlOptHTTPAuth 2  # Telling the driver to use http authentication
dbpf $(PREFIX)cam1:CurlAuthFile "/tmp/file.toml"  # Telling the driver to look for authentication credentials in the file "/tmp/file.toml"
 
dbpf $(PREFIX)cam1:ImageMode_RBV 0
 
dbpf $(PREFIX)cam1:Acquire 1

@EmilioPeJu
Copy link
Member

I think it might be worth making libcurl an optional dependency, i.e. the curl specific code could be in a separate file that gets compiled only if WITH_CURL is set to yes in the CONFIG_SITE file (this also requires a little #ifdef magic in URLDriver.cpp, but should be minimal)

@marcomontevechi1
Copy link
Author

marcomontevechi1 commented Aug 4, 2024

@EmilioPeJu I think it's a good idea. In order to make that in the less invasive way I can think of I intend to put some class declaration stuff into a header file. I will open another PR for that.

marcofilho added 2 commits August 4, 2024 22:28
Also change the DRIVER_MODIFICATION number even though I'm not sure if
this should be done since this shouldn't change anything in the driver
per se.
@marcomontevechi1 marcomontevechi1 mentioned this pull request Aug 4, 2024
marcofilho added 16 commits August 7, 2024 20:45
Add WITH_CURL compilation option.

If compiled with WITH_CURL = YES, CurlUsage.template file will be added
and it's records will be created. curl.h will be included.
First record - UseCurl - should futurely toggle curl usage in the
Driver.
No need to use getIntegerParam in this context if we already have the
value argument.
Using this along with to-be-added CURLOPT_PASSWORD would expose
credentials in the network.

I leave it in the driver as a means to completely express the API
functionalities, but there should be better ways of setting your
credentials if you mean to.

Probably will add a configuration file for that in the future.
Same warning about last commit: this shouldn't be used but it's left
here as an option for quick testing and better expressing the API
functionalities.

For actual credentials usage future records should add a path for a
configuration file containing the credentials.
Should be used to load the file contents and put them
into the correct parameters. Uses a very similar mechanism from
NDFile.template and functions from asynNDArrayDriver.

For now it just checks if the file exists and is accessible, but not
it's contents.
Add CurlLoadConfig record and loadConfigFile function.

loadConfigFile() calls writeInt32 and writeOctet for all parameters
it can recognize, except username and password. For those,
loadConfigFile() calls curl_easy_setopt without ever setting the
parameter value.

This means setpoint and RBV values for all parameters can be different,
so I add readback values for all records.

writeInt32 and writeOctet are called inside loadConfigFile(), which is
called inside writeInt32. In my understanding this cannot lead to any
infinite loop since CurlLoadConfig record has no "ASYN_" prepending it's
name, so it's impossible for it to call writeInt32 on itself.

Also, I think this is thread safe because the function is only supposed
to be called inside writeInt32, which is supposed to be already locked.
Readbuffer is a char vector just so we can copy all needed bytes to it.
writeCallback should simply add stuff to the buffer.

readImage clears buffer before adding to it. Unfortunately I think clear
cant be called inside writeCallback because it's called more than one
time per read.
This is obviously needed and acquisition will fail without this.
WITH_CURL = YES/NO is used to tell the compiler to use or not use curl.
I add an example in configure/CONFIG_SITE to make it easy for people to
enable/disable this in future.
Curl is added as an option both at compile and at runtime.

If compiled with WITH_CURL = YES at configure/CONFIG_SITE.local,
curl option will be enabled at runtime but default will still be UseCurl
= NO.

If record $(P)$(R)UseCurl = YES, then code will get image from URL using
libCurl instead of graphicsMagick. Some curlOptions are configurable as
records. More can be easily added.

The CurlConfigFile.template is based on NDFile.template, but a bit
different, so I preferred to create a new one instead of including the
one that already exists. Maybe this can be modified in future.
@marcomontevechi1
Copy link
Author

@EmilioPeJu I'm closing this pull request since I changed a lot about the overall structure in new branches. Will open a new one afterwards.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants