Welcome to our community

Be a part of something great, join today!

  • Hey all, just changed over the backend after 15 years I figured time to give it a bit of an update, its probably gonna be a bit weird for most of you and i am sure there is a few bugs to work out but it should kinda work the same as before... hopefully :)

Caching System and Push Notifications

Gavin Greenwalt

Well-known member
Joined
Dec 29, 2006
Messages
7,614
Reaction score
0
Points
36
Age
40
Could you elaborate a bit on the caching system that the official API performs. If you can't know if a value has changed via direct camera input what's the value of a cached value? Can an app subscribe to values to receive push notifications from the camera? I'm thinking of something like:

#$DRAGON:S:SUBSCRIBE:FSTOP,ISO,FOCUS|1|1:\n

Then when any of those 3 values change the Epic would automatically just push an update. You could subscribe and unsubscribe to various parameters and leave an open socket on the app listening for updates. That would cut back on a massive amount of traffic after the first update. It would also mean that the cache would be more likely to be accurate.
 
Could you elaborate a bit on the caching system that the official API performs. If you can't know if a value has changed via direct camera input what's the value of a cached value? Can an app subscribe to values to receive push notifications from the camera? I'm thinking of something like:

#$DRAGON:S:SUBSCRIBE:FSTOP,ISO,FOCUS|1|1:\n

Then when any of those 3 values change the Epic would automatically just push an update. You could subscribe and unsubscribe to various parameters and leave an open socket on the app listening for updates. That would cut back on a massive amount of traffic after the first update. It would also mean that the cache would be more likely to be accurate.

I'll try to address each of the individual concerns below.

If you can't know if a value has changed via direct camera input what's the value of a cached value?

The camera always sends out a CURRENT message for any parameter that changes value. That is, your statement is not correct and there is no need to "subscribe" to parameters - you are automatically "subscribed" to all parameters. In response to these CURRENT messages the API notifies your application via a callback function that you register.

Could you elaborate a bit on the caching system that the official API performs.

The caching in the API keeps track of the latest CURRENT value for each of the parameters so when you call:
rcp_get(con, RCP_PARAM_ISO)
The API will only send the RCP packet "#$API:G:ISO:\n" to the camera if it doesn't have a cached value. If it has a cached value, nothing will be sent to the camera and the client application callback will be called with the cached value.

Can an app subscribe to values to receive push notifications from the camera? I'm thinking of something like:

#$DRAGON:S:SUBSCRIBE:FSTOP,ISO,FOCUS|1|1:\n

Then when any of those 3 values change the Epic would automatically just push an update. You could subscribe and unsubscribe to various parameters and leave an open socket on the app listening for updates.

As I mentioned before, there is no need to subscribe to parameters to get there current values, this happens automatically. Limiting which parameter you receive currents for isn't very helpful and could cause stale data on your application if you forget to subscribe to a parameter you are displaying on your UI.

...and leave an open socket on the app listening for updates.
It is recommend that you always keep the socket connection to the camera open while you are connected. Are you thinking of opening a socket, sending a packet, and the closing the socket?

That would cut back on a massive amount of traffic after the first update
There really isn't a massive amount of traffic. After the initial update you only receive about 2-4k of data a second. Even our implementation on smaller microcontrollers don't have an issue with this level of traffic. The only time I have found the amount of data to be troublesome is when trying to read the stream by hand.

It would also mean that the cache would be more likely to be accurate.
I'm not sure what you mean by this. The cache is accurate.
 
If you're pushing updates on a regular basis then it all makes sense. I didn't see anywhere in the SDK manual about the camera sending out updates without a request so the caching seemed kind of pointless. I was assuming that I needed to periodically do a full 'Current' on the entire camera which would still be very little data but if I did it every 1-2 seconds with 100+ camera requests I would be slightly nervous. Which would to me have seemed to defeat the purpose of even having an individual property get command.

Is the SDK 'smart' about knowing what properties might change based on other changes? e.g. when you change resolution the available framerates would change.

Thanks!
 
If you're pushing updates on a regular basis then it all makes sense. I didn't see anywhere in the SDK manual about the camera sending out updates without a request so the caching seemed kind of pointless. I was assuming that I needed to periodically do a full 'Current' on the entire camera which would still be very little data but if I did it every 1-2 seconds with 100+ camera requests I would be slightly nervous. Which would to me have seemed to defeat the purpose of even having an individual property get command.

Is the SDK 'smart' about knowing what properties might change based on other changes? e.g. when you change resolution the available framerates would change.

Thanks!

Yes, the system is smart about dependencies. The camera itself handles most of the dependencies (like the framerate list changing based on format), and the API kows that these lists should not be cached (since they can changed based on other camera settings). The API also has logic built into it to handle some more nuanced dependencies and for things like color coding the values based on other camera parameters.

