in reply to How to make a variable in hard call.

G'day Konan,

Welcome to the Monastery.

[Disclaimer: I am not a user of Device::BCM2835. The following is based on its source code.]

gpio_fsel() is not exported; however, you can create an alias so that you don't need to use the fully-qualified subroutine name repeatedly (see "perldata: Typeglobs and Filehandles" for details):

*gpio_fsel = \&Device::BCM2835::gpio_fsel;

RPI_V2_GPIO_P1_07 is exported (line 582); it's part of our @EXPORT = qw(...); which starts on line 317.

Your code could end up looking something like this:

#!/usr/bin/env perl use strict; use warnings; use Device::BCM2835; ... *gpio_fsel = \&Device::BCM2835::gpio_fsel; ... my $inputcmd = ...; ... gpio_fsel(RPI_V2_GPIO_P1_07, $inputcmd); ...

To use a variable in place of RPI_V2_GPIO_P1_07, you could do something like the following. Bear in mind, without seeing your code, I'm very much guessing with regards to the context.

my %rpi_v2_gpio_p1 = ( 3 => RPI_V2_GPIO_P1_03, 5 => RPI_V2_GPIO_P1_05, 7 => RPI_V2_GPIO_P1_07, ..., 40 => RPI_V2_GPIO_P1_40, ); ... gpio_fsel($rpi_v2_gpio_p1{$_}, $inputcmd) for 3, 5, 7, ..., 40;

In other posts, I see variations using dispatch tables and eval. These may well be more appropriate for your code.

If none of the suggestions so far are suitable, you'll need to show us more code such that we can see how gpio_fsel() is being used.

— Ken

Replies are listed 'Best First'.
Re^2: How to make a variable in hard call.
by ikegami (Patriarch) on May 09, 2023 at 08:20 UTC

    Taken a couple of steps further, we can replace

    my %rpi_v2_gpio_p1 = ( 3 => Device::BCM2835::RPI_V2_GPIO_P1_03, 5 => Device::BCM2835::RPI_V2_GPIO_P1_05, 7 => Device::BCM2835::RPI_V2_GPIO_P1_07, ..., 40 => Device::BCM2835::RPI_V2_GPIO_P1_40, );
    with
    my @rpi_v2_gpio_p1; for ( @Device::BCM2835::EXPORT_OK ) { next if !/^RPI_V2_GPIO_P1_(\d+)\z/; my $pin = 0 + $1; my $val = do { no strict "refs"; "Device::BCM2835::$_"->() }; $rpi_v2_gpio_p1[ $pin ] = $val; }
    or
    my @rpi_v2_gpio_p1; for ( @Device::BCM2835::EXPORT_OK ) { next if !/^RPI_V2_GPIO_P1_(\d+)\z/; my $pin = 0 + $1; my $val = ( \&{"Device::BCM2835::$_"} )->(); $rpi_v2_gpio_p1[ $pin ] = $val; }

      Just a quick note: A hash with named pins might be easier to understand and adapt in the long run. E.g. name pins according to their function in code instead of their pin number. This is especially true if, say, the hardware changes. Pin "40" doesn't say anything, but "RTC_IRQ" tells me it's the IRQ pin for the real time clock.

      Additionally, named pins are much easier to find&replace in code. If you search for "1" you could find a lot of stuff not relevant to the problem at hand, "SPI_CLK" on the other hand would be pretty unique to that pin functionality:

      my %rpi_v2_gpio_p1 = ( SPI_CLK => Device::BCM2835::RPI_V2_GPIO_P1_03, SPI_CS => Device::BCM2835::RPI_V2_GPIO_P1_05, SPI_MOSI => Device::BCM2835::RPI_V2_GPIO_P1_07, SPI_MISO => Device::BCM2835::RPI_V2_GPIO_P1_07, ..., );

      That's the same stuff i do in C for my Arduino projects:

      ... globals.h: #define PIN_RTC_IRQ 2 ...Firmware.ino: #if RADIODUINO_BOARD_REVISION < 2 // RTC PIN uses internal pullup resistor pinMode(PIN_RTC_IRQ, INPUT_PULLUP); #else // REV B and up already have an external pullup pinMode(PIN_RTC_IRQ, INPUT); #endif ... alarms.cpp: attachInterrupt(digitalPinToInterrupt(PIN_RTC_IRQ), RTCIRQ, FALLING);

      If, say, the next hardware revision moves the IRQ pin to PIN 3, all i would need to change is globals.h:

      #if RADIODUINO_BOARD_REVISION < 4 #define PIN_RTC_IRQ 2 #else #define PIN_RTC_IRQ 3 #endif

      And with named pin mappings, it's also way easier to find all parts of the code that touch that specific pin:

      $ fgrep PIN_RTC_IRQ * alarms.cpp: attachInterrupt(digitalPinToInterrupt(PIN_RTC_IRQ), RTC +IRQ, FALLING); Firmware.ino: pinMode(PIN_RTC_IRQ, INPUT_PULLUP); Firmware.ino: pinMode(PIN_RTC_IRQ, INPUT); globals.h:#define PIN_RTC_IRQ 2

      So, in my opinion, don't use "magic numbers", use proper names for everything.

      PerlMonks XP is useless? Not anymore: XPD - Do more with your PerlMonks XP
Re^2: How to make a variable in hard call.
by kcott (Archbishop) on May 09, 2023 at 12:53 UTC

    I note that Device::BCM2835 has many functions with fully-qualifed names that aren't exported. You've shown use of one of these:

    Device::BCM2835::gpio_fsel(...);

    and I showed how to create an alias:

    *gpio_fsel = \&Device::BCM2835::gpio_fsel;

    If you're actually using a number of these subroutines, you can make aliases for all in a similar fashion to ++ikegami's "Taken a step further". For example, if you're using Device::BCM2835::gpio_fsel(...), Device::BCM2835::gpio_set(...) and Device::BCM2835::gpio_clr(...), you could write:

    for my $sub (qw{gpio_fsel gpio_set gpio_clr}) { no strict 'refs'; *$sub = \&{"Device::BCM2835::$sub"}; }

    and subsequently call:

    gpio_fsel(...); gpio_set(...); gpio_clr(...);

    Update (typo fix): I had written "(...}" instead of "(...)"; then, with the power of copy-paste, propagated that typo two more times. I've fixed all three instances.

    — Ken

      As a side note: the module claims to export nothing by default, which is contradictory to the source.