diff --git a/components/badge23/include/badge23/spio.h b/components/badge23/include/badge23/spio.h index e12afbb207fac7654bb55fb81568e5acf9d311d9..6de6699987b0f306c7ae46bf02d5488eccb50298 100644 --- a/components/badge23/include/badge23/spio.h +++ b/components/badge23/include/badge23/spio.h @@ -16,16 +16,6 @@ #define BADGE_LINK_PIN_MASK_LINE_OUT ((BADGE_LINK_PIN_MASK_LINE_OUT_TIP) | (BADGE_LINK_PIN_MASK_LINE_OUT_RING)) #define BADGE_LINK_PIN_MASK_ALL ((BADGE_LINK_PIN_MASK_LINE_IN) | (BADGE_LINK_PIN_MASK_LINE_OUT)) -#define BADGE_LINK_PIN_INDEX_LINE_IN_TIP 4 -#define BADGE_LINK_PIN_INDEX_LINE_IN_RING 5 -#if defined(CONFIG_BADGE23_HW_GEN_P6) -#define BADGE_LINK_PIN_INDEX_LINE_OUT_TIP 7 -#define BADGE_LINK_PIN_INDEX_LINE_OUT_RING 6 -#else -#define BADGE_LINK_PIN_INDEX_LINE_OUT_TIP 6 -#define BADGE_LINK_PIN_INDEX_LINE_OUT_RING 7 -#endif - /* Initializes GPIO modes, prefills structs, etc. Call before using library. */ void init_buttons(); diff --git a/components/badge23/spio.c b/components/badge23/spio.c index 1c65765713ee1daa9fdd9d226828490ca277145f..58855354bcc3b7506011b441b15df57c7f3c7661 100644 --- a/components/badge23/spio.c +++ b/components/badge23/spio.c @@ -1,424 +1,100 @@ -//special purpose input outputs -#include "driver/gpio.h" -#include "stdint.h" #include "badge23/spio.h" -#include "st3m_audio.h" -#include "flow3r_bsp_i2c.h" - -#include "driver/i2c.h" -#define TIMEOUT_MS 1000 - -#if defined(CONFIG_BADGE23_HW_GEN_P1) - -#define BADGE_LINK_LINE_OUT_TIP_ENABLE_PIN 5 -#define BADGE_LINK_LINE_OUT_RING_ENABLE_PIN 6 -#define BADGE_LINK_LINE_IN_TIP_ENABLE_PIN 3 -#define BADGE_LINK_LINE_IN_RING_ENABLE_PIN 4 - -#elif defined(CONFIG_BADGE23_HW_GEN_P4) || defined(CONFIG_BADGE23_HW_GEN_P3) - -#define BADGE_LINK_LINE_OUT_TIP_ENABLE_PIN 6 -#define BADGE_LINK_LINE_OUT_RING_ENABLE_PIN 7 -#define BADGE_LINK_LINE_IN_TIP_ENABLE_PIN 5 -#define BADGE_LINK_LINE_IN_RING_ENABLE_PIN 4 - -//on ESP32 -#define LEFT_BUTTON_LEFT 3 -#define LEFT_BUTTON_MID 0 - -//on PORTEXPANDER -#define LEFT_BUTTON_RIGHT (0+8) -#define RIGHT_BUTTON_LEFT (6+8) -#define RIGHT_BUTTON_MID (5+8) -#define RIGHT_BUTTON_RIGHT (7+8) - -#elif defined(CONFIG_BADGE23_HW_GEN_P6) - -#define BADGE_LINK_LINE_OUT_RING_ENABLE_PIN 5 -#define BADGE_LINK_LINE_OUT_TIP_ENABLE_PIN 6 -#define BADGE_LINK_LINE_IN_TIP_ENABLE_PIN 4 -#define BADGE_LINK_LINE_IN_RING_ENABLE_PIN 3 - -#define ENABLE_INVERTED - -//on ESP32 -#define RIGHT_BUTTON_MID 3 -#define LEFT_BUTTON_MID 0 - -//on PORTEXPANDER -#define LEFT_BUTTON_RIGHT (0+8) -#define RIGHT_BUTTON_LEFT (4+8) -#define LEFT_BUTTON_LEFT (7+8) -#define RIGHT_BUTTON_RIGHT (5+8) - -#define LINE_IN_JACKSENSE (6+8) -#define CHARGER_STATE (2+8) - -#endif - -static int8_t leftbutton = 0; -static int8_t rightbutton = 0; - -static bool line_in_jacksense = 1; -static bool charger_state; - -static bool menu_button_left = 0; - -static uint8_t badge_link_enabled = 0; - -/* The MAX7321 doesn't have any input/output pin configuration methods. Instead, - * it has a ~40k pullup resistor to VCC and a programmable shunt transistor to VEE. - * Writing a byte to the IC closes each shunt with a LO at its index. - * Reading a byte returns the state of each pin. - * - * This means that changing a single output bit cannot be changed without some - * information about the other pins. Also a output pin set to HI can read as LO - * if there's an outside shunt. - */ -typedef struct{ - flow3r_i2c_address *addr; - uint8_t is_output_pin; // mask for pins we wish to use as outputs - uint8_t read_state; // - uint8_t output_state; // goal output state -} max7321_t; - -max7321_t port_expanders[2]; - -void _max7321_update(max7321_t *max){ - uint8_t rx = 0; - uint8_t tx = (~(max->is_output_pin)) | max->output_state; - - flow3r_bsp_i2c_write_read_device(*max->addr, &tx, sizeof(tx), &rx, sizeof(rx), TIMEOUT_MS / portTICK_PERIOD_MS); - // TODO(q3k): handle error - max->read_state = rx; -} - -void max7321s_update(){ - _max7321_update(&port_expanders[0]); - _max7321_update(&port_expanders[1]); -} - -bool max7321s_get_pin(uint8_t pin){ - if(pin>15) return 0; - max7321_t * pe = &port_expanders[0]; - if(pin>7){ - pe = &port_expanders[1]; - pin -= 8; - } - return ((pe->read_state) >> pin) & 1; -} - -bool max7321s_set_pin(uint8_t pin, bool on){ - if(pin>15) return 0; - max7321_t * pe = &port_expanders[0]; - if(pin>7){ - pe = &port_expanders[1]; - pin -= 8; - } - - if(((pe->is_output_pin) >> pin) & 1){ - if(on){ - pe->output_state |= 1<<pin; - } else { - pe->output_state &= ~(1<<pin); - } - return 1; - } else { - return 0; - } -} - -void max7321s_set_pinmode_output(uint8_t pin, bool output){ - if(pin>15) return 0; - max7321_t * pe = &port_expanders[0]; - if(pin>7){ - pe = &port_expanders[1]; - pin -= 8; - } - if(output){ - pe->is_output_pin |= (1<<pin); - } else { - pe->is_output_pin &= ~(1<<pin); - } -} - -#if defined(CONFIG_BADGE23_HW_GEN_P1) - -#define RIGHT_BUTTON_LEFT 37 -#define RIGHT_BUTTON_MID 0 -#define RIGHT_BUTTON_RIGHT 35 - -#define LEFT_BUTTON_LEFT 7 -#define LEFT_BUTTON_MID 6 -#define LEFT_BUTTON_RIGHT 5 - -static void _init_buttons(){ - //configure all buttons as pullup - uint64_t mask = 0; - mask |= (1ULL << RIGHT_BUTTON_LEFT); - mask |= (1ULL << RIGHT_BUTTON_RIGHT); - mask |= (1ULL << LEFT_BUTTON_LEFT); - mask |= (1ULL << LEFT_BUTTON_MID); - mask |= (1ULL << LEFT_BUTTON_RIGHT); - gpio_config_t cfg = { - .pin_bit_mask = mask, - .mode = GPIO_MODE_INPUT, - .pull_up_en = GPIO_PULLUP_ENABLE, - .pull_down_en = GPIO_PULLDOWN_DISABLE, - .intr_type = GPIO_INTR_DISABLE - }; - ESP_ERROR_CHECK(gpio_config(&cfg)); - cfg.pin_bit_mask = 1; - cfg.pull_up_en = GPIO_PULLUP_DISABLE; - ESP_ERROR_CHECK(gpio_config(&cfg)); -} - -void update_button_state(){ - if(!gpio_get_level(RIGHT_BUTTON_LEFT)){ - rightbutton = BUTTON_PRESSED_LEFT; - } else if(!gpio_get_level(RIGHT_BUTTON_MID)){ - rightbutton = BUTTON_PRESSED_DOWN; - } else if(!gpio_get_level(RIGHT_BUTTON_RIGHT)){ - rightbutton = BUTTON_PRESSED_RIGHT; - } else { - rightbutton = BUTTON_NOT_PRESSED; - } - - if(!gpio_get_level(LEFT_BUTTON_LEFT)){ - leftbutton = BUTTON_PRESSED_LEFT; - } else if(!gpio_get_level(LEFT_BUTTON_MID)){ - leftbutton = BUTTON_PRESSED_DOWN; - } else if(!gpio_get_level(LEFT_BUTTON_RIGHT)){ - leftbutton = BUTTON_PRESSED_RIGHT; - } else { - leftbutton = BUTTON_NOT_PRESSED; - } -} - -#elif defined(CONFIG_BADGE23_HW_GEN_P3) || defined(CONFIG_BADGE23_HW_GEN_P4) - -max7321_t port_expanders[] = { {&flow3r_i2c_addresses.portexp[0], 0, 255, 255}, - {&flow3r_i2c_addresses.portexp[1], 0, 255, 255} }; - -static void _init_buttons(){ - //configure all buttons as pullup - gpio_config_t cfg = { - .pin_bit_mask = 1 << LEFT_BUTTON_LEFT, - .mode = GPIO_MODE_INPUT, - .pull_up_en = GPIO_PULLUP_ENABLE, - .pull_down_en = GPIO_PULLDOWN_DISABLE, - .intr_type = GPIO_INTR_DISABLE - }; - ESP_ERROR_CHECK(gpio_config(&cfg)); - cfg.pin_bit_mask = 1; - cfg.pull_up_en = GPIO_PULLUP_DISABLE; - ESP_ERROR_CHECK(gpio_config(&cfg)); - - max7321s_set_pinmode_output(RIGHT_BUTTON_RIGHT, 0); - max7321s_set_pinmode_output(RIGHT_BUTTON_MID, 0); - max7321s_set_pinmode_output(RIGHT_BUTTON_LEFT, 0); - max7321s_set_pinmode_output(LEFT_BUTTON_RIGHT, 0); -} - -int8_t process_button_state(bool r, bool m, bool l){ - if(!l){ - return BUTTON_PRESSED_LEFT; - } else if(!m){ - return BUTTON_PRESSED_DOWN; - } else if(!r){ - return BUTTON_PRESSED_RIGHT; - } else { - return BUTTON_NOT_PRESSED; - } -} - -void update_button_state(){ - max7321s_update(); - uint8_t rr = max7321s_get_pin(RIGHT_BUTTON_RIGHT); - uint8_t rm = max7321s_get_pin(RIGHT_BUTTON_MID); - uint8_t rl = max7321s_get_pin(RIGHT_BUTTON_LEFT); - uint8_t lr = max7321s_get_pin(LEFT_BUTTON_RIGHT); - uint8_t ll = gpio_get_level(LEFT_BUTTON_LEFT); - uint8_t lm = gpio_get_level(LEFT_BUTTON_MID); - - int8_t new_rightbutton = process_button_state(rr, rm, rl); - int8_t new_leftbutton = process_button_state(lr, lm, ll); - if(new_rightbutton != rightbutton){ - //TODO: CALLBACK button_state_has_changed_to(new_rightbutton) - //note: consider menubutton/application button config option - } - if(new_leftbutton != leftbutton){ - //TODO: CALLBACK button_state_has_changed_to(new_leftbutton) - } - rightbutton = new_rightbutton; - leftbutton = new_leftbutton; -} -#elif defined(CONFIG_BADGE23_HW_GEN_P6) -max7321_t port_expanders[] = { {&flow3r_i2c_addresses.portexp[0], 0, 255, 255}, - {&flow3r_i2c_addresses.portexp[1], 0, 255, 255} }; +static const char *TAG = "badge23-spio"; -static void _init_buttons(){ - //configure all buttons as pullup - gpio_config_t cfg = { - .pin_bit_mask = 1 << RIGHT_BUTTON_MID, - .mode = GPIO_MODE_INPUT, - .pull_up_en = GPIO_PULLUP_ENABLE, - .pull_down_en = GPIO_PULLDOWN_DISABLE, - .intr_type = GPIO_INTR_DISABLE - }; - ESP_ERROR_CHECK(gpio_config(&cfg)); - cfg.pin_bit_mask = 1; - cfg.pull_up_en = GPIO_PULLUP_DISABLE; - ESP_ERROR_CHECK(gpio_config(&cfg)); - - max7321s_set_pinmode_output(RIGHT_BUTTON_RIGHT, 0); - max7321s_set_pinmode_output(LEFT_BUTTON_LEFT, 0); - max7321s_set_pinmode_output(RIGHT_BUTTON_LEFT, 0); - max7321s_set_pinmode_output(LEFT_BUTTON_RIGHT, 0); -} +#include "esp_log.h" -int8_t process_button_state(bool r, bool m, bool l){ - if(!l){ - return BUTTON_PRESSED_LEFT; - } else if(!m){ - return BUTTON_PRESSED_DOWN; - } else if(!r){ - return BUTTON_PRESSED_RIGHT; - } else { - return BUTTON_NOT_PRESSED; - } -} +#include "st3m_audio.h" +#include "flow3r_bsp_i2c.h" +#include "flow3r_bsp.h" void update_button_state(){ - max7321s_update(); - uint8_t rr = max7321s_get_pin(RIGHT_BUTTON_RIGHT); - uint8_t ll = max7321s_get_pin(LEFT_BUTTON_LEFT); - uint8_t rl = max7321s_get_pin(RIGHT_BUTTON_LEFT); - uint8_t lr = max7321s_get_pin(LEFT_BUTTON_RIGHT); - uint8_t rm = gpio_get_level(RIGHT_BUTTON_MID); - uint8_t lm = gpio_get_level(LEFT_BUTTON_MID); - - line_in_jacksense = max7321s_get_pin(LINE_IN_JACKSENSE); - charger_state = max7321s_get_pin(CHARGER_STATE); - - int8_t new_rightbutton = process_button_state(rr, rm, rl); - int8_t new_leftbutton = process_button_state(lr, lm, ll); - if(new_rightbutton != rightbutton){ - //TODO: CALLBACK button_state_has_changed_to(new_rightbutton) - //note: consider menubutton/application button config option - } - if(new_leftbutton != leftbutton){ - //TODO: CALLBACK button_state_has_changed_to(new_leftbutton) + esp_err_t ret = flow3r_bsp_spio_update(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "update failed: %s", esp_err_to_name(ret)); } - rightbutton = new_rightbutton; - leftbutton = new_leftbutton; } -#else -#error "spio not implemented for this badge generation" -#endif - void init_buttons(){ - _init_buttons(); -} - -//#define ALWAYS_UPDATE_BUTTON -int8_t get_button_state(bool left){ -#ifdef ALWAYS_UPDATE_BUTTON - update_button_state(); -#endif - if(left) return leftbutton; - return rightbutton; + esp_err_t ret = flow3r_bsp_spio_init(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "init failed: %s", esp_err_to_name(ret)); + for (;;) {} + } } -bool spio_charger_state_get(){ -#ifdef ALWAYS_UPDATE_BUTTON - update_button_state(); -#endif - return charger_state; +bool spio_charger_state_get() { + return flow3r_bsp_spio_charger_state_get(); } bool spio_line_in_jacksense_get(){ -#ifdef ALWAYS_UPDATE_BUTTON - update_button_state(); -#endif - return line_in_jacksense; + return flow3r_bsp_spio_jacksense_right_get(); } +static bool menu_button_left = false; + void spio_menu_button_set_left(bool left){ - menu_button_left = 1; + menu_button_left = left; } -int8_t spio_menu_button_get(){ - return get_button_state(menu_button_left); +int8_t spio_menu_button_get() { + if (menu_button_left) + return flow3r_bsp_spio_left_button_get(); + return flow3r_bsp_spio_right_button_get(); } int8_t spio_application_button_get(){ - return get_button_state(!menu_button_left); + if (menu_button_left) + return flow3r_bsp_spio_right_button_get(); + return flow3r_bsp_spio_left_button_get(); } int8_t spio_left_button_get(){ - return get_button_state(1); + return flow3r_bsp_spio_left_button_get(); } int8_t spio_right_button_get(){ - return get_button_state(0); + return flow3r_bsp_spio_right_button_get(); } int8_t spio_menu_button_get_left(){ return menu_button_left; } +static uint8_t badge_link_enabled = 0; + uint8_t spio_badge_link_get_active(uint8_t pin_mask){ return badge_link_enabled & pin_mask; } -#if defined(CONFIG_BADGE23_HW_GEN_P1) - -static uint8_t spio_badge_link_set(uint8_t pin_mask, uint8_t state){ - return 0; // no badge link here (yet) -} - -#elif defined(CONFIG_BADGE23_HW_GEN_P3) || defined(CONFIG_BADGE23_HW_GEN_P4) || defined(CONFIG_BADGE23_HW_GEN_P6) - -#define USER_WARNINGS_ENABLED - -static int8_t spio_badge_link_set(uint8_t pin_mask, bool state){ +static int8_t spio_badge_link_set(uint8_t mask, bool state) { + bool left_tip = (mask & BADGE_LINK_PIN_MASK_LINE_OUT_TIP) > 0; + bool left_ring = (mask & BADGE_LINK_PIN_MASK_LINE_OUT_RING) > 0; + bool right_tip = (mask & BADGE_LINK_PIN_MASK_LINE_IN_TIP) > 0; + bool right_ring = (mask & BADGE_LINK_PIN_MASK_LINE_IN_RING) > 0; if(state) { - if((pin_mask & BADGE_LINK_PIN_MASK_LINE_OUT_RING) || (pin_mask & BADGE_LINK_PIN_MASK_LINE_OUT_TIP)){ + if (left_tip || left_ring) { if(!st3m_audio_headphones_are_connected()) { - pin_mask &= ~BADGE_LINK_PIN_MASK_LINE_OUT_RING; - pin_mask &= ~BADGE_LINK_PIN_MASK_LINE_OUT_TIP; -#ifdef USER_WARNINGS_ENABLED - printf("cannot enable line out badge link without cable plugged in for safety reasons\n"); - } else { - printf("badge link enabled on line out. please make sure not to have headphones or sound sources connected before transmitting data.\n"); -#endif + left_tip = false; + left_ring = false; + ESP_LOGE(TAG, "cannot enable line out badge link without cable plugged in for safety reasons"); } } + if (left_tip) badge_link_enabled |= BADGE_LINK_PIN_MASK_LINE_OUT_TIP; + if (left_ring) badge_link_enabled |= BADGE_LINK_PIN_MASK_LINE_OUT_RING; + if (right_tip) badge_link_enabled |= BADGE_LINK_PIN_MASK_LINE_IN_TIP; + if (right_ring) badge_link_enabled |= BADGE_LINK_PIN_MASK_LINE_IN_RING; + } else { + if (!left_tip) badge_link_enabled &= ~BADGE_LINK_PIN_MASK_LINE_OUT_TIP; + if (!left_ring) badge_link_enabled &= ~BADGE_LINK_PIN_MASK_LINE_OUT_RING; + if (!right_tip) badge_link_enabled &= ~BADGE_LINK_PIN_MASK_LINE_IN_TIP; + if (!right_ring) badge_link_enabled &= ~BADGE_LINK_PIN_MASK_LINE_IN_RING; } -#ifdef ENABLE_INVERTED - uint8_t hw_state = state; -#else - uint8_t hw_state = !state; -#endif - if(pin_mask & BADGE_LINK_PIN_MASK_LINE_IN_RING) max7321s_set_pinmode_output(BADGE_LINK_LINE_IN_RING_ENABLE_PIN, 1); - if(pin_mask & BADGE_LINK_PIN_MASK_LINE_IN_TIP) max7321s_set_pinmode_output(BADGE_LINK_LINE_IN_TIP_ENABLE_PIN, 1); - if(pin_mask & BADGE_LINK_PIN_MASK_LINE_OUT_RING) max7321s_set_pinmode_output(BADGE_LINK_LINE_OUT_RING_ENABLE_PIN, 1); - if(pin_mask & BADGE_LINK_PIN_MASK_LINE_OUT_TIP) max7321s_set_pinmode_output(BADGE_LINK_LINE_OUT_TIP_ENABLE_PIN, 1); - - if(pin_mask & BADGE_LINK_PIN_MASK_LINE_IN_RING) max7321s_set_pin(BADGE_LINK_LINE_IN_RING_ENABLE_PIN, hw_state); - if(pin_mask & BADGE_LINK_PIN_MASK_LINE_IN_TIP) max7321s_set_pin(BADGE_LINK_LINE_IN_TIP_ENABLE_PIN, hw_state); - if(pin_mask & BADGE_LINK_PIN_MASK_LINE_OUT_RING) max7321s_set_pin(BADGE_LINK_LINE_OUT_RING_ENABLE_PIN, hw_state); - if(pin_mask & BADGE_LINK_PIN_MASK_LINE_OUT_TIP) max7321s_set_pin(BADGE_LINK_LINE_OUT_TIP_ENABLE_PIN, hw_state); - - max7321s_update(); - badge_link_enabled = (badge_link_enabled & (~pin_mask)) | (pin_mask & (hw_state ? 255 : 0)); - return spio_badge_link_get_active(pin_mask); + flow3r_bsp_spio_badgelink_left_enable(left_tip, left_ring); + flow3r_bsp_spio_badgelink_right_enable(right_tip, right_ring); + return spio_badge_link_get_active(mask); } -#endif uint8_t spio_badge_link_disable(uint8_t pin_mask){ return spio_badge_link_set(pin_mask, 0); diff --git a/components/flow3r_bsp/CMakeLists.txt b/components/flow3r_bsp/CMakeLists.txt index 7d165308ddb41193fe16794ee21d2e6eaffe97a4..9414a39ee6c382900b5d0204e23c8be4feb341fb 100644 --- a/components/flow3r_bsp/CMakeLists.txt +++ b/components/flow3r_bsp/CMakeLists.txt @@ -5,10 +5,12 @@ idf_component_register( flow3r_bsp_gc9a01.c flow3r_bsp_hwconfig.c flow3r_bsp_i2c.c + flow3r_bsp_max7321.c flow3r_bsp_max98091.c flow3r_bsp_leds.c flow3r_bsp_rmtled.c flow3r_bsp_spiled.c + flow3r_bsp_spio.c INCLUDE_DIRS . ) diff --git a/components/flow3r_bsp/flow3r_bsp.h b/components/flow3r_bsp/flow3r_bsp.h index 8fd857a7ecfd7901d2866b07abce050d6298eca0..def81e768bbe91854ad0b4c8ec5f97ec6d8696a8 100644 --- a/components/flow3r_bsp/flow3r_bsp.h +++ b/components/flow3r_bsp/flow3r_bsp.h @@ -137,4 +137,60 @@ void flow3r_bsp_leds_set_pixel(uint32_t index, uint32_t red, uint32_t green, uin // Transmit from internal buffer into LEDs. This will block in case there // already is a previous transmission happening. -esp_err_t flow3r_bsp_leds_refresh(TickType_t timeout_ms); \ No newline at end of file +esp_err_t flow3r_bsp_leds_refresh(TickType_t timeout_ms); + +// A 'tripos' button is what we're calling the shoulder buttons. As the name +// indicates, it has three positions: left, middle (a.k.a. down/press) and right. +typedef enum { + // Not pressed. + flow3r_bsp_tripos_none = 0, + // Pressed towards the left. + flow3r_bsp_tripos_left = -1, + // Pressed down. + flow3r_bsp_tripos_mid = 2, + // Pressed towards the right. + flow3r_bsp_tripos_right = 1, +} flow3r_bsp_tripos_state_t; + +// Initialize 'special purpose i/o', which is like gpio, but more :). This means +// effectively all the buttons and on-board detect/enable signals. +esp_err_t flow3r_bsp_spio_init(void); + +// Refresh the state of I/O: update outputs based on last called _set functions, +// and make _get return the newest hardware state. +esp_err_t flow3r_bsp_spio_update(void); + +// Return the latest updated position of the left shoulder/tripos button. +// +// flow3r_bsp_spio_update must be called for this data to be up to date. +flow3r_bsp_tripos_state_t flow3r_bsp_spio_left_button_get(void); + +// Return the latest updated position of the right shoulder/tripos button. +// +// flow3r_bsp_spio_update must be called for this data to be up to date. +flow3r_bsp_tripos_state_t flow3r_bsp_spio_right_button_get(void); + +// Returns true if the device is charging. +// +// flow3r_bsp_spio_update must be called for this data to be up to date. +bool flow3r_bsp_spio_charger_state_get(void); + +// Returns true if the device has something plugged into the right 3.5mm jack. +// +// flow3r_bsp_spio_update must be called for this data to be up to date. +bool flow3r_bsp_spio_jacksense_right_get(void); + +// Switch tip/ring muxes to 'badgelink' digital I/O data pins on the left hand +// jack. As this is the same as the headphone jack, please observe caution when +// enabling this! See the comment at the bottom of st3m_audio.h. +// +// flow3r_bsp_spio_update must be called for this setting to actually propagate +// to hardware. +void flow3r_bsp_spio_badgelink_left_enable(bool tip_on, bool ring_on); + +// Switch tip/ring muxes to 'badgelink' digital I/O data pins on the right hand +// jack. +// +// flow3r_bsp_spio_update must be called for this setting to actually propagate +// to hardware. +void flow3r_bsp_spio_badgelink_right_enable(bool tip_on, bool ring_on); \ No newline at end of file diff --git a/components/flow3r_bsp/flow3r_bsp_max7321.c b/components/flow3r_bsp/flow3r_bsp_max7321.c new file mode 100644 index 0000000000000000000000000000000000000000..47329c2d159ea67ee13743b20dcb1d2af8bc4cbe --- /dev/null +++ b/components/flow3r_bsp/flow3r_bsp_max7321.c @@ -0,0 +1,59 @@ +#include "flow3r_bsp_max7321.h" +#include "flow3r_bsp_i2c.h" + +/* The MAX7321 doesn't have any input/output pin configuration methods. Instead, + * it has a ~40k pullup resistor to VCC and a programmable shunt transistor to VEE. + * Writing a byte to the IC closes each shunt with a LO at its index. + * Reading a byte returns the state of each pin. + * + * This means that changing a single output bit cannot be changed without some + * information about the other pins. Also a output pin set to HI can read as LO + * if there's an outside shunt. + */ + +// TODO(q3k): unhardcode +#define TIMEOUT_MS 1000 + +esp_err_t flow3r_bsp_max7321_init(flow3r_bsp_max7321_t *max, flow3r_i2c_address addr) { + max->addr = addr; + max->is_output_pin = 0; + max->read_state = 0xff; + max->output_state = 0xff; + + return flow3r_bsp_max7321_update(max); +} + +void flow3r_bsp_max7321_set_pinmode_output(flow3r_bsp_max7321_t *max, uint32_t pin, bool output) { + if(output) { + max->is_output_pin |= (1<<pin); + } else { + max->is_output_pin &= ~(1<<pin); + } +} + +bool flow3r_bsp_max7321_get_pin(flow3r_bsp_max7321_t *max, uint32_t pin) { + return ((max->read_state) >> pin) & 1; +} + +void flow3r_bsp_max7321_set_pin(flow3r_bsp_max7321_t *max, uint32_t pin, bool on) { + if(((max->is_output_pin) >> pin) & 1){ + if(on){ + max->output_state |= 1<<pin; + } else { + max->output_state &= ~(1<<pin); + } + } +} + +esp_err_t flow3r_bsp_max7321_update(flow3r_bsp_max7321_t *max) { + uint8_t rx = 0; + uint8_t tx = (~(max->is_output_pin)) | max->output_state; + + esp_err_t ret = flow3r_bsp_i2c_write_read_device(max->addr, &tx, sizeof(tx), &rx, sizeof(rx), TIMEOUT_MS / portTICK_PERIOD_MS); + if (ret != ESP_OK) { + return ret; + } + max->read_state = rx; + + return ESP_OK; +} \ No newline at end of file diff --git a/components/flow3r_bsp/flow3r_bsp_max7321.h b/components/flow3r_bsp/flow3r_bsp_max7321.h new file mode 100644 index 0000000000000000000000000000000000000000..79ae185e41d9566ae0e494c9241d56b887af01f9 --- /dev/null +++ b/components/flow3r_bsp/flow3r_bsp_max7321.h @@ -0,0 +1,23 @@ +#pragma once + +#include <stdbool.h> +#include <stdint.h> + +#include "flow3r_bsp_i2c.h" + +#include "esp_err.h" + +typedef struct { + flow3r_i2c_address addr; + // mask for pins we wish to use as outputs + uint8_t is_output_pin; + uint8_t read_state; + // goal output state + uint8_t output_state; +} flow3r_bsp_max7321_t; + +esp_err_t flow3r_bsp_max7321_init(flow3r_bsp_max7321_t *max, flow3r_i2c_address addr); +void flow3r_bsp_max7321_set_pinmode_output(flow3r_bsp_max7321_t *max, uint32_t pin, bool output); +bool flow3r_bsp_max7321_get_pin(flow3r_bsp_max7321_t *max, uint32_t pin); +void flow3r_bsp_max7321_set_pin(flow3r_bsp_max7321_t *max, uint32_t pin, bool on); +esp_err_t flow3r_bsp_max7321_update(flow3r_bsp_max7321_t *max); \ No newline at end of file diff --git a/components/flow3r_bsp/flow3r_bsp_spio.c b/components/flow3r_bsp/flow3r_bsp_spio.c new file mode 100644 index 0000000000000000000000000000000000000000..3acfb39525f4ff93dcc797fb2899874cf025ce8c --- /dev/null +++ b/components/flow3r_bsp/flow3r_bsp_spio.c @@ -0,0 +1,319 @@ +#include "flow3r_bsp.h" + +#include <stdbool.h> + +#include "driver/gpio.h" +#include "esp_log.h" + +static const char *TAG = "flow3r-spio"; + +typedef enum { + flow3r_bsp_iochip_esp32 = 0, + flow3r_bsp_iochip_portexp = 1, + flow3r_bsp_iochip_dummy = 2, +} flow3r_bsp_iochip_t; + + +typedef struct { + flow3r_bsp_iochip_t chip; + uint32_t pin; + bool output; + bool pullup; + bool invert; +} flow3r_bsp_iopin_t; + +#define IESP(pinno, pullup_, ...) { .chip = flow3r_bsp_iochip_esp32, .pin = pinno, .output = false, .pullup = pullup_ , __VA_ARGS__} +#define IPEX(pinno, pexno, ...) { .chip = flow3r_bsp_iochip_portexp, .pin = pinno + pexno * 8, .output = false, __VA_ARGS__ } +#define OPEX(pinno, pexno, ...) { .chip = flow3r_bsp_iochip_portexp, .pin = pinno + pexno * 8, .output = true, __VA_ARGS__ } +#define IODUMMY { .chip = flow3r_bsp_iochip_dummy } + +typedef struct { + flow3r_bsp_iopin_t left; + flow3r_bsp_iopin_t mid; + flow3r_bsp_iopin_t right; +} flow3r_bsp_iodef_tripos_t; + +typedef struct { + flow3r_bsp_iopin_t tip_badgelink_enable; + flow3r_bsp_iopin_t ring_badgelink_enable; +} flow3r_bsp_iodef_trrs_t; + +typedef struct { + flow3r_bsp_iodef_tripos_t tripos_left; + flow3r_bsp_iodef_tripos_t tripos_right; + flow3r_bsp_iodef_trrs_t trrs_left; + flow3r_bsp_iodef_trrs_t trrs_right; + + flow3r_bsp_iopin_t charger_state; + flow3r_bsp_iopin_t jacksense_right; +} flow3r_bsp_iodef_t; + +#if defined(CONFIG_BADGE23_HW_GEN_P1) +static const flow3r_bsp_iodef_t iodef = { + .tripos_left = { + .left = IPEX(37, 1), + .mid = IESP(0, false), + .right = IPEX(35, 1), + }, + .tripos_right = { + .left = IESP(7, 1), + .mid = IESP(6, true), + .right = IESP(5, 1), + }, + .trrs_left = { + .tip_badgelink_enable = IODUMMY, + .ring_badgelink_enable = IODUMMY, + }, + .trrs_right = { + .tip_badgelink_enable = IODUMMY, + .ring_badgelink_enable = IODUMMY, + }, + .charger_state = IODUMMY, + .jacksense_right = IODUMMY, +}; +#define PORTEXP_NONE +#elif defined(CONFIG_BADGE23_HW_GEN_P4) || defined(CONFIG_BADGE23_HW_GEN_P3) +static const flow3r_bsp_iodef_t iodef = { + .tripos_left = { + .left = IESP(3, true), + .mid = IESP(0, false), + .right = IPEX(0, 1), + }, + .tripos_right = { + .left = IPEX(6, 1), + .mid = IPEX(5, 1), + .right = IPEX(7, 1), + }, + .trrs_left = { + .tip_badgelink_enable = OPEX(6, 0), + .ring_badgelink_enable = OPEX(7, 0), + }, + .trrs_right = { + .tip_badgelink_enable = OPEX(5, 0), + .ring_badgelink_enable = OPEX(4, 0), + }, + .charger_state = IODUMMY, + .jacksense_right = IODUMMY, +}; +#define PORTEXP_MAX7321S +#elif defined(CONFIG_BADGE23_HW_GEN_P6) +static const flow3r_bsp_iodef_t iodef = { + .tripos_left = { + .left = IPEX(7, 1, .invert = true), + .mid = IESP(0, false, .invert = true), + .right = IPEX(0, 1, .invert = true), + }, + .tripos_right = { + .left = IPEX(4, 1, .invert = true), + .mid = IESP(3, true, .invert = true), + .right = IPEX(5, 1, .invert = true), + }, + .trrs_left = { + .tip_badgelink_enable = OPEX(6, 0, .invert = true), + .ring_badgelink_enable = OPEX(5, 0, .invert = true), + }, + .trrs_right = { + .tip_badgelink_enable = OPEX(4, 0, .invert = true), + .ring_badgelink_enable = OPEX(3, 0, .invert = true), + }, + .charger_state = IPEX(2, 1), + .jacksense_right = IPEX(6, 1), +}; +#define PORTEXP_MAX7321S +#else +#error "spio unimplemented for this badge generation" +#endif + +#ifdef PORTEXP_MAX7321S +#include "flow3r_bsp_max7321.h" +static flow3r_bsp_max7321_t portexps[2]; + +static esp_err_t _portexp_init(void) { + esp_err_t ret = flow3r_bsp_max7321_init(&portexps[0], flow3r_i2c_addresses.portexp[0]); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to initialize portexp 0: %s", esp_err_to_name(ret)); + return ret; + } + ret = flow3r_bsp_max7321_init(&portexps[1], flow3r_i2c_addresses.portexp[1]); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to initialize portexp 1: %s", esp_err_to_name(ret)); + return ret; + } + return ESP_OK; +} + +static uint32_t _portexp_pin(const flow3r_bsp_iopin_t *iopin) { + return iopin->pin % 8; +} + +static flow3r_bsp_max7321_t *_portexp_max(const flow3r_bsp_iopin_t *iopin) { + uint32_t ix = (iopin->pin >> 3) % 2; + return &portexps[ix]; +} + +static void _iopin_portexp_init(const flow3r_bsp_iopin_t *iopin) { + flow3r_bsp_max7321_set_pinmode_output(_portexp_max(iopin), _portexp_pin(iopin), iopin->output); +} + +static bool _iopin_portexp_get_pin(const flow3r_bsp_iopin_t *iopin) { + return flow3r_bsp_max7321_get_pin(_portexp_max(iopin), _portexp_pin(iopin)); +} + +static void _iopin_portexp_set_pin(const flow3r_bsp_iopin_t *iopin, bool on) { + flow3r_bsp_max7321_set_pin(_portexp_max(iopin), _portexp_pin(iopin), on); +} + +static esp_err_t _portexp_update(void) { + esp_err_t ret = flow3r_bsp_max7321_update(&portexps[0]); + if (ret != ESP_OK) { + return ret; + } + ret = flow3r_bsp_max7321_update(&portexps[1]); + if (ret != ESP_OK) { + return ret; + } + return ESP_OK; +} +#endif + +#ifdef PORTEXP_NONE +static esp_err_t _portexp_init(void) { return ESP_OK; } +static void _iopin_portexp_init(const flow3r_bsp_iopin_t *iopin) {} +static bool _iopin_portexp_get_pin(const flow3r_bsp_iopin_t *iopin) { return false; } +static void _iopin_portexp_set_pin(const flow3r_bsp_iopin_t *iopin, bool on) {} +static esp_err_t _portexp_update(void) { return ESP_OK; } +#endif + +static esp_err_t _iopin_esp32_init(const flow3r_bsp_iopin_t *iopin) { + gpio_config_t cfg = { + .pin_bit_mask = 1 << iopin->pin, + .mode = GPIO_MODE_INPUT, + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE + }; + if (iopin->output) { + // Untested, so unimplemented. + return ESP_ERR_NOT_SUPPORTED; + } + if (iopin->pullup) { + cfg.pull_up_en = GPIO_PULLUP_ENABLE; + } + return gpio_config(&cfg); +} + +static esp_err_t _iopin_init(const flow3r_bsp_iopin_t *iopin) { + switch (iopin->chip) { + case flow3r_bsp_iochip_esp32: + return _iopin_esp32_init(iopin); + case flow3r_bsp_iochip_portexp: + _iopin_portexp_init(iopin); + return ESP_OK; + case flow3r_bsp_iochip_dummy: + return ESP_OK; + } + return ESP_ERR_NOT_SUPPORTED; +} + +static bool _iopin_esp32_get_pin(const flow3r_bsp_iopin_t *iopin) { + return gpio_get_level(iopin->pin); +} + +static bool _iopin_get_pin(const flow3r_bsp_iopin_t *iopin) { + bool res = false; + switch (iopin->chip) { + case flow3r_bsp_iochip_esp32: + res = _iopin_esp32_get_pin(iopin); + break; + case flow3r_bsp_iochip_portexp: + res = _iopin_portexp_get_pin(iopin); + break; + case flow3r_bsp_iochip_dummy: + res = false; + } + if (iopin->invert) { + res = !res; + } + return res; +} + +static void _iopin_set_pin(const flow3r_bsp_iopin_t *iopin, bool on) { + if (iopin->invert) { + on = !on; + } + + switch (iopin->chip) { + case flow3r_bsp_iochip_esp32: + // Not implemented. + break; + case flow3r_bsp_iochip_portexp: + _iopin_portexp_set_pin(iopin, on); + break; + case flow3r_bsp_iochip_dummy: + break; + } +} + +#define INITIO(name) ret = _iopin_init(&iodef.name); if (ret != ESP_OK) { return ret; } +esp_err_t flow3r_bsp_spio_init(void) { + esp_err_t ret = _portexp_init(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Port Expander initialzation failed: %s", esp_err_to_name(ret)); + return ret; + } + INITIO(tripos_left.left); + INITIO(tripos_left.mid); + INITIO(tripos_left.right); + INITIO(tripos_right.left); + INITIO(tripos_right.mid); + INITIO(tripos_right.right); + INITIO(trrs_left.tip_badgelink_enable); + INITIO(trrs_left.ring_badgelink_enable); + INITIO(trrs_right.tip_badgelink_enable); + INITIO(trrs_right.ring_badgelink_enable); + + return _portexp_update(); +} + +esp_err_t flow3r_bsp_spio_update(void) { + return _portexp_update(); +} + +static flow3r_bsp_tripos_state_t _tripos_get(const flow3r_bsp_iodef_tripos_t *io) { + if (_iopin_get_pin(&io->mid)) { + return flow3r_bsp_tripos_mid; + } + if (_iopin_get_pin(&io->left)) { + return flow3r_bsp_tripos_left; + } + if (_iopin_get_pin(&io->right)) { + return flow3r_bsp_tripos_right; + } + return flow3r_bsp_tripos_none; +} + +flow3r_bsp_tripos_state_t flow3r_bsp_spio_left_button_get(void) { + return _tripos_get(&iodef.tripos_left); +} + +flow3r_bsp_tripos_state_t flow3r_bsp_spio_right_button_get(void) { + return _tripos_get(&iodef.tripos_right); +} + +bool flow3r_bsp_spio_charger_state_get(void) { + return _iopin_get_pin(&iodef.charger_state); +} + +bool flow3r_bsp_spio_jacksense_right_get(void) { + return _iopin_get_pin(&iodef.jacksense_right); +} + +void flow3r_bsp_spio_badgelink_left_enable(bool tip_on, bool ring_on) { + _iopin_set_pin(&iodef.trrs_left.ring_badgelink_enable, ring_on); + _iopin_set_pin(&iodef.trrs_left.tip_badgelink_enable, tip_on); +} + +void flow3r_bsp_spio_badgelink_right_enable(bool tip_on, bool ring_on) { + _iopin_set_pin(&iodef.trrs_right.ring_badgelink_enable, ring_on); + _iopin_set_pin(&iodef.trrs_right.tip_badgelink_enable, tip_on); +} \ No newline at end of file diff --git a/usermodule/mp_badge_link.c b/usermodule/mp_badge_link.c index 237bd9bf9ba29ec5ab081b9566a8853f51b2764d..bf33edcfbca31fb16a25e29920dd2a00ab4abeba 100644 --- a/usermodule/mp_badge_link.c +++ b/usermodule/mp_badge_link.c @@ -43,10 +43,6 @@ STATIC const mp_rom_map_elem_t mp_module_badge_link_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_PIN_MASK_LINE_IN), MP_ROM_INT(BADGE_LINK_PIN_MASK_LINE_IN) }, { MP_ROM_QSTR(MP_QSTR_PIN_MASK_LINE_OUT), MP_ROM_INT(BADGE_LINK_PIN_MASK_LINE_OUT) }, { MP_ROM_QSTR(MP_QSTR_PIN_MASK_ALL), MP_ROM_INT(BADGE_LINK_PIN_MASK_ALL) }, - { MP_ROM_QSTR(MP_QSTR_PIN_INDEX_LINE_IN_TIP), MP_ROM_INT(BADGE_LINK_PIN_INDEX_LINE_IN_TIP) }, - { MP_ROM_QSTR(MP_QSTR_PIN_INDEX_LINE_IN_RING), MP_ROM_INT(BADGE_LINK_PIN_INDEX_LINE_IN_RING) }, - { MP_ROM_QSTR(MP_QSTR_PIN_INDEX_LINE_OUT_TIP), MP_ROM_INT(BADGE_LINK_PIN_INDEX_LINE_OUT_TIP) }, - { MP_ROM_QSTR(MP_QSTR_PIN_INDEX_LINE_OUT_RING), MP_ROM_INT(BADGE_LINK_PIN_INDEX_LINE_OUT_RING) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_badge_link_globals, mp_module_badge_link_globals_table);