diff --git a/include/mraa_adv_func.h b/include/mraa_adv_func.h index 710aa21..b33fc36 100644 --- a/include/mraa_adv_func.h +++ b/include/mraa_adv_func.h @@ -41,7 +41,7 @@ typedef struct { mraa_result_t (*gpio_mode_replace) (mraa_gpio_context dev, mraa_gpio_mode_t mode); mraa_result_t (*gpio_mode_pre) (mraa_gpio_context dev, mraa_gpio_mode_t mode); mraa_result_t (*gpio_mode_post) (mraa_gpio_context dev, mraa_gpio_mode_t mode); - + mraa_result_t (*gpio_edge_mode_replace) (mraa_gpio_context dev, mraa_gpio_edge_t mode); mraa_result_t (*gpio_dir_replace) (mraa_gpio_context dev, mraa_gpio_dir_t dir); @@ -53,7 +53,8 @@ typedef struct { mraa_result_t (*gpio_write_pre) (mraa_gpio_context dev, int value); mraa_result_t (*gpio_write_post) (mraa_gpio_context dev, int value); mraa_result_t (*gpio_mmap_setup) (mraa_gpio_context dev, mraa_boolean_t en); - void* (*gpio_interrupt_handler_replace) (mraa_gpio_context dev); + mraa_result_t (*gpio_interrupt_handler_init_replace) (mraa_gpio_context dev); + mraa_result_t (*gpio_wait_interrupt_replace) (mraa_gpio_context dev); mraa_result_t (*i2c_init_pre) (unsigned int bus); mraa_result_t (*i2c_init_bus_replace) (mraa_i2c_context dev); diff --git a/src/gpio/gpio.c b/src/gpio/gpio.c index f67f1ab..8f387de 100644 --- a/src/gpio/gpio.c +++ b/src/gpio/gpio.c @@ -268,18 +268,21 @@ static void* mraa_gpio_interrupt_handler(void* arg) { mraa_gpio_context dev = (mraa_gpio_context) arg; - if (IS_FUNC_DEFINED(dev, gpio_interrupt_handler_replace)) - return dev->advance_func->gpio_interrupt_handler_replace(dev); - + int fp = -1; mraa_result_t ret; - // open gpio value with open(3) - char bu[MAX_SIZE]; - sprintf(bu, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin); - int fp = open(bu, O_RDONLY); - if (fp < 0) { - syslog(LOG_ERR, "gpio: failed to open gpio%d/value", dev->pin); - return NULL; + if (IS_FUNC_DEFINED(dev, gpio_interrupt_handler_init_replace)) { + if (dev->advance_func->gpio_interrupt_handler_init_replace(dev) != MRAA_SUCCESS) + return NULL; + } else { + // open gpio value with open(3) + char bu[MAX_SIZE]; + sprintf(bu, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin); + fp = open(bu, O_RDONLY); + if (fp < 0) { + syslog(LOG_ERR, "gpio: failed to open gpio%d/value", dev->pin); + return NULL; + } } #ifndef HAVE_PTHREAD_CANCEL @@ -309,11 +312,15 @@ mraa_gpio_interrupt_handler(void* arg) #endif for (;;) { - ret = mraa_gpio_wait_interrupt(dev->isr_value_fp + if (IS_FUNC_DEFINED(dev, gpio_wait_interrupt_replace)) { + ret = dev->advance_func->gpio_wait_interrupt_replace(dev); + } else { + ret = mraa_gpio_wait_interrupt(dev->isr_value_fp #ifndef HAVE_PTHREAD_CANCEL , dev->isr_control_pipe[0] #endif ); + } if (ret == MRAA_SUCCESS && !dev->isr_thread_terminating) { #ifdef HAVE_PTHREAD_CANCEL pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); @@ -391,8 +398,10 @@ mraa_gpio_interrupt_handler(void* arg) #ifdef HAVE_PTHREAD_CANCEL pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); #endif - close(dev->isr_value_fp); - dev->isr_value_fp = -1; + if (fp != -1) { + close(dev->isr_value_fp); + dev->isr_value_fp = -1; + } #if defined(SWIGJAVA) || defined(JAVACALLBACK) if(dev->isr == mraa_java_isr_callback) { diff --git a/src/usb/ftdi_ft4222.c b/src/usb/ftdi_ft4222.c index 26b6735..26f1eb6 100644 --- a/src/usb/ftdi_ft4222.c +++ b/src/usb/ftdi_ft4222.c @@ -40,7 +40,7 @@ #define PCA9672_PINS 8 #define PCA9545_BUSSES 4 #define GPIO_PORT_IO_RESET GPIO_PORT2 -#define GPIO_PORT_IO_STATUS GPIO_PORT3 +#define GPIO_PORT_IO_INT GPIO_PORT3 static FT_HANDLE ftHandleGpio = (FT_HANDLE) NULL; //GPIO Handle static FT_HANDLE ftHandleI2c = (FT_HANDLE) NULL; //I2C/SPI Handle @@ -52,6 +52,36 @@ static int numI2cGpioExpanderPins = 8; static int numI2cSwitchBusses = 4; static int currentI2cBus = 0; + +static void +mraa_ftdi_ft4222_sleep_ms(unsigned long mseconds) +{ + struct timespec sleepTime; + + sleepTime.tv_sec = mseconds / 1000; // Number of seconds + sleepTime.tv_nsec = (mseconds % 1000) * 1000000; // Convert fractional seconds to nanoseconds + + // Iterate nanosleep in a loop until the total sleep time is the original + // value of the seconds parameter + while ((nanosleep(&sleepTime, &sleepTime) != 0) && (errno == EINTR)) + ; +} + +static unsigned int +mraa_ftdi_ft4222_get_tick_count_ms() +{ + static unsigned int startTick = 0; + unsigned int ticks; + struct timeval now; + gettimeofday(&now, NULL); + ticks = now.tv_sec * 1000; + ticks += now.tv_usec / 1000; + if (startTick == 0) + startTick = ticks; + return ticks - startTick; +} + + mraa_result_t mraa_ftdi_ft4222_init() { @@ -181,7 +211,8 @@ mraa_ftdi_ft4222_i2c_read_internal(FT_HANDLE handle, uint8_t addr, uint8_t* data { uint16 bytesRead = 0; uint8 controllerStatus; - // syslog(LOG_NOTICE, "FT4222_I2CMaster_Read(%#02X, %#02X)", addr, length); + syslog(LOG_NOTICE, "FT4222_I2CMaster_Read(%#02X, %#02X)", addr, length); + mraa_ftdi_ft4222_sleep_ms(1); FT4222_STATUS ft4222Status = FT4222_I2CMaster_Read(handle, addr, data, length, &bytesRead); ft4222Status = FT4222_I2CMaster_GetStatus(ftHandleI2c, &controllerStatus); if (FT4222_OK != ft4222Status || I2CM_ERROR(controllerStatus)) { @@ -189,6 +220,7 @@ mraa_ftdi_ft4222_i2c_read_internal(FT_HANDLE handle, uint8_t addr, uint8_t* data FT4222_I2CMaster_Reset(handle); return 0; } + syslog(LOG_NOTICE, "FT4222_I2CMaster_Read completed"); return bytesRead; } @@ -197,7 +229,7 @@ mraa_ftdi_ft4222_i2c_write_internal(FT_HANDLE handle, uint8_t addr, const uint8_ { uint16 bytesWritten = 0; uint8 controllerStatus; - // syslog(LOG_NOTICE, "FT4222_I2CMaster_Write(%#02X, %#02X, %d)", addr, *data, bytesToWrite); + syslog(LOG_NOTICE, "FT4222_I2CMaster_Write(%#02X, %#02X, %d)", addr, *data, bytesToWrite); FT4222_STATUS ft4222Status = FT4222_I2CMaster_Write(handle, addr, (uint8_t*) data, bytesToWrite, &bytesWritten); ft4222Status = FT4222_I2CMaster_GetStatus(ftHandleI2c, &controllerStatus); if (FT4222_OK != ft4222Status || I2CM_ERROR(controllerStatus)) { @@ -209,6 +241,7 @@ mraa_ftdi_ft4222_i2c_write_internal(FT_HANDLE handle, uint8_t addr, const uint8_ if (bytesWritten != bytesToWrite) syslog(LOG_ERR, "FT4222_I2CMaster_Write wrote %u of %u bytes.\n", bytesWritten, bytesToWrite); + syslog(LOG_NOTICE, "FT4222_I2CMaster_Write completed"); return bytesWritten; } @@ -242,6 +275,17 @@ ftdi_ft4222_set_internal_gpio_dir(int pin, GPIO_Dir direction) return MRAA_SUCCESS; } +static mraa_result_t +ftdi_ft4222_set_internal_gpio_trigger(int pin, GPIO_Trigger trigger) +{ + FT4222_STATUS ft4222Status = FT4222_GPIO_SetInputTrigger(ftHandleGpio, pin, trigger); + if (ft4222Status == FT4222_OK) + return MRAA_SUCCESS; + else + return MRAA_ERROR_UNSPECIFIED; +} + + // Function detects known I2C switches and returns the number of busses. // On startup switch is disabled so default bus will be integrated i2c bus. static int @@ -260,6 +304,7 @@ static mraa_result_t mraa_ftdi_ft4222_i2c_select_bus(int bus) { if (bus != currentI2cBus) { + syslog(LOG_NOTICE, "mraa_ftdi_ft4222_i2c_select_bus switching to bus %d", bus); uint8_t data; if (bus == 0) data = 0; @@ -292,34 +337,6 @@ mraa_ftdi_ft4222_i2c_context_write(mraa_i2c_context dev, uint8_t* data, int leng } -static void -mraa_ftdi_ft4222_sleep_ms(unsigned long mseconds) -{ - struct timespec sleepTime; - - sleepTime.tv_sec = mseconds / 1000; // Number of seconds - sleepTime.tv_nsec = (mseconds % 1000) * 1000000; // Convert fractional seconds to nanoseconds - - // Iterate nanosleep in a loop until the total sleep time is the original - // value of the seconds parameter - while ((nanosleep(&sleepTime, &sleepTime) != 0) && (errno == EINTR)) - ; -} - -static unsigned int -mraa_ftdi_ft4222_get_tick_count_ms() -{ - static unsigned int startTick = 0; - unsigned int ticks; - struct timeval now; - gettimeofday(&now, NULL); - ticks = now.tv_sec * 1000; - ticks += now.tv_usec / 1000; - if (startTick == 0) - startTick = ticks; - return ticks - startTick; -} - /******************* I2C functions *******************/ @@ -488,13 +505,27 @@ mraa_ftdi_ft4222_gpio_init_internal_replace(mraa_gpio_context dev, int pin) static mraa_result_t mraa_ftdi_ft4222_gpio_mode_replace(mraa_gpio_context dev, mraa_gpio_mode_t mode) { - return MRAA_SUCCESS; + return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; } static mraa_result_t mraa_ftdi_ft4222_gpio_edge_mode_replace(mraa_gpio_context dev, mraa_gpio_edge_t mode) { - return MRAA_SUCCESS; + if (mraa_ftdi_ft4222_is_internal_gpio(dev->pin)) { + switch (mode) { + case MRAA_GPIO_EDGE_NONE: + return ftdi_ft4222_set_internal_gpio_trigger(dev->pin, 0); + case MRAA_GPIO_EDGE_BOTH: + return ftdi_ft4222_set_internal_gpio_trigger(dev->pin, GPIO_TRIGGER_RISING | GPIO_TRIGGER_FALLING); + case MRAA_GPIO_EDGE_RISING: + return ftdi_ft4222_set_internal_gpio_trigger(dev->pin, GPIO_TRIGGER_RISING); + case MRAA_GPIO_EDGE_FALLING: + return ftdi_ft4222_set_internal_gpio_trigger(dev->pin, GPIO_TRIGGER_FALLING); + default: + return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED; + } + } else + return MRAA_SUCCESS; } static int @@ -581,49 +612,61 @@ mraa_ftdi_ft4222_gpio_dir_replace(mraa_gpio_context dev, mraa_gpio_dir_t dir) } } - -static void* -mraa_ftdi_ft4222_gpio_interrupt_handler_replace(mraa_gpio_context dev) +static mraa_boolean_t +mraa_ftdi_ft4222_has_internal_gpio_triggered(int pin) { -#ifdef USE_FT4222_GPIO_TRIGGER - // FIXME: Use big buffer; shouldn't be more than this many events to read - GPIO_Trigger event_buf[256]; - int prev_level = mraa_ftdi_ft4222_gpio_read_replace(dev); - while (1) { - uint16 num_events = 0; - FT4222_STATUS status = FT4222_GPIO_GetTriggerStatus(ftHandleGpio, GPIO_PORT_IO_STATUS, &num_events); - if (status != FT4222_OK) - printf("FT4222_GPIO_GetTriggerStatus failed with code %d\n", status); - printf("%u: FT4222_GPIO_GetTriggerStatus Events = %d\n", mraa_ftdi_ft4222_get_tick_count_ms(), num_events); - if (num_events > 0) { - int level = mraa_ftdi_ft4222_gpio_read_replace(dev); - uint16 num_events_read; - FT4222_GPIO_ReadTriggerQueue(ftHandleGpio, GPIO_PORT_IO_STATUS, event_buf, num_events, &num_events_read); - // printf("%u: FT4222_GPIO_ReadTriggerQueue Events= %d\n", mraa_ftdi_ft4222_get_tick_count_ms(), num_events_read); - printf("%u: level = %d\n", mraa_ftdi_ft4222_get_tick_count_ms(), level); - if (level != prev_level) { - dev->isr(dev->isr_args); - prev_level = level; - } + uint16 num_events = 0; + FT4222_STATUS ft4222Status = FT4222_GPIO_GetTriggerStatus(ftHandleGpio, pin, &num_events); + if (num_events > 0) { + int i; + uint16 num_events_read; + GPIO_Trigger event; + for (i = 0; i < num_events; ++i) + FT4222_GPIO_ReadTriggerQueue(ftHandleGpio, pin, &event, 1, &num_events_read); + return TRUE; + } else + return FALSE; +} - } - mraa_ftdi_ft4222_sleep_ms(20); - // int level = mraa_ftdi_ft4222_gpio_read_replace(dev); - // printf("level = %d\n", level); +static mraa_result_t +mraa_ftdi_ft4222_gpio_interrupt_handler_init_replace(mraa_gpio_context dev) +{ + if (mraa_ftdi_ft4222_is_internal_gpio(dev->pin)) { + mraa_ftdi_ft4222_has_internal_gpio_triggered(dev->phy_pin); + } else { + ftdi_ft4222_set_internal_gpio_dir(GPIO_PORT_IO_INT, GPIO_INPUT); + ftdi_ft4222_set_internal_gpio_trigger(GPIO_PORT_IO_INT, GPIO_TRIGGER_FALLING); + mraa_ftdi_ft4222_has_internal_gpio_triggered(GPIO_PORT_IO_INT); } -#else + return MRAA_SUCCESS; +} + +static mraa_result_t +mraa_ftdi_ft4222_gpio_wait_interrupt_replace(mraa_gpio_context dev) +{ int prev_level = mraa_ftdi_ft4222_gpio_read_replace(dev); - while (1) { - int level = mraa_ftdi_ft4222_gpio_read_replace(dev); - // MRAA_GPIO_EDGE_BOTH - if (level != prev_level) { - dev->isr(dev->isr_args); - prev_level = level; + mraa_boolean_t is_internal_pin = mraa_ftdi_ft4222_is_internal_gpio(dev->pin); + mraa_boolean_t interrupt_detected = FALSE; + + // INT pin of i2c PCA9672 GPIO expander is connected to FT4222 GPIO #3 + // We use INT to detect any expander GPIO level change + while (!dev->isr_thread_terminating && !interrupt_detected) { + if (is_internal_pin) { + interrupt_detected = mraa_ftdi_ft4222_has_internal_gpio_triggered(dev->phy_pin); } - mraa_ftdi_ft4222_sleep_ms(100); + else { + mraa_boolean_t gpio_activity_detected = mraa_ftdi_ft4222_has_internal_gpio_triggered(GPIO_PORT_IO_INT); + if (gpio_activity_detected) { + int level = mraa_ftdi_ft4222_gpio_read_replace(dev); + if (level != prev_level) { + interrupt_detected = TRUE; + } + } + } + if (!interrupt_detected) + mraa_ftdi_ft4222_sleep_ms(20); } -#endif - return NULL; + return MRAA_SUCCESS; } static void @@ -653,7 +696,8 @@ mraa_ftdi_ft4222_populate_gpio_func_table(mraa_adv_func_t* func_table) func_table->gpio_dir_replace = &mraa_ftdi_ft4222_gpio_dir_replace; func_table->gpio_read_replace = &mraa_ftdi_ft4222_gpio_read_replace; func_table->gpio_write_replace = &mraa_ftdi_ft4222_gpio_write_replace; - func_table->gpio_interrupt_handler_replace = &mraa_ftdi_ft4222_gpio_interrupt_handler_replace; + func_table->gpio_interrupt_handler_init_replace = &mraa_ftdi_ft4222_gpio_interrupt_handler_init_replace; + func_table->gpio_wait_interrupt_replace = &mraa_ftdi_ft4222_gpio_wait_interrupt_replace; } @@ -752,3 +796,4 @@ mraa_ftdi_ft4222() sub_plat->adv_func = func_table; return sub_plat; } +