Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Software-defined GPIOs / GPIO hooks #245

RenaKunisaki started this conversation in Ideas
Discussion options

Consider something like:

#define NUM_SW_GPIOS 50 //arbitrary number
#define NUM_GPIOS (NUM_HW_GPIOS + NUM_SW_GPIOS)
typedef int (*swGpioReadFunc_t)(int pin);
swGpioReadFunc_t readFunc[NUM_GPIOS];

int _readHwGpio(int pin) {
  //whatever hardware-specific code here
}
int _readDummyGpio(int pin) {
  return 0;
}

void _initGpios() { //would be called at some point during boot
  for(int i=0; i<NUM_GPIOS; i++) {
    if(i < NUM_HW_GPIOS) readFunc[i] = _readHwGpio;
    else readFunc[i] = _readDummyGpio;
  }
}

int gpioRead(int pin) {
  return readFunc[pin](pin);
}

swGpioReadFunc_t gpioSetReadFunc(int pin, swGpioReadFunc_t func) {
  swGpioReadFunc_t old = readFunc[pin];
  readFunc[pin] = func;
  return old;
}

Now, suppose you're using a library that handles some device for you such as a rotary encoder. It expects to be told which pins the encoder is connected to:

Encoder myEncoder(PIN_ENCODER1, PIN_ENCODER2);

But due to space constraints, you don't want to connect the encoder to a GPIO. Instead, you want to use an I/O expander such as the MCP23017. That means you need to modify the Encoder library. But with this change, you don't!

#define PIN_MCP_BASE 40 //pin 0 of MCP23017 is virtual GPIO40
MCP23017 mcp(PIN_MCP_BASE, whatever);

#define PIN_ENCODER1 (PIN_MCP_BASE+0)
#define PIN_ENCODER2 (PIN_MCP_BASE+1)
Encoder myEncoder(PIN_ENCODER1, PIN_ENCODER2);

int _gpioRead_mcp(int pin) {
  //assume this reads one bit; inefficient for simplicity's sake for demo
  return mcp.read(pin - PIN_MCP_BASE);
}

void setup() {
  gpioSetReadFunc(PIN_MCP_BASE, _gpioRead_mcp);
  gpioSetReadFunc(PIN_MCP_BASE+1, _gpioRead_mcp);
  //...repeat for however many pins you want to use
}

Now when the unmodified Encoder library attempts to read GPIOs 40 and 41, it will actually call _gpioRead_mcp and get data from the I/O expansion. Thus we can use expansions, virtual GPIOs, remote connections, etc transparently with libraries that expect to use normal GPIOs.

Of course this example only demonstrates reading (and assumes Encoder's constructor doesn't touch its GPIOs, else we could use new instead), but the same would apply to other operations.

As a bonus, it would even be possible to hook the real hardware GPIOs, eg for debugging when something is accessing them, inverting their output, remapping them, etc.

You must be logged in to vote

Replies: 0 comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
💡
Ideas
Labels
None yet
1 participant
Morty Proxy This is a proxified and sanitized view of the page, visit original site.