-
Notifications
You must be signed in to change notification settings - Fork 0
Add support for MCP23017 (I2C GPIO expander). #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: driver_tidy
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,9 @@ | ||
| #include <stdio.h> | ||
| #include <string.h> | ||
|
|
||
| #include "gpio.h" | ||
| #include "config.h" | ||
| #include "gpio.h" | ||
| #include "i2c.h" | ||
| #include "messages.h" | ||
|
|
||
| #ifdef BUILD_TESTS | ||
|
|
@@ -19,6 +20,7 @@ | |
| //uint32_t gpio_i2c_mcp_indexes[MAX_I2C_MCP] = {0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}; | ||
| uint32_t gpio_i2c_mcp_indexes[MAX_I2C_MCP] = {0, 0, 0, 0}; | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is used, by gpio_i2c_mcp_alloc. |
||
| uint8_t gpio_i2c_mcp_addresses[MAX_I2C_MCP] = {0xff, 0xff, 0xff, 0xff}; | ||
| uint8_t gpio_last_type[32 * MAX_I2C_MCP]; | ||
|
||
|
|
||
| void update_gpio_config( | ||
| const uint8_t gpio, | ||
|
|
@@ -32,22 +34,23 @@ void update_gpio_config( | |
| printf("ERROR: Higher than MAX_GPIO requested. %u\n", gpio); | ||
| return; | ||
| } | ||
| volatile struct ConfigGPIO *cfg = &config.gpio[gpio]; | ||
|
|
||
| if(type != NULL) { | ||
| config.gpio[gpio].type = *type; | ||
| cfg->type = *type; | ||
| } | ||
| if(index != NULL) { | ||
| if(*index > 32) { | ||
| printf("WARN: GPIO index out of range. Add: %u Index: %u\n", *address, *index); | ||
| } else { | ||
| config.gpio[gpio].index = *index; | ||
| cfg->index = *index; | ||
| } | ||
| } | ||
| if(address != NULL) { | ||
| config.gpio[gpio].address = *address; | ||
| cfg->address = *address; | ||
| } | ||
| if(value != NULL) { | ||
| config.gpio[gpio].value = *value; | ||
| cfg->value = *value; | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -97,7 +100,7 @@ void gpio_set_values(const uint8_t bank, uint32_t values) { | |
|
|
||
| switch(config.gpio[gpio].type) { | ||
| case GPIO_TYPE_NATIVE_OUT_DEBUG: | ||
| printf("DBG GPIO OUT: %u IO: %u val: %u\n", gpio, index, new_value); | ||
| printf("DBG GPIO: %u IO: %u val: %u\n", gpio, index, new_value); | ||
| // Note: no break. | ||
| case GPIO_TYPE_NATIVE_OUT: | ||
| gpio_local_set_out_pin(index, new_value); | ||
|
|
@@ -108,6 +111,7 @@ void gpio_set_values(const uint8_t bank, uint32_t values) { | |
| default: | ||
| break; | ||
| } | ||
| gpio_last_type[gpio] = type; | ||
|
|
||
| update_gpio_config(gpio, NULL, NULL, NULL, &new_value); | ||
| } | ||
|
|
@@ -122,68 +126,57 @@ bool gpio_local_get_pin(uint32_t index) { | |
| return gpio_get(index); | ||
| } | ||
|
|
||
| /* Happens before iterating through gpio data. | ||
| * Do any i2c required operations here. */ | ||
| void gpio_i2c_mcp_prepare() { | ||
| for(uint8_t i2c_bucket = 0; i2c_bucket < MAX_I2C_MCP; i2c_bucket++) { | ||
| // uint8_t i2c_address = gpio_i2c_mcp_addresses[i2c_bucket]; | ||
| // TODO: Any other MCP implementation here. | ||
| int gpio_i2c_mcp_alloc(uint8_t address) { | ||
| int i2c = 0, i2c_free = -1; | ||
| for(i2c = 0; i2c < MAX_I2C_MCP; i2c++) { | ||
| if(gpio_i2c_mcp_addresses[i2c] == address) { | ||
| return i2c; | ||
| } | ||
| if(gpio_i2c_mcp_addresses[i2c] == 0xFF && i2c_free == -1) { | ||
| i2c_free = i2c; | ||
| } | ||
| } | ||
| if (i2c_free != -1) { | ||
| gpio_i2c_mcp_addresses[i2c_free] = address; | ||
| i2c_gpio.config[i2c_free].i2c_address = address; | ||
| i2c_gpio.config[i2c_free].type = I2CGPIO_TYPE_MCP23017; | ||
| } | ||
| return i2c_free; | ||
| } | ||
|
|
||
| /* Find all GPIO pins sharing the same i2c address and put | ||
| */ | ||
| void gpio_i2c_mcp_set_out_pin(uint8_t index, uint8_t address, bool new_value) { | ||
| // Find which slot this i2c address is being stored in. | ||
| uint8_t i2c = MAX_I2C_MCP; | ||
| for(i2c = 0; i2c < MAX_I2C_MCP; i2c++) { | ||
| if(gpio_i2c_mcp_addresses[i2c] == address) { | ||
| break; | ||
| } | ||
| if (gpio_i2c_mcp_addresses[i2c] == 0xff) { | ||
| // Haven't found this address yet. | ||
| // Since this buffer slot is empty, use it for this address. | ||
| gpio_i2c_mcp_addresses[i2c] = address; | ||
| break; | ||
| } | ||
| } | ||
| int i2c = gpio_i2c_mcp_alloc(address); | ||
|
|
||
| if(i2c >= MAX_I2C_MCP) { | ||
| if(i2c == -1) { | ||
| printf("WARN: Too may i2c addresses. Add: %u Index: %u\n", address, index); | ||
| return; | ||
| } | ||
|
|
||
| // Add new_value to buffer to be sent to this i2c address. | ||
| uint8_t bindex = (index >> 3) & 1; | ||
| uint8_t bitmask = 0x1 << (index & 7); | ||
| uint8_t *data = &i2c_gpio.config[i2c].output_data[bindex]; | ||
| if(new_value) { | ||
| gpio_i2c_mcp_indexes[i2c] |= (0x1 << index); | ||
| *data |= bitmask; | ||
| } else { | ||
| gpio_i2c_mcp_indexes[i2c] &= (~(0x1 << index)); | ||
| *data &= ~bitmask; | ||
| } | ||
| } | ||
|
|
||
| /* Happens after iterating through GPIO data. | ||
| * Do any i2c required operations here. */ | ||
| void gpio_i2c_mcp_tranceive() { | ||
| for(uint8_t i2c_bucket = 0; i2c_bucket < MAX_I2C_MCP; i2c_bucket++) { | ||
| // Write gpio_i2c_mcp_indexes[i2c] as output | ||
| // then read inputs into same buffer. | ||
| uint8_t values = gpio_i2c_mcp_indexes[i2c_bucket]; | ||
| uint8_t address = gpio_i2c_mcp_addresses[i2c_bucket]; | ||
| // TODO: Send values to the i2c connected MCP. | ||
| printf("i2c addr: %u values: %#04x\n", address, values); | ||
|
|
||
| // TODO: Read i2c data into gpio_i2c_mcp_indexes[MAX_I2C_MCP] for later | ||
| // UDP transmission. | ||
| } | ||
| } | ||
|
|
||
| bool gpio_i2c_mcp_get_pin(uint8_t index, uint8_t address) { | ||
| for(uint8_t i2c = 0; i2c < MAX_I2C_MCP; i2c++) { | ||
| if(gpio_i2c_mcp_addresses[i2c] == address) { | ||
| return gpio_i2c_mcp_indexes[i2c] | (0x1 << index); | ||
| } | ||
| bool gpio_i2c_mcp_get_pin(uint8_t index, uint8_t address, uint8_t pullup) { | ||
| int i2c = gpio_i2c_mcp_alloc(address); | ||
| if(i2c == -1) { | ||
| printf("WARN: Too may i2c addresses. Add: %u Index: %u\n", address, index); | ||
| return false; | ||
| } | ||
| return 0; | ||
| uint8_t bindex = (index >> 3) & 1; | ||
| uint8_t bmask = (1 << (index & 7)); | ||
| uint8_t data = i2c_gpio.config[i2c].input_data[bindex]; | ||
| //printf("%02x:%d = %d [%02x, %02x]\n", address, index, (data & bmask), data, bmask); | ||
| return data & bmask ? 1 : 0; | ||
| } | ||
|
|
||
| /* Pack GPIO inputs in buffer for UDP transmission. */ | ||
|
|
@@ -209,7 +202,7 @@ void gpio_serialize(struct NWBuffer* tx_buf, size_t* tx_buf_len) { | |
|
|
||
| get_gpio_config(gpio, &type, &index, &address, &previous_value); | ||
|
|
||
| switch(config.gpio[gpio].type) { | ||
| switch(type) { | ||
| case GPIO_TYPE_NATIVE_IN_DEBUG: | ||
| case GPIO_TYPE_NATIVE_IN: | ||
| new_value = gpio_local_get_pin(index); | ||
|
|
@@ -221,7 +214,8 @@ void gpio_serialize(struct NWBuffer* tx_buf, size_t* tx_buf_len) { | |
| } | ||
| break; | ||
| case GPIO_TYPE_I2C_MCP_IN: | ||
| new_value = gpio_i2c_mcp_get_pin(index, address); | ||
| case GPIO_TYPE_I2C_MCP_IN_PULLUP: | ||
| new_value = gpio_i2c_mcp_get_pin(index, address, type == GPIO_TYPE_I2C_MCP_IN_PULLUP); | ||
| if(previous_value != new_value) { | ||
| to_send[bank] = true; | ||
| config.gpio_confirmation_pending[bank] = true; | ||
|
|
@@ -234,6 +228,7 @@ void gpio_serialize(struct NWBuffer* tx_buf, size_t* tx_buf_len) { | |
| new_value = previous_value; | ||
| break; | ||
| } | ||
| gpio_last_type[gpio] = type; | ||
|
|
||
| values[bank] |= (new_value << (gpio % 32)); | ||
| } | ||
|
|
@@ -242,20 +237,20 @@ void gpio_serialize(struct NWBuffer* tx_buf, size_t* tx_buf_len) { | |
| reply.type = REPLY_GPIO; | ||
|
|
||
| for(uint8_t bank = 0; bank < MAX_GPIO_BANK; bank++) { | ||
| if(! config.gpio_confirmation_pending[bank]) { | ||
| continue; | ||
| } | ||
| if(! config.gpio_confirmation_pending[bank]) { | ||
| continue; | ||
| } | ||
|
|
||
| reply.bank = bank; | ||
| reply.values = values[bank]; | ||
| reply.confirmation_pending = to_send[bank]; | ||
| reply.bank = bank; | ||
| reply.values = values[bank]; | ||
| reply.confirmation_pending = to_send[bank]; | ||
|
|
||
| *tx_buf_len = pack_nw_buff(tx_buf, &reply, sizeof(reply)); | ||
| *tx_buf_len = pack_nw_buff(tx_buf, &reply, sizeof(reply)); | ||
|
|
||
| if(! *tx_buf_len) { | ||
| printf("WARN: TX length greater than buffer size. gpio bank: %u\n", bank); | ||
| return; | ||
| } | ||
| if(! *tx_buf_len) { | ||
| printf("WARN: TX length greater than buffer size. gpio bank: %u\n", bank); | ||
| return; | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.