If you use the C API your client application can be surprisingly simple and straight forward. It was designed so that you really only need to focus on presentation in your client application, the API will handle all the other logic.
 
Sadly Microsoft didn't see fit to include a C compiler for ARM WinRT. :( It was a huge PITA apparently for the VLC team too since all of their libraries were C Libraries. The VLC and FFMPEG guys eventually found a solve, but whatever it is I'm sure is way outside my pay grade and specialization.
 
Sadly Microsoft didn't see fit to include a C compiler for ARM WinRT. :( It was a huge PITA apparently for the VLC team too since all of their libraries were C Libraries. The VLC and FFMPEG guys eventually found a solve, but whatever it is I'm sure is way outside my pay grade and specialization.

I don't have much working knowledge of WinRT. That being said, C was chosen as the API language since it is pretty much a universal lowest common denominator. We are successfully using the RCP API library on Windows, Mac, Linux, iOS, Andriod, and various embedded processors. It is really unfortunate that microsoft failed to include a C compiler for ARM WinRT. What languages are supported for ARM WinRT? It may be trivial to port the library to something like C++ and perhaps even C#. Is it possible to create a DLL from the C code and use that?
 
It's possible to link to C DLLs but then it won't pass certification for the Windows Store for Phone and Desktop since they couldn't ensure it wasn't using non-standard/insecure APIs. Both C++ and C# though are native citizens. Your choice was sensible, just not compatible with Modern(tm) apps. C# on windows though does have some nice side effects like .NET's callback and async threading system being so robust. As I learned WinRT I was cursing it every step of the way but now whenever I go back to regular C/C++ programming I feel like it's 1985, I've mostly come around to the new way of doing things.
 
It's possible to link to C DLLs but then it won't pass certification for the Windows Store for Phone and Desktop since they couldn't ensure it wasn't using non-standard/insecure APIs. Both C++ and C# though are native citizens. Your choice was sensible, just not compatible with Modern(tm) apps. C# on windows though does have some nice side effects like .NET's callback and async threading system being so robust. As I learned WinRT I was cursing it every step of the way but now whenever I go back to regular C/C++ programming I feel like it's 1985, I've mostly come around to the new way of doing things.

I can't think of any reason the API code won't compile using the C++ compiler. Please let me know of any issues you run into porting over and we can try to incorporate any required changes to the source.

Edit:
I just did a quick test and renamed all the .c files in the API to .cpp and tried compiling under Visual Studio 2010 and gcc (under cygwin). The only changes needed are explicit casts of the malloc calls. With gcc I didn't have to make any changes if I used the -fpermissive option.

If this is a working solution for you let me know. I may modify the API source code to look something like this to help you out in future releases:

char * str =
#ifdef __cplusplus
(char *)
#endif
malloc(str_size);
 
I was just going to say that I got it pretty close to compiling with a straight up rename in VS 2013 except for "char *" and "void *"

The other error I'm seeing but it's just in the test code is:

EDIT
Cannot open include file: netdb.h
arpa/inet.h
pthread.h
unistd.h
ifaddrs.h
net/if.h

I imagine something is important somewhere in there. But is that all cygwin specific?
 
I was just going to say that I got it pretty close to compiling with a straight up rename in VS 2013 except for "char *"

The other error I'm seeing but it's just in the test code is:

EDIT
Cannot open include file: netdb.h
arpa/inet.h
pthread.h
unistd.h
ifaddrs.h
net/if.h

I imagine something is important somewhere in there. But is that all cygwin specific?

The rcp_api_test.cpp file only compiles under POSIX system like Mac, Linux, and Cygwin. You obviously don't need that file for your application.
 
One last question before the weekend if you're still around. :)

We integrate all of the function definitions for rcp_api.h into our app right? I'm not just missing a file? :D

Thanks again!
 
One last question before the weekend if you're still around. :)

We integrate all of the function definitions for rcp_api.h into our app right? I'm not just missing a file? :D

Thanks again!

I'm not sure exactly what your question is. Your application should compile in all the source files we provide in the API (along side your code). For a complete list of all required files take a look in CMakeLists.txt. I don't want to explicitly list the files here as they will potentially change with version. Note that there are a few files outside of the rcp_api directory (that is, the clist, rcp_parser, decorated_string, and base64 source code).
 
Another note for WinRT applications. Apparently GetTickCount() has been deprecated in favor of GetTickCount64().

(In the RCP_API_LOG.cpp)

However for ARM (Windows Phone/Windows RT) you need to use System.Environment.TickCount

http://msdn.microsoft.com/en-us/library/system.environment.tickcount(v=vs.110).aspx

If you provide a patch file (or your complete modified source) I can try to incorporate your changes within appropriate #ifdefs to make your life easier in future releases.
 
