Home > Software engineering >  How to change a variable properly with pigpio SetAlertFunc?
How to change a variable properly with pigpio SetAlertFunc?

Time:11-09

I want to monitor for a specific GPIO pin which has a button connected to it and depending on the number of times the button has been pressed it will either turn on some LED lights, make them blink or turn them off.

#include <stdio.h>
#include <pigpio.h>
#include <stdlib.h>
#include <unistd.h>

#define LED_1 13
#define LED_2 19
#define BUTTON 25
#define ON 1
#define OFF 0
#define DELAY 1

void initalise_pins();
void clear_all();
void start_button();
void turn_on_lights();
void increment_state(int gpio, int level, uint32_t tick);


int current_state = 0; /*Don't have a better way of breaking out of loop during pulse so using global var*/

int main(){
    if (gpioInitialise() < 0){
        printf("Error initializing pigpio library, exiting");
    }
    else{
        initalise_pins();
        clear_all();
        start_button();
    }
}

int main(){
    initalise_pins();
    clear_all();
    start_button();
}

void initalise_pins(){
    gpioSetMode(LED_1, PI_OUTPUT); /*Set LED at pin 13 to output*/
    gpioSetMode(LED_2, PI_OUTPUT); /*Set LED at pin 19 to output*/
    gpioSetMode(BUTTON, PI_INPUT); /*Set Button at pin 25 to input*/
    gpioSetPullUpDown(BUTTON, PI_PUD_DOWN); /*Set Button at pin 25 to pulldown*/
    gpioSetAlertFunc(BUTTON, increment_state); /*Function to watch for GPIO state change*/
}

void clear_all(){
    gpioWrite(LED_1, OFF); /*Resets LED_1 to off*/
    gpioWrite(LED_2, OFF); /*Resets LED_2 to off*/
}

void turn_on_lights(){
    gpioWrite(LED_1, ON);
    gpioWrite(LED_2, ON);
}

void increment_state(int gpio, int level, uint32_t tick){
    if (level == 1){
        current_state  = 1;
    }
}

void start_button(){
    for (;;){ /*Loop to keep reading button value*/
        if (current_state == 0){ /*Current state off*/
            continue;
        }
        else if (current_state == 1){ /*Current state on*/
            turn_on_lights();
        }
        else if (current_state == 2){ /*Current state blinking*/
            clear_all();
            sleep(DELAY);
            turn_on_lights();
            sleep(DELAY);
        }
        else{ /*Reset state to off*/
            clear_all();
            current_state = 0;
        }
        sleep(0.1);
    }
}

The code works as expected but is there a proper way to set the value of current_state instead of having it as a global variable? Main issue with this solution is that when I compile it as a library to be used in Python this function will break.

CodePudding user response:

To my knowledge, there are three ways to store data 'beyond their scope'.

  1. A global variable - This variable is, as you know, shared across all calls and can be referenced even outside the compile unit.
  2. A static variable - This type is limited to the scope it is defined in, inaccessible from the outside, but, once again, shared among all calls.
  3. Parameters, which are passed into your function.

The way I understand your question, you do NOT want to share the value of the variable across all instances of your call, which automatically disqualifies 1. and 2.

As such, you will need to pass the required information into your function from the outside.

While you could just pass the current_state_id into your function set 'as is', this requires the user of your library to know a thing or two about how your library works.

A better solution would be a context structure, which hides the interna of the data you need and gives you the flexibility to add/remove data from within, without having to worry about changing your API.

A normal approach to this would look something like this:

struct _PIN_Ctrl; //Forward declaration of the (opaque) structure.
typedef struct _PIN_Ctrl *PIN_Ctrl;

PIN_Ctrl createPINCtrl(void);
//Any number of functions taking PINCtrl as context structure.
freePINCtrl(PIN_Ctrl ctrl);

Calling would work similarly (using C99 Notation now):

if (PIN_Ctrl ctrl = createPINCtrl())
{
    //doStuffWithYourContext
    freePINCtrl(ctrl);
}

createPINCtrl needs to malloc your structure and initialize its members to a defined state (i.E. 'currentState' to 0). Internally, you would naturally access the members of your structure and finally 'freePINCtrl' merely performs free(ctrl) to clean up the allocated memory.

  • Related