Welcome new user! You can search existing questions and answers without registering, but please register to post new questions and receive answers. Note that due to large amounts of spam attempts, your first three posts will be manually moderated, so please be patient.
We have moved to a new forum at http://jevois.usc.edu, please check it out. The forum at jevois.org/qa will not allow new user registrations but is maintained alive for its useful past questions and answers.

static map access on jevois - error

0 votes

I have a new module that implements a global static map to save shared_ptr instances of a subcomponent, in order to access the class functions from free functions

In summary (pseudo-code):

class MAVLinkTest : public jevois::Module{
itsMAVLink = addSubComponent<MAVLink>("MAVLink", &MAVLink_data, MAVLink::Type_t::USB);
itsMAVLink->set_instance(itsMAVLink); //saves a copy of shared_ptr in the static map
}
process(){
auto m = MAVLink::get_instance(MAVLink::Type_t::USB); //retrieves a copy of the instance with matching type
m->somefunction();
}

Where the global static map is 

namespace  mavlink {
    static  std::map<MAVLink::Type_t, std::shared_ptr<MAVLink> > gMAVLink_instances;
}

The current code can be found in this fork - MAVLink branch. 

I was able to successfully run the code on ubuntu host and receive and send MAVLink messages, but I get an error when running it on jevois. The error occurs when I try to access the global static map to retrieve the instance. Could there be some differences in the compiler flags that changes the behavior of static global list/map access? I can't figure out how to debug it and step through with gdb on jevois so far. 

I'm able to access the class instance from within the module class (with itsMAVlink) but that doesn't solve my problem, since the mavlink API requires free functions that access the serial send and receive methods.

I'm open to suggestions on how to save the MAVLink instance somewhere and retrieve it in a free function based on some criteria I pass to getInstance function. 

Here is a question I posted regarding the implementation method. 

- Ali

asked Jun 23, 2017 in Programmer Questions by alsaibie (740 points)
edited Jun 23, 2017 by alsaibie

1 Answer

0 votes
I figured out the issue with accessing the shared ptr instance, I was checking if the shared_ptr_instance != nullptr, which works on the host but no on the platform. Instead I had to use !shared_ptr_instance (a bool operator) to check if the instance is valid. No I'm running into problems with the mavlink functions which is a separate issue now and I'll continue looking at.
answered Jun 23, 2017 by alsaibie (740 points)
Great! Your code looks great to me, maybe one thing would be to remove that map entry a bit earlier when the module is unloaded, i recommend moving what you have in the MAVLink destructor to postUninit() override instead, or you may get an error message (non fatal), see around line 110 of Component.C in jevois/
I spoke too soon, there was no problem with checking the nullptr. It seems to be the non-fatal error you mentioned, yes I do get that error when connecting with ffplay, when jevois destroys the already initialized MAVlinkTest and reinitializes new instances of it. I will fix that, thanks for pointing out the posUnint(), I wouldn't have figured it out easily. Hopefully this will do.
I am guessing some other thread is calling those free functions? If so you probably need to protect all accesses to it with a static mutex associated with your map.
Turns out it was the improper deconstruction of the instance. So postUnint resolved it and now it's behaving like the host. New question, I'm trying to get a module to run without video output, just like RoadNavigation for example, I did add the virtual process(inframe) function and added a video mapping, the module gets initialized and ready but doesn't run process (I get a debug message: No procesing module loaded or not streaming). The same thing happens when I load RoadNavigation module with no video output. Is there a specific setting that I'm missing? Thanks
yes, likely you are not streaming. When using modes with no USB out, there is no host to tell JeVois to start streaming when you open guvcview on the host, so you have to do it manually with command 'streamon'. The reason we do not start the stream immediately upon module load is to give users some time to configure it first (set parameters, etc).
Got it! Btw the microsd mount feature is awesome, make it much more pleasant programming.
Finally got MAVlink to work back and forth between host and platform as well QGroundControl, using serial-over-USB. The next step would be to test it on the hard serial. I believe I'm running into a buffer overrun issue, say I start streaming and sending serial characters but the received is busy or disconnected the program just hangs at write(), I'd like the program to dumb the buffer and continue its thing, I've added a flushout function (tcflush(itsDev, TCOFLUSH)) and tested calling it periodically but that didn't seem to help.

Any pointers on automatically draining the buffer if full? I'm using the Serial::write() to write characters out.
Indeed we have tried in the Serial class to not drop any data, and instead to throttle down until all the data can get through. I think if you do not want this feature maybe the best is to make your own version of the Serial class with a simple call to ::write() and no checking. Or just add a writeNoCheck() function to Serial and send us a pull request, we will integrate it. Just look at Serial::write() and only keep the call to ::write() in there. The problem with that is how will you get back in sync, i.e., if half of a message gets lost, how do you detect that?
That makes sense, I'll add a separate function. Now to sync there are two options, keep MAVLink in a separate thread, but have to make sure I don't lock a data mutex, or use the MAVLink API to check if data is received properly (say if not all parameters are received, request new transmission, and/or acknowledge receipt of message), which is how the proper MAVLink implementation is done (still learning as I go along). I will want to implement multiple threads in any case, will cross that bridge when I get there.
Is there a built-in way to pass camera control parameters from a module? Say I want to pass setcam gain from process(). I can add the camera controls as MAVLink parameters and they can be set using GCS. If not available, what's the safest way to do so?
oops, there isn't, same reason as for why you cannot mess with Engine's parameters: those controls should be under user control and not module writer control, to avoid surprises as to why some settings made by users end up having no effect.

You can write a file called script.cfg in the directory of your module, with any valid CLI commands in there. It will be run after your module is loaded and init()'ed. See the ObjectTracker in jevoisbase for an example. Let us know if it does not work, has not been thoroughly tested yet...

btw, this question would probably be more useful to others as a standalone question, for future reference.
...