Will do. I'll wait until I can get the whole shoot and shabang to compile as a DLL including threading and I might provide a proposed class structure to make it more C++/OOish. I found out that the latest RTM of VS2013 has re-enabled winsock2 support so I'm updating right now to that to be as close as possible between WinRT and your Cygwin/Win32 example.
 
I'm not sure exactly what your question is. Your application should compile in all the source files we provide in the API (along side your code). For a complete list of all required files take a look in CMakeLists.txt. I don't want to explicitly list the files here as they will potentially change with version. Note that there are a few files outside of the rcp_api directory (that is, the clist, rcp_parser, decorated_string, and base64 source code).

I found what I was looking for, you were defining them in the example .c files along with main(). I was looking for Mutex lock etc. I was thinking there might be an rcp_api.c somewhere that I accidentally missed while importing.
 
I found what I was looking for, you were defining them in the example .c files along with main(). I was looking for Mutex lock etc. I was thinking there might be an rcp_api.c somewhere that I accidentally missed while importing.

Just to clarify, the following functions are required to be implemented by your code:
rcp_malloc
rcp_free
rcp_mutex_lock
rcp_mutex_unlock

This allows for flexibility in porting the API to different platforms. There are implementations in the test application that you can use as a reference, but you will obviously need to make changes to rcp_mutex_lock and rcp_mutex_unlock as you are not using pthreads.

The test code for rcp_malloc and rcp_free is overkill for a real application, instead you should probably use the code shown in the documentation, that is:

void * rcp_malloc(size_t NBYTES)
{
return malloc(NBYTES);
}

void rcp_free(void * APTR)
{
free(APTR);
}
 
If this was a perfect world I would break out some of the functionality in the API to be a little more modular and granular. For instance the RCP_Discovery.c section feels a bit too self-contained. It would be great if _rcp_discovery_cam_info_list was bumped out of all of the functions and passed in as a pointer and then all of those functions were more like:

Code:
static void _rcp_discovery_cam_info_list(rcp_discovery_cam_info_list_t * cam_inf_list, const rcp_cam_info_t * cam_info, const char * from_ipv4)
{
}

It would pretty dramatically increase the flexibility of what bits and pieces I could reuse and maybe use in different contexts.

Or if for instance _rcp_discovery_handle_packet should in my opinion be made more atomic:

_rcp_discovery_handle_packet is a useful function as a stand alone function. What if I want two different lists of discovered cameras instead of one (for instance breaking them out between two different network interfaces)? I'm stuck then with the single _rcp_discovery_cam_info_list.

It would also have the side effect of letting a developer handle locks and unlocks in a less prescribed fashion.
 
If this was a perfect world I would break out some of the functionality in the API to be a little more modular and granular. For instance the RCP_Discovery.c section feels a bit too self-contained. It would be great if _rcp_discovery_cam_info_list was bumped out of all of the functions and passed in as a pointer and then all of those functions were more like:

Code:
static void _rcp_discovery_cam_info_list(rcp_discovery_cam_info_list_t * cam_inf_list, const rcp_cam_info_t * cam_info, const char * from_ipv4)
{
}

It would pretty dramatically increase the flexibility of what bits and pieces I could reuse and maybe use in different contexts.

Or if for instance _rcp_discovery_handle_packet should in my opinion be made more atomic:

_rcp_discovery_handle_packet is a useful function as a stand alone function. What if I want two different lists of discovered cameras instead of one (for instance breaking them out between two different network interfaces)? I'm stuck then with the single _rcp_discovery_cam_info_list.

It would also have the side effect of letting a developer handle locks and unlocks in a less prescribed fashion.

The only file in the API you should really be concerning yourself with is rcp_api.h - the public API header. The fact that you have the soirc of the API and can look at the implementation doesn't mean you should try to use the "private" functions. The only reason all the source was released was so that it would be easier to port to other platforms. Otherwise we would need to provide binary library packages for any platform people may want to use the API in.

Understanding the API implementation might help you understand how to use the public API which is good. But I worry that you might start using or relying on parts of the API that are not guaranteed to stay constant across releases as we add features or refactor.
 
Which is why I'm asking for a few small changes to the API to keep it constant. ;)

I feel like the camera API from what I'm learning make sense, it's just the discovery functions that are a bit too high level. Specifically the fact that you can only perform one discovery at a time since the discovery list is a single block of memory. I could also probably manage the memory better from an application level since I could make it something like .NET's ConcurrentBag<t> which is automatically thread safe. All I really need from the API is the conversion from packet to cam_info_t. I can also then throw in callbacks to aysnchronously populate a camera list as cameras are discovered instead of querying the entire list.

async task OnCamDiscovered(void)
{
UpdateUIList();
}
 
Back
Top