Use the gpioService from a legacy app?

Hi, all. I need to code something very much like the gpioCf3Demo, but it needs to be a ‘legacy app’ to fit within the constraints of our current project’s build system. A colleague of mine wrote a CMake function that is supposed to handle this, but I’m having trouble seeing how it all fits together.

Reverse-engineering the CMake bits via some message() calls, I see that his function is running the following command:

/opt/legato/bin/ifgen \
    --gen-client \
    --gen-interface \
    --gen-local \
    --gen-messages \
    --gen-common-interface \
    --gen-common-client \
    /opt/legato/interfaces/le_gpio.api

This generates the following files:

$ ls -1 le_*.*
le_gpio_client.c
le_gpio_common.h
le_gpio_commonclient.c
le_gpio_interface.h
le_gpio_messages.h
le_gpio_service.h

The .c files are compiled into the binary as described in Port Legacy C App. The CMake function also creates an .adef file for the app that contains the following config blocks:

...

bindings:
{
     *.le_gpioPin2 -> <root>.le_gpioPin2                                                                                                
     *.le_gpioPin42 -> <root>.le_gpioPin42
}

...

extern:
{
    requires:
    {
        le_gpioPin2 = /opt/legato/interfaces/le_gpio.api                                                                                
        le_gpioPin42 = /opt/legato/interfaces/le_gpio.api
    }
}

...

(This is a partial listing, since the file is 92 lines long; I can provide the entire content if needed.)

My expectation from the .adef file—and from studying the gpioCf3Demo sample app—is that I should be able to call functions such as le_gpioPin2_Read(), le_gpioPin42_IsActive(), etc, to control the two desired GPIO pins. But these symbols are undefined:

Scanning dependencies of target systemmanagerservice
[ 66%] Building CXX object systemmanagerservice/CMakeFiles/systemmanagerservice.dir/src/gpiofuncs.cpp.o
/build/ivs_car/src/systemmanagerservice/src/gpiofuncs.cpp: In function 'int ivs::systemmanagerservice::gpio_read(int)':
/build/ivs_car/src/systemmanagerservice/src/gpiofuncs.cpp:39:12: error: 'le_gpioPin2_Read' was not declared in this scope
     return le_gpioPin2_Read();
            ^~~~~~~~~~~~~~~~
/build/ivs_car/src/systemmanagerservice/src/gpiofuncs.cpp:39:12: note: suggested alternative: 'le_gpio_Read'
     return le_gpioPin2_Read();
            ^~~~~~~~~~~~~~~~
            le_gpio_Read

Erm… there’s a single le_gpio_Read() function?? Which pin does it read—all of them? It doesn’t accept any arguments, so… I’m confused. Can anybody shed some light on what’s going wrong here? I’m very new to Legato, so I can’t tell whether:

  1. My expectations are simply incorrect
  2. The ifgen command run by my coleague’s CMake function is incorrect/incomplete
  3. The .adef is incorrect/incomplete
  4. Something else is wrong?

Any insights much appreciated—thank you!

With ifgen try using “–name-prefix le_gpioPin2”. That will generate le_gpioPin2_funcs()

Hey, thanks for the tip—it helped! I found through trial-and-error that these are the commands needed to generate the files required for my app:

/opt/legato/bin/ifgen \
 --gen-common-client \
 --gen-common-interface \
 --gen-messages \
 /opt/legato/interfaces/le_gpio.api

/opt/legato/bin/ifgen \
 --gen-client \
 --gen-interface \
 --gen-local \
 --name-prefix le_gpioPin2 \
 /opt/legato/interfaces/le_gpio.api

/opt/legato/bin/ifgen \
 --gen-client \
 --gen-interface \
 --gen-local \
 --name-prefix le_gpioPin42 \                                                                                                            
 /opt/legato/interfaces/le_gpio.api

This generated the following files:

ls -1 le_gpio*
le_gpioPin2_client.c
le_gpioPin2_interface.h
le_gpioPin2_service.h
le_gpioPin42_client.c
le_gpioPin42_interface.h
le_gpioPin42_service.h
le_gpio_common.h
le_gpio_commonclient.c
le_gpio_messages.h

After adding in the generated sources, the compiler was able to resolve all le_gpioPin2_read(), le_gpioPin42_Activate() etc. calls. I believe this is a minimal set. (Some of the options my colleague was passing previously created a few ‘extra’ .c files containing functions that aren’t actually needed for our use case.)

Thanks again for the suggestion, it saved me a lot of time! :pray:

1 Like

FYI, you’d also need to specify “–service-name le_gpioPin2” with ifgen for the GPIO service. The Legato documentation is lacking in this regard. We will update it. Thanks.

LOL—yes! I just kinda reverse-engineered this two days ago. Without passing --service-name le_gpioPin36, too, everything compiled, but the call to le_gpioPin36_ConnectService() was hanging. I figured out that I could ‘fix’ this by running:

sed -i 's/SERVICE_INSTANCE_NAME "le_gpio"/SERVICE_INSTANCE_NAME "le_gpioPin36"/' le_gpioPin36_messages.h

after running ifgen. But that seemed like such an egregious hack that I ran ifgen --help again and carefully scrutinized each option; --service-name jumped out at me as the most likely candidate. Lo and behold: it works! Thank you…