diff --git a/boards/addons/ginput/touch/ADS7843/ginput_lld_mouse_board_olimex_stm32_e407.h b/boards/addons/ginput/touch/ADS7843/ginput_lld_mouse_board_olimex_stm32_e407.h index f17d6e8e..af5f1282 100644 --- a/boards/addons/ginput/touch/ADS7843/ginput_lld_mouse_board_olimex_stm32_e407.h +++ b/boards/addons/ginput/touch/ADS7843/ginput_lld_mouse_board_olimex_stm32_e407.h @@ -16,6 +16,14 @@ #ifndef _GINPUT_LLD_MOUSE_BOARD_H #define _GINPUT_LLD_MOUSE_BOARD_H +// Resolution and Accuracy Settings +#define GMOUSE_ADS7843_PEN_CALIBRATE_ERROR 8 +#define GMOUSE_ADS7843_PEN_CLICK_ERROR 6 +#define GMOUSE_ADS7843_PEN_MOVE_ERROR 4 +#define GMOUSE_ADS7843_FINGER_CALIBRATE_ERROR 14 +#define GMOUSE_ADS7843_FINGER_CLICK_ERROR 18 +#define GMOUSE_ADS7843_FINGER_MOVE_ERROR 14 + static const SPIConfig spicfg = { 0, GPIOG, @@ -23,67 +31,49 @@ static const SPIConfig spicfg = { /* SPI_CR1_BR_2 |*/ SPI_CR1_BR_1 | SPI_CR1_BR_0, }; -/** - * @brief Initialise the board for the touch. - * - * @notapi - */ -static inline void init_board(void) { +// How much extra data to allocate at the end of the GMouse structure for the board's use +#define GMOUSE_ADS7843_BOARD_DATA_SIZE 0 + +static bool_t init_board(GMouse* m, unsigned driverinstance) { + (void) m; + + if (driverinstance) + return FALSE; + spiStart(&SPID2, &spicfg); + return TRUE; } -/** - * @brief Check whether the surface is currently touched - * @return TRUE if the surface is currently touched - * - * @notapi - */ -static inline bool_t getpin_pressed(void) { +static inline bool_t getpin_pressed(GMouse* m) { + (void) m; + return (!palReadPad(GPIOG, 0)); } -/** - * @brief Aquire the bus ready for readings - * - * @notapi - */ -static inline void aquire_bus(void) { + +static inline void aquire_bus(GMouse* m) { + (void) m; + spiAcquireBus(&SPID2); //TOUCHSCREEN_SPI_PROLOGUE(); palClearPad(GPIOG, 10); } -/** - * @brief Release the bus after readings - * - * @notapi - */ -static inline void release_bus(void) { +static inline void release_bus(GMouse* m) { + (void) m; + palSetPad(GPIOG, 10); spiReleaseBus(&SPID2); //TOUCHSCREEN_SPI_EPILOGUE(); } -/** - * @brief Read a value from touch controller - * @return The value read from the controller - * - * params[in] port The controller port to read. - * - * @notapi - */ -static inline uint16_t read_value(uint16_t port) { +static inline uint16_t read_value(GMouse* m, uint16_t port) { static uint8_t txbuf[3] = {0}; static uint8_t rxbuf[3] = {0}; - uint16_t ret; + (void) m; txbuf[0] = port; - spiExchange(&SPID2, 3, txbuf, rxbuf); - - ret = (rxbuf[1] << 5) | (rxbuf[2] >> 3); - - return ret; + return ((uint16_t)rxbuf[1] << 5) | (rxbuf[2] >> 3); } #endif /* _GINPUT_LLD_MOUSE_BOARD_H */ - diff --git a/boards/addons/ginput/touch/ADS7843/ginput_lld_mouse_board_st_stm32f4_discovery.h b/boards/addons/ginput/touch/ADS7843/ginput_lld_mouse_board_st_stm32f4_discovery.h index 6c3e2124..b4478d2b 100644 --- a/boards/addons/ginput/touch/ADS7843/ginput_lld_mouse_board_st_stm32f4_discovery.h +++ b/boards/addons/ginput/touch/ADS7843/ginput_lld_mouse_board_st_stm32f4_discovery.h @@ -34,41 +34,61 @@ static const SPIConfig spicfg = { /* SPI_CR1_BR_2 |*/ SPI_CR1_BR_1 | SPI_CR1_BR_0, }; -static inline void init_board(void) { +// Resolution and Accuracy Settings +#define GMOUSE_ADS7843_PEN_CALIBRATE_ERROR 8 +#define GMOUSE_ADS7843_PEN_CLICK_ERROR 6 +#define GMOUSE_ADS7843_PEN_MOVE_ERROR 4 +#define GMOUSE_ADS7843_FINGER_CALIBRATE_ERROR 14 +#define GMOUSE_ADS7843_FINGER_CLICK_ERROR 18 +#define GMOUSE_ADS7843_FINGER_MOVE_ERROR 14 + +// How much extra data to allocate at the end of the GMouse structure for the board's use +#define GMOUSE_ADS7843_BOARD_DATA_SIZE 0 + +static bool_t init_board(GMouse* m, unsigned driverinstance) { + (void) m; + + if (driverinstance) + return FALSE; + palSetPadMode(GPIOB, 13, PAL_MODE_ALTERNATE(5) ); /* SCK */ palSetPadMode(GPIOB, 14, PAL_MODE_ALTERNATE(5) ); /* MISO */ palSetPadMode(GPIOB, 15, PAL_MODE_ALTERNATE(5) ); /* MOSI */ palSetPadMode(GPIOC, 4, PAL_MODE_OUTPUT_PUSHPULL); /* CS */ spiStart(&SPID2, &spicfg); + return TRUE; } -static inline bool_t getpin_pressed(void) { +static inline bool_t getpin_pressed(GMouse* m) { + (void) m; + return (!palReadPad(GPIOC, 5)); } -static inline void aquire_bus(void) { +static inline void aquire_bus(GMouse* m) { + (void) m; + spiAcquireBus(&SPID2); palClearPad(GPIOC, 4); } -static inline void release_bus(void) { +static inline void release_bus(GMouse* m) { + (void) m; + palSetPad(GPIOC, 4); spiReleaseBus(&SPID2); } -static inline uint16_t read_value(uint16_t port) { +static inline uint16_t read_value(GMouse* m, uint16_t port) { static uint8_t txbuf[3] = {0}; static uint8_t rxbuf[3] = {0}; - uint16_t ret; + (void) m; txbuf[0] = port; - spiExchange(&SPID2, 3, txbuf, rxbuf); - ret = (rxbuf[1] << 5) | (rxbuf[2] >> 3); - - return ret; + return ((uint16_t)rxbuf[1] << 5) | (rxbuf[2] >> 3); } #endif /* _GINPUT_LLD_MOUSE_BOARD_H */ diff --git a/boards/addons/ginput/touch/MCU/ginput_lld_mouse_board_olimex_pic32mx_lcd.h b/boards/addons/ginput/touch/MCU/ginput_lld_mouse_board_olimex_pic32mx_lcd.h index 87e2a93c..391eba9c 100644 --- a/boards/addons/ginput/touch/MCU/ginput_lld_mouse_board_olimex_pic32mx_lcd.h +++ b/boards/addons/ginput/touch/MCU/ginput_lld_mouse_board_olimex_pic32mx_lcd.h @@ -16,6 +16,24 @@ #ifndef _GINPUT_LLD_MOUSE_BOARD_H #define _GINPUT_LLD_MOUSE_BOARD_H +#define ADC_MAX 1023 + +// Resolution and Accuracy Settings +#define GMOUSE_MCU_PEN_CALIBRATE_ERROR 8 +#define GMOUSE_MCU_PEN_CLICK_ERROR 6 +#define GMOUSE_MCU_PEN_MOVE_ERROR 4 +#define GMOUSE_MCU_FINGER_CALIBRATE_ERROR 14 +#define GMOUSE_MCU_FINGER_CLICK_ERROR 18 +#define GMOUSE_MCU_FINGER_MOVE_ERROR 14 + +#define GMOUSE_MCU_Z_MIN 0 // The minimum Z reading +#define GMOUSE_MCU_Z_MAX ADC_MAX // The maximum Z reading +#define GMOUSE_MCU_Z_TOUCHON 60 // Values between this and Z_MAX are definitely pressed +#define GMOUSE_MCU_Z_TOUCHOFF 30 // Values between this and Z_MIN are definitely not pressed + +// How much extra data to allocate at the end of the GMouse structure for the board's use +#define GMOUSE_MCU_BOARD_DATA_SIZE 0 + static const ADCConfig ADCC = { .vref = ADC_VREF_CFG_AVDD_AVSS, .stime = 15, @@ -29,10 +47,6 @@ static struct ADCDriver ADCD; #define XPOS 12 // L #define YPOS 11 // D -#define ADC_MAX 1023 - -#define TOUCH_THRESHOULD 50 - static const ADCConversionGroup ADC_X_CG = { .circular = FALSE, .num_channels = 1, @@ -45,104 +59,59 @@ static const ADCConversionGroup ADC_Y_CG = { .channels = 1 << YPOS, }; -/** - * @brief Initialise the board for the touch. - * - * @notapi - */ -static inline void init_board(void) { - adcObjectInit(&ADCD); - adcStart(&ADCD, &ADCC); +static bool_t init_board(GMouse *m, unsigned driverinstance) { + (void) m; + + if (driverinstance) + return FALSE; + + adcObjectInit(&ADCD); + adcStart(&ADCD, &ADCC); + return TRUE; } -/** - * @brief Check whether the surface is currently touched - * @return TRUE if the surface is currently touched - * - * @notapi - */ -static inline bool_t getpin_pressed(void) { - adcsample_t samples[2] = {0, }; +static bool_t read_xyz(GMouse *m, GMouseReading *prd) { + adcsample_t samples[2]; - // Set X+ to ground - palSetPadMode(IOPORTB, XPOS, PAL_MODE_OUTPUT); - palClearPad(IOPORTB, XPOS); + prd->buttons = 0; - // Set Y- to VCC - palSetPadMode(IOPORTB, YNEG, PAL_MODE_OUTPUT); - palSetPad(IOPORTB, YNEG); + // Read the z value first. + // Set X+ to ground and Y- to VCC + palSetPadMode(IOPORTB, XPOS, PAL_MODE_OUTPUT); + palClearPad(IOPORTB, XPOS); + palSetPadMode(IOPORTB, YNEG, PAL_MODE_OUTPUT); + palSetPad(IOPORTB, YNEG); + palSetPadMode(IOPORTB, XNEG, PAL_MODE_INPUT_ANALOG); + palSetPadMode(IOPORTB, YPOS, PAL_MODE_INPUT_ANALOG); + adcConvert(&ADCD, &ADC_X_CG, &samples[0], 1); + adcConvert(&ADCD, &ADC_Y_CG, &samples[1], 1); + pdr->z = ADC_MAX - (samples[1] - samples[0]); - palSetPadMode(IOPORTB, XNEG, PAL_MODE_INPUT_ANALOG); - palSetPadMode(IOPORTB, YPOS, PAL_MODE_INPUT_ANALOG); + // Shortcut - no need to read X or Y if the touch is off. + if (pdr->z < GMOUSE_MCU_Z_TOUCHON) + return TRUE; - adcConvert(&ADCD, &ADC_X_CG, &samples[0], 1); - adcConvert(&ADCD, &ADC_Y_CG, &samples[1], 1); + // Read X + palSetPadMode(IOPORTB, XPOS, PAL_MODE_OUTPUT); + palSetPad(IOPORTB, XPOS); + palSetPadMode(IOPORTB, XNEG, PAL_MODE_OUTPUT); + palClearPad(IOPORTB, XNEG); + palSetPadMode(IOPORTB, YNEG, PAL_MODE_INPUT); + palSetPadMode(IOPORTB, YPOS, PAL_MODE_INPUT_ANALOG); + adcConvert(&ADCD, &ADC_Y_CG, &samples[0], 1); + pdr->x = ADC_MAX - samples[0]; - return (ADC_MAX - (samples[1] - samples[0])) > TOUCH_THRESHOULD; -} + // Read Y + palSetPadMode(IOPORTB, YNEG, PAL_MODE_OUTPUT); + palClearPad(IOPORTB, YNEG); + palSetPadMode(IOPORTB, YPOS, PAL_MODE_OUTPUT); + palSetPad(IOPORTB, YPOS); + palSetPadMode(IOPORTB, XPOS, PAL_MODE_INPUT); + palSetPadMode(IOPORTB, XNEG, PAL_MODE_INPUT_ANALOG); + adcConvert(&ADCD, &ADC_X_CG, &samples[0], 1); + pdr->y = ADC_MAX - samples[0]; -/** - * @brief Aquire the bus ready for readings - * - * @notapi - */ -static inline void aquire_bus(void) { -} - -/** - * @brief Release the bus after readings - * - * @notapi - */ -static inline void release_bus(void) { -} - -/** - * @brief Read an x value from touch controller - * @return The value read from the controller - * - * @notapi - */ -static inline uint16_t read_x_value(void) { - adcsample_t sample; - - palSetPadMode(IOPORTB, XPOS, PAL_MODE_OUTPUT); - palSetPad(IOPORTB, XPOS); - - palSetPadMode(IOPORTB, XNEG, PAL_MODE_OUTPUT); - palClearPad(IOPORTB, XNEG); - - palSetPadMode(IOPORTB, YNEG, PAL_MODE_INPUT); - - palSetPadMode(IOPORTB, YPOS, PAL_MODE_INPUT_ANALOG); - - adcConvert(&ADCD, &ADC_Y_CG, &sample, 1); - - return ADC_MAX - sample; -} - -/** - * @brief Read an y value from touch controller - * @return The value read from the controller - * - * @notapi - */ -static inline uint16_t read_y_value(void) { - adcsample_t sample; - - palSetPadMode(IOPORTB, YNEG, PAL_MODE_OUTPUT); - palClearPad(IOPORTB, YNEG); - - palSetPadMode(IOPORTB, YPOS, PAL_MODE_OUTPUT); - palSetPad(IOPORTB, YPOS); - - palSetPadMode(IOPORTB, XPOS, PAL_MODE_INPUT); - - palSetPadMode(IOPORTB, XNEG, PAL_MODE_INPUT_ANALOG); - - adcConvert(&ADCD, &ADC_X_CG, &sample, 1); - - return ADC_MAX - sample; + return TRUE; } #endif /* _GINPUT_LLD_MOUSE_BOARD_H */ diff --git a/boards/base/Embest-STM32-DMSTF4BB/ginput_lld_mouse_board.h b/boards/base/Embest-STM32-DMSTF4BB/ginput_lld_mouse_board.h deleted file mode 100644 index d525e268..00000000 --- a/boards/base/Embest-STM32-DMSTF4BB/ginput_lld_mouse_board.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _GINPUT_LLD_MOUSE_BOARD_H -#define _GINPUT_LLD_MOUSE_BOARD_H - -static const I2CConfig i2ccfg = { - OPMODE_I2C, - 400000, - FAST_DUTY_CYCLE_2, -}; - -static void init_board(void) -{ - palSetPadMode(GPIOC, 13, PAL_MODE_INPUT | PAL_STM32_PUDR_FLOATING); /* TP IRQ */ - palSetPadMode(GPIOB, 8, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); /* SCL */ - palSetPadMode(GPIOB, 9, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); /* SDA */ - - i2cStart(&I2CD1, &i2ccfg); -} - -static inline bool_t getpin_irq(void) -{ - return (!(palReadPad(GPIOC, 13))); -} - -static void write_reg(uint8_t reg, uint8_t n, uint16_t val) -{ - uint8_t txbuf[3]; - - i2cAcquireBus(&I2CD1); - - txbuf[0] = reg; - - if (n == 1) { - txbuf[1] = val; - i2cMasterTransmitTimeout(&I2CD1, STMPE811_ADDR, txbuf, 2, 0, 0, MS2ST(STMPE811_TIMEOUT)); - } else if (n == 2) { - txbuf[1] = ((val & 0xFF00) >> 8); - txbuf[2] = (val & 0x00FF); - i2cMasterTransmitTimeout(&I2CD1, STMPE811_ADDR, txbuf, 3, 0, 0, MS2ST(STMPE811_TIMEOUT)); - } - - i2cReleaseBus(&I2CD1); -} - -static uint16_t read_reg(uint8_t reg, uint8_t n) -{ - uint8_t txbuf[1], rxbuf[2]; - uint16_t ret; - - rxbuf[0] = 0; - rxbuf[1] = 0; - - i2cAcquireBus(&I2CD1); - - txbuf[0] = reg; - i2cMasterTransmitTimeout(&I2CD1, STMPE811_ADDR, txbuf, 1, rxbuf, n, MS2ST(STMPE811_TIMEOUT)); - - if (n == 1) { - ret = rxbuf[0]; - } else if (n == 2) { - ret = ((rxbuf[0] << 8) | (rxbuf[1] & 0xFF)); - } - - i2cReleaseBus(&I2CD1); - - return ret; -} - -static void read_reg_n(uint8_t reg, uint8_t n, uint8_t *rxbuf) -{ - uint8_t txbuf[1]; - - i2cAcquireBus(&I2CD1); - - txbuf[0] = reg; - i2cMasterTransmitTimeout(&I2CD1, STMPE811_ADDR, txbuf, 1, rxbuf, n, MS2ST(STMPE811_TIMEOUT)); - - i2cReleaseBus(&I2CD1); -} - -#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ - diff --git a/boards/base/Embest-STM32-DMSTF4BB/ginput_lld_mouse_config.h b/boards/base/Embest-STM32-DMSTF4BB/ginput_lld_mouse_config.h deleted file mode 100644 index f3a89208..00000000 --- a/boards/base/Embest-STM32-DMSTF4BB/ginput_lld_mouse_config.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _LLD_GINPUT_MOUSE_CONFIG_H -#define _LLD_GINPUT_MOUSE_CONFIG_H - -#define GINPUT_MOUSE_EVENT_TYPE GEVENT_TOUCH -#define GINPUT_MOUSE_NEED_CALIBRATION TRUE -#define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE -#define GINPUT_MOUSE_MAX_CALIBRATION_ERROR 12 -#define GINPUT_MOUSE_READ_CYCLES 4 -#define GINPUT_MOUSE_POLL_PERIOD 3 -#define GINPUT_MOUSE_MAX_CLICK_JITTER 2 -#define GINPUT_MOUSE_MAX_MOVE_JITTER 2 -#define GINPUT_MOUSE_CLICK_TIME 500 - -#endif /* _LLD_GINPUT_MOUSE_CONFIG_H */ - diff --git a/boards/base/Embest-STM32-DMSTF4BB/gmouse_lld_STMPE811_board.h b/boards/base/Embest-STM32-DMSTF4BB/gmouse_lld_STMPE811_board.h new file mode 100644 index 00000000..bbb17010 --- /dev/null +++ b/boards/base/Embest-STM32-DMSTF4BB/gmouse_lld_STMPE811_board.h @@ -0,0 +1,119 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _GINPUT_LLD_MOUSE_BOARD_H +#define _GINPUT_LLD_MOUSE_BOARD_H + +// Resolution and Accuracy Settings +#define GMOUSE_STMPE811_PEN_CALIBRATE_ERROR 8 +#define GMOUSE_STMPE811_PEN_CLICK_ERROR 6 +#define GMOUSE_STMPE811_PEN_MOVE_ERROR 4 +#define GMOUSE_STMPE811_FINGER_CALIBRATE_ERROR 14 +#define GMOUSE_STMPE811_FINGER_CLICK_ERROR 18 +#define GMOUSE_STMPE811_FINGER_MOVE_ERROR 14 + +// How much extra data to allocate at the end of the GMouse structure for the board's use +#define GMOUSE_STMPE811_BOARD_DATA_SIZE 0 + +// Options - Leave these commented to make it user configurable in the gfxconf.h +//#define GMOUSE_STMPE811_READ_PRESSURE FALSE +//#define GMOUSE_STMPE811_SELF_CALIBRATE FALSE +//#define GMOUSE_STMPE811_TEST_MODE FALSE + +// If TRUE this board has the STMPE811 IRQ pin connected to a GPIO. +// Note: Although this board has such a pin its reliability has not been tested on this board!!!!! +#define GMOUSE_STMPE811_GPIO_IRQPIN FALSE + +// If TRUE this is a really slow CPU and we should always clear the FIFO between reads. +#define GMOUSE_STMPE811_SLOW_CPU FALSE + +// Slave address +#define STMPE811_ADDR (0x82 >> 1) + +// Maximum timeout +#define STMPE811_TIMEOUT 0x3000 + +static const I2CConfig i2ccfg = { + OPMODE_I2C, + 400000, + FAST_DUTY_CYCLE_2, +}; + +static bool_t init_board(GMouse* m, unsigned driverinstance) { + (void) m; + + // This board only supports one touch panel + if (driverinstance) + return FALSE; + + palSetPadMode(GPIOC, 13, PAL_MODE_INPUT | PAL_STM32_PUDR_FLOATING); /* TP IRQ */ + palSetPadMode(GPIOB, 8, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); /* SCL */ + palSetPadMode(GPIOB, 9, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); /* SDA */ + + i2cStart(&I2CD1, &i2ccfg); + + return TRUE; +} + +#if GMOUSE_STMPE811_GPIO_IRQPIN + static bool_t getpin_irq(GMouse* m) { + (void) m; + + return !palReadPad(GPIOC, 13); + } +#endif + +static inline void aquire_bus(GMouse* m) { + (void) m; + +} + +static inline void release_bus(GMouse* m) { + (void) m; + +} + +static void write_reg(GMouse* m, uint8_t reg, uint8_t val) { + uint8_t txbuf[2]; + (void) m; + + txbuf[0] = reg; + txbuf[1] = val; + + i2cAcquireBus(&I2CD1); + i2cMasterTransmitTimeout(&I2CD1, STMPE811_ADDR, txbuf, 2, 0, 0, MS2ST(STMPE811_TIMEOUT)); + i2cReleaseBus(&I2CD1); +} + +static uint8_t read_byte(GMouse* m, uint8_t reg) { + uint8_t rxbuf[1]; + (void) m; + + rxbuf[0] = 0; + + i2cAcquireBus(&I2CD1); + i2cMasterTransmitTimeout(&I2CD1, STMPE811_ADDR, ®, 1, rxbuf, 1, MS2ST(STMPE811_TIMEOUT)); + i2cReleaseBus(&I2CD1); + + return rxbuf[0]; +} + +static uint16_t read_word(GMouse* m, uint8_t reg) { + uint8_t rxbuf[2]; + (void) m; + + rxbuf[0] = 0; + rxbuf[1] = 0; + + i2cAcquireBus(&I2CD1); + i2cMasterTransmitTimeout(&I2CD1, STMPE811_ADDR, ®, 1, rxbuf, 2, MS2ST(STMPE811_TIMEOUT)); + i2cReleaseBus(&I2CD1); + + return (((uint16_t)rxbuf[0]) << 8) | rxbuf[1]; +} + +#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ diff --git a/boards/base/FireBull-STM32F103-FB/ginput_lld_mouse_board.h b/boards/base/FireBull-STM32F103-FB/ginput_lld_mouse_board.h deleted file mode 100644 index 6ca1a897..00000000 --- a/boards/base/FireBull-STM32F103-FB/ginput_lld_mouse_board.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _GINPUT_LLD_MOUSE_BOARD_H -#define _GINPUT_LLD_MOUSE_BOARD_H - -static const SPIConfig spicfg = { - 0, - GPIOC, - 6, - /* SPI_CR1_BR_2 |*/ SPI_CR1_BR_1 | SPI_CR1_BR_0, -}; - -static inline void init_board(void) -{ - spiStart(&SPID1, &spicfg); -} - -static inline bool_t getpin_pressed(void) -{ - return (!palReadPad(GPIOC, 4)); -} - -static inline void aquire_bus(void) -{ - spiAcquireBus(&SPID1); - palClearPad(GPIOC, 6); -} - -static inline void release_bus(void) -{ - palSetPad(GPIOC, 6); - spiReleaseBus(&SPID1); -} - -static inline uint16_t read_value(uint16_t port) -{ - static uint8_t txbuf[3] = {0}; - static uint8_t rxbuf[3] = {0}; - uint16_t ret; - - txbuf[0] = port; - - spiExchange(&SPID1, 3, txbuf, rxbuf); - - ret = (rxbuf[1] << 5) | (rxbuf[2] >> 3); - - return ret; -} - -#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ - diff --git a/boards/base/FireBull-STM32F103-FB/ginput_lld_mouse_config.h b/boards/base/FireBull-STM32F103-FB/ginput_lld_mouse_config.h deleted file mode 100644 index f3a89208..00000000 --- a/boards/base/FireBull-STM32F103-FB/ginput_lld_mouse_config.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _LLD_GINPUT_MOUSE_CONFIG_H -#define _LLD_GINPUT_MOUSE_CONFIG_H - -#define GINPUT_MOUSE_EVENT_TYPE GEVENT_TOUCH -#define GINPUT_MOUSE_NEED_CALIBRATION TRUE -#define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE -#define GINPUT_MOUSE_MAX_CALIBRATION_ERROR 12 -#define GINPUT_MOUSE_READ_CYCLES 4 -#define GINPUT_MOUSE_POLL_PERIOD 3 -#define GINPUT_MOUSE_MAX_CLICK_JITTER 2 -#define GINPUT_MOUSE_MAX_MOVE_JITTER 2 -#define GINPUT_MOUSE_CLICK_TIME 500 - -#endif /* _LLD_GINPUT_MOUSE_CONFIG_H */ - diff --git a/boards/base/FireBull-STM32F103-FB/gmouse_lld_ADS7843_board.h b/boards/base/FireBull-STM32F103-FB/gmouse_lld_ADS7843_board.h new file mode 100644 index 00000000..b202dd85 --- /dev/null +++ b/boards/base/FireBull-STM32F103-FB/gmouse_lld_ADS7843_board.h @@ -0,0 +1,86 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _GINPUT_LLD_MOUSE_BOARD_H +#define _GINPUT_LLD_MOUSE_BOARD_H + +// Resolution and Accuracy Settings +#define GMOUSE_ADS7843_PEN_CALIBRATE_ERROR 2 +#define GMOUSE_ADS7843_PEN_CLICK_ERROR 2 +#define GMOUSE_ADS7843_PEN_MOVE_ERROR 2 +#define GMOUSE_ADS7843_FINGER_CALIBRATE_ERROR 20 +#define GMOUSE_ADS7843_FINGER_CLICK_ERROR 4 +#define GMOUSE_ADS7843_FINGER_MOVE_ERROR 4 + +// How much extra data to allocate at the end of the GMouse structure for the board's use +#define GMOUSE_ADS7843_BOARD_DATA_SIZE 0 + +static const SPIConfig spicfg = { + 0, + GPIOC, + 6, + /* SPI_CR1_BR_2 |*/ SPI_CR1_BR_1 | SPI_CR1_BR_0, +}; + +static bool_t init_board(GMouse* m, unsigned driverinstance) +{ + (void)m; + + // Only one touch interface on this board + if (driverinstance) + return FALSE; + + // Set the GPIO modes + palSetPadMode(GPIOC, 4, PAL_MODE_INPUT_PULLUP); + + // Start the SPI peripheral + spiStart(&SPID1, &spicfg); + + return TRUE; +} + +static inline bool_t getpin_pressed(GMouse* m) +{ + (void) m; + + return (!palReadPad(GPIOC, 4)); +} + +static inline void aquire_bus(GMouse* m) +{ + (void) m; + + spiAcquireBus(&SPID1); + palClearPad(GPIOC, 6); +} + +static inline void release_bus(GMouse* m) +{ + (void) m; + + palSetPad(GPIOC, 6); + spiReleaseBus(&SPID1); +} + +static inline uint16_t read_value(GMouse* m, uint16_t port) +{ + static uint8_t txbuf[3] = {0}; + static uint8_t rxbuf[3] = {0}; + uint16_t ret; + (void) m; + + txbuf[0] = port; + + spiExchange(&SPID1, 3, txbuf, rxbuf); + + ret = (rxbuf[1] << 5) | (rxbuf[2] >> 3); + + return ret; +} + +#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ + diff --git a/boards/base/Marlin/ginput_lld_mouse_board.h b/boards/base/Marlin/ginput_lld_mouse_board.h deleted file mode 100644 index d787d224..00000000 --- a/boards/base/Marlin/ginput_lld_mouse_board.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/ginput/touch/FT5x06/ginput_lld_mouse_board_marlin.h - * @brief GINPUT Touch low level driver source for the FT5x06. - * - * @defgroup Mouse Mouse - * @ingroup GINPUT - * @{ - */ - -#ifndef _GINPUT_LLD_MOUSE_BOARD_H -#define _GINPUT_LLD_MOUSE_BOARD_H - -/* I2C interface #2 - Touchscreen controller */ -static const I2CConfig i2ccfg2 = { - OPMODE_I2C, - 400000, - FAST_DUTY_CYCLE_2, -}; - -/** - * @brief Initialise the board for the touch. - * - * @notapi - */ -static void init_board(void) { - -} - - -/** - * @brief Write a value into a certain register - * - * @param[in] reg The register address - * @param[in] n The amount of bytes (one or two) - * @param[in] val The value - * - * @notapi - */ -static void write_reg(uint8_t reg, uint8_t n, uint16_t val) { - uint8_t txbuf[3]; - - i2cAcquireBus(&I2CD2); - - txbuf[0] = reg; - - if (n == 1) { - txbuf[1] = val; - i2cMasterTransmitTimeout(&I2CD2, FT5x06_ADDR, txbuf, 2, 0, 0, MS2ST(FT5x06_TIMEOUT)); - } else if (n == 2) { - txbuf[1] = ((val & 0xFF00) >> 8); - txbuf[2] = (val & 0x00FF); - i2cMasterTransmitTimeout(&I2CD2, FT5x06_ADDR, txbuf, 3, 0, 0, MS2ST(FT5x06_TIMEOUT)); - } - - i2cReleaseBus(&I2CD2); -} - -/** - * @brief Read the value of a certain register - * - * @param[in] reg The register address - * @param[in] n The amount of bytes (one or two) - * - * @return Data read from device (one byte or two depending on n param) - * - * @notapi - */ -static uint16_t read_reg(uint8_t reg, uint8_t n) { - uint8_t txbuf[1], rxbuf[2]; - uint16_t ret; - - rxbuf[0] = 0; - rxbuf[1] = 0; - - i2cAcquireBus(&I2CD2); - - txbuf[0] = reg; - i2cMasterTransmitTimeout(&I2CD2, FT5x06_ADDR, txbuf, 1, rxbuf, n, MS2ST(FT5x06_TIMEOUT)); - - if (n == 1) { - ret = rxbuf[0]; - } else if (n == 2) { - ret = ((rxbuf[0] << 8) | (rxbuf[1] & 0xFF)); - } - - i2cReleaseBus(&I2CD2); - - return ret; -} - -static void read_reg_n(uint8_t reg, uint8_t n, uint8_t *rxbuf) { - uint8_t txbuf[1]; - - i2cAcquireBus(&I2CD2); - - txbuf[0] = reg; - i2cMasterTransmitTimeout(&I2CD2, FT5x06_ADDR, txbuf, 1, rxbuf, n, MS2ST(FT5x06_TIMEOUT)); - - i2cReleaseBus(&I2CD2); -} - -#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ -/** @} */ - diff --git a/boards/base/Marlin/ginput_lld_mouse_config.h b/boards/base/Marlin/ginput_lld_mouse_config.h deleted file mode 100644 index 57d3f135..00000000 --- a/boards/base/Marlin/ginput_lld_mouse_config.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/ginput/touch/STMPE811/ginput_lld_mouse_config.h - * @brief GINPUT LLD header file for mouse/touch driver. - * - * @defgroup Mouse Mouse - * @ingroup GINPUT - * - * @{ - */ - -#ifndef _LLD_GINPUT_MOUSE_CONFIG_H -#define _LLD_GINPUT_MOUSE_CONFIG_H - -#define GINPUT_MOUSE_EVENT_TYPE GEVENT_TOUCH -#define GINPUT_MOUSE_NEED_CALIBRATION TRUE -#define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE -#define GINPUT_MOUSE_MAX_CALIBRATION_ERROR 15 -#define GINPUT_MOUSE_READ_CYCLES 1 -#define GINPUT_MOUSE_POLL_PERIOD 25 -#define GINPUT_MOUSE_MAX_CLICK_JITTER 10 -#define GINPUT_MOUSE_MAX_MOVE_JITTER 5 -#define GINPUT_MOUSE_CLICK_TIME 450 - -#endif /* _LLD_GINPUT_MOUSE_CONFIG_H */ -/** @} */ diff --git a/boards/base/Marlin/gmouse_lld_FT5x06_board.h b/boards/base/Marlin/gmouse_lld_FT5x06_board.h new file mode 100644 index 00000000..ac961d0e --- /dev/null +++ b/boards/base/Marlin/gmouse_lld_FT5x06_board.h @@ -0,0 +1,93 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _GINPUT_LLD_MOUSE_BOARD_H +#define _GINPUT_LLD_MOUSE_BOARD_H + +// Resolution and Accuracy Settings +#define GMOUSE_FT5x06_PEN_CALIBRATE_ERROR 8 +#define GMOUSE_FT5x06_PEN_CLICK_ERROR 6 +#define GMOUSE_FT5x06_PEN_MOVE_ERROR 4 +#define GMOUSE_FT5x06_FINGER_CALIBRATE_ERROR 14 +#define GMOUSE_FT5x06_FINGER_CLICK_ERROR 18 +#define GMOUSE_FT5x06_FINGER_MOVE_ERROR 14 + +// How much extra data to allocate at the end of the GMouse structure for the board's use +#define GMOUSE_FT5x06_BOARD_DATA_SIZE 0 + +// Set this to TRUE if you want self-calibration. +// NOTE: This is not as accurate as real calibration. +// It requires the orientation of the touch panel to match the display. +// It requires the active area of the touch panel to exactly match the display size. +#define GMOUSE_FT5x06_SELF_CALIBRATE FALSE + +/* I2C interface #2 - Touchscreen controller */ +static const I2CConfig i2ccfg2 = { + OPMODE_I2C, + 400000, + FAST_DUTY_CYCLE_2, +}; + +static bool_t init_board(GMouse* m, unsigned driverinstance) { + (void) m; + + // We only support one of these on this board + if (driverinstance) + return FALSE; + return TRUE; +} + +static inline void aquire_bus(GMouse* m) { + (void) m; + +} + +static inline void release_bus(GMouse* m) { + (void) m; + +} + +static void write_reg(GMouse* m, uint8_t reg, uint8_t val) { + uint8_t txbuf[2]; + (void) m; + + txbuf[0] = reg; + txbuf[1] = val; + + i2cAcquireBus(&I2CD2); + i2cMasterTransmitTimeout(&I2CD2, FT5x06_ADDR, txbuf, 2, 0, 0, MS2ST(FT5x06_TIMEOUT)); + i2cReleaseBus(&I2CD2); +} + +static uint8_t read_byte(GMouse* m, uint8_t reg) { + uint8_t rxbuf[1]; + (void) m; + + rxbuf[0] = 0; + + i2cAcquireBus(&I2CD2); + i2cMasterTransmitTimeout(&I2CD2, FT5x06_ADDR, ®, 1, rxbuf, 1, MS2ST(FT5x06_TIMEOUT)); + i2cReleaseBus(&I2CD2); + + return rxbuf[0]; +} + +static uint16_t read_word(GMouse* m, uint8_t reg) { + uint8_t rxbuf[2]; + (void) m; + + rxbuf[0] = 0; + rxbuf[1] = 0; + + i2cAcquireBus(&I2CD2); + i2cMasterTransmitTimeout(&I2CD2, FT5x06_ADDR, ®, 1, rxbuf, 2, MS2ST(FT5x06_TIMEOUT)); + i2cReleaseBus(&I2CD2); + + return (((uint16_t)rxbuf[0]) << 8) | rxbuf[1]; +} + +#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/ginput_lld_mouse_board.h b/boards/base/Mikromedia-STM32-M4-ILI9341/ginput_lld_mouse_board.h deleted file mode 100644 index 75db2c62..00000000 --- a/boards/base/Mikromedia-STM32-M4-ILI9341/ginput_lld_mouse_board.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _GINPUT_LLD_MOUSE_BOARD_H -#define _GINPUT_LLD_MOUSE_BOARD_H - -#define ADC_NUM_CHANNELS 2 -#define ADC_BUF_DEPTH 1 - -static const ADCConversionGroup adcgrpcfg = { - FALSE, - ADC_NUM_CHANNELS, - 0, - 0, - /* HW dependent part.*/ - 0, - ADC_CR2_SWSTART, - 0, - 0, - ADC_SQR1_NUM_CH(ADC_NUM_CHANNELS), - 0, - ADC_SQR3_SQ2_N(ADC_CHANNEL_IN8) | ADC_SQR3_SQ1_N(ADC_CHANNEL_IN9) -}; - -static inline void init_board(void) { - adcStart(&ADCD1, 0); -} - -static inline void aquire_bus(void) { - -} - -static inline void release_bus(void) { -} - -static inline void setup_x(void) { - palSetPad(GPIOB, GPIOB_DRIVEA); - palClearPad(GPIOB, GPIOB_DRIVEB); - chThdSleepMilliseconds(2); -} - -static inline void setup_y(void) { - palClearPad(GPIOB, GPIOB_DRIVEA); - palSetPad(GPIOB, GPIOB_DRIVEB); - chThdSleepMilliseconds(2); -} - -static inline void setup_z(void) { - palClearPad(GPIOB, GPIOB_DRIVEA); - palClearPad(GPIOB, GPIOB_DRIVEB); - chThdSleepMilliseconds(2); -} - -static inline uint16_t read_x(void) { - adcsample_t samples[ADC_NUM_CHANNELS * ADC_BUF_DEPTH]; - - adcConvert(&ADCD1, &adcgrpcfg, samples, ADC_BUF_DEPTH); - return samples[1]; -} - -static inline uint16_t read_y(void) { - adcsample_t samples[ADC_NUM_CHANNELS * ADC_BUF_DEPTH]; - - adcConvert(&ADCD1, &adcgrpcfg, samples, ADC_BUF_DEPTH); - return samples[0]; -} - -static inline uint16_t read_z(void) { - adcsample_t samples[ADC_NUM_CHANNELS * ADC_BUF_DEPTH]; - - adcConvert(&ADCD1, &adcgrpcfg, samples, ADC_BUF_DEPTH); - // z will go from ~200 to ~4000 when pressed - // auto range this back to 0 to 100 - if (samples[0] > 4000) - return 100; - if (samples[0] < 400) - return 0; - return (samples[0] - 400) / ((4000-400)/100); -} - -#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/ginput_lld_mouse_config.h b/boards/base/Mikromedia-STM32-M4-ILI9341/ginput_lld_mouse_config.h deleted file mode 100644 index 328e6337..00000000 --- a/boards/base/Mikromedia-STM32-M4-ILI9341/ginput_lld_mouse_config.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _LLD_GINPUT_MOUSE_CONFIG_H -#define _LLD_GINPUT_MOUSE_CONFIG_H - -#define GINPUT_MOUSE_EVENT_TYPE GEVENT_TOUCH -#define GINPUT_MOUSE_NEED_CALIBRATION TRUE -#define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE -#define GINPUT_MOUSE_MAX_CALIBRATION_ERROR 12 -#define GINPUT_MOUSE_READ_CYCLES 1 -#define GINPUT_MOUSE_POLL_PERIOD 25 -#define GINPUT_MOUSE_MAX_CLICK_JITTER 2 -#define GINPUT_MOUSE_MAX_MOVE_JITTER 2 -#define GINPUT_MOUSE_CLICK_TIME 500 - -#endif /* _LLD_GINPUT_MOUSE_CONFIG_H */ diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/gmouse_lld_MCU_board.h b/boards/base/Mikromedia-STM32-M4-ILI9341/gmouse_lld_MCU_board.h new file mode 100644 index 00000000..bad8b9ab --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/gmouse_lld_MCU_board.h @@ -0,0 +1,95 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _LLD_GMOUSE_MCU_BOARD_H +#define _LLD_GMOUSE_MCU_BOARD_H + +// Resolution and Accuracy Settings +#define GMOUSE_MCU_PEN_CALIBRATE_ERROR 8 +#define GMOUSE_MCU_PEN_CLICK_ERROR 6 +#define GMOUSE_MCU_PEN_MOVE_ERROR 4 +#define GMOUSE_MCU_FINGER_CALIBRATE_ERROR 14 +#define GMOUSE_MCU_FINGER_CLICK_ERROR 18 +#define GMOUSE_MCU_FINGER_MOVE_ERROR 14 +#define GMOUSE_MCU_Z_MIN 0 +#define GMOUSE_MCU_Z_MAX 4095 +#define GMOUSE_MCU_Z_TOUCHON 3090 +#define GMOUSE_MCU_Z_TOUCHOFF 400 + +// How much extra data to allocate at the end of the GMouse structure for the board's use +#define GMOUSE_MCU_BOARD_DATA_SIZE 0 + +#define ADC_NUM_CHANNELS 2 +#define ADC_BUF_DEPTH 1 + +static const ADCConversionGroup adcgrpcfg = { + FALSE, + ADC_NUM_CHANNELS, + 0, + 0, + /* HW dependent part.*/ + 0, + ADC_CR2_SWSTART, + 0, + 0, + ADC_SQR1_NUM_CH(ADC_NUM_CHANNELS), + 0, + ADC_SQR3_SQ2_N(ADC_CHANNEL_IN8) | ADC_SQR3_SQ1_N(ADC_CHANNEL_IN9) +}; + +static bool_t init_board(GMouse *m, unsigned driverinstance) { + (void) m; + + // Only one touch interface on this board + if (driverinstance) + return FALSE; + + adcStart(&ADCD1, 0); + + // Set up for reading Z + palClearPad(GPIOB, GPIOB_DRIVEA); + palClearPad(GPIOB, GPIOB_DRIVEB); + chThdSleepMilliseconds(1); // Settling time + return TRUE; +} + +static bool_t read_xyz(GMouse *m, GMouseReading *prd) { + adcsample_t samples[ADC_NUM_CHANNELS * ADC_BUF_DEPTH]; + (void) m; + + // No buttons + prd->buttons = 0; + + // Get the z reading (assumes we are ready to read z) + adcConvert(&ADCD1, &adcgrpcfg, samples, ADC_BUF_DEPTH); + prd->z = samples[0]; + + // Take a shortcut and don't read x, y if we know we are definitely not touched. + if (prd->z >= GMOUSE_MCU_Z_TOUCHOFF) { + + // Get the x reading + palSetPad(GPIOB, GPIOB_DRIVEA); + palClearPad(GPIOB, GPIOB_DRIVEB); + chThdSleepMilliseconds(2); + adcConvert(&ADCD1, &adcgrpcfg, samples, ADC_BUF_DEPTH); + prd->x = samples[1]; + + // Get the y reading + palClearPad(GPIOB, GPIOB_DRIVEA); + palSetPad(GPIOB, GPIOB_DRIVEB); + chThdSleepMilliseconds(2); + adcConvert(&ADCD1, &adcgrpcfg, samples, ADC_BUF_DEPTH); + prd->y = samples[0]; + + // Set up for reading z again. We know it will be 20ms before we get called again so don't worry about settling time + palClearPad(GPIOB, GPIOB_DRIVEA); + palClearPad(GPIOB, GPIOB_DRIVEB); + } + return TRUE; +} + +#endif /* _LLD_GMOUSE_MCU_BOARD_H */ diff --git a/boards/base/Olimex-STM32-LCD/ginput_lld_mouse_board.h b/boards/base/Olimex-STM32-LCD/ginput_lld_mouse_board.h deleted file mode 100644 index 91575527..00000000 --- a/boards/base/Olimex-STM32-LCD/ginput_lld_mouse_board.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _GINPUT_LLD_MOUSE_BOARD_H -#define _GINPUT_LLD_MOUSE_BOARD_H - -#define ADC_NUM_CHANNELS 2 -#define ADC_BUF_DEPTH 1 - -static const ADCConversionGroup adc_y_config = { - FALSE, - ADC_NUM_CHANNELS, - 0, - 0, - 0, 0, - 0, 0, - ADC_SQR1_NUM_CH(ADC_NUM_CHANNELS), - 0, - ADC_SQR3_SQ2_N(ADC_CHANNEL_IN12) | ADC_SQR3_SQ1_N(ADC_CHANNEL_IN13) -}; - -static const ADCConversionGroup adc_x_config = { - FALSE, - ADC_NUM_CHANNELS, - 0, - 0, - 0, 0, - 0, 0, - ADC_SQR1_NUM_CH(ADC_NUM_CHANNELS), - 0, - ADC_SQR3_SQ2_N(ADC_CHANNEL_IN10) | ADC_SQR3_SQ1_N(ADC_CHANNEL_IN11) -}; - -static inline void init_board(void) { - adcStart(&ADCD1, 0); -} - -static inline void aquire_bus(void) { - -} - -static inline void release_bus(void) { - -} - -static inline void setup_x(void) { - palSetPadMode(GPIOC, 0, PAL_MODE_INPUT_ANALOG); - palSetPadMode(GPIOC, 1, PAL_MODE_INPUT_ANALOG); - palSetPadMode(GPIOC, 2, PAL_MODE_OUTPUT_PUSHPULL); - palSetPadMode(GPIOC, 3, PAL_MODE_OUTPUT_PUSHPULL); - - palSetPad(GPIOC, 2); - palClearPad(GPIOC, 3); - gfxSleepMilliseconds(1); -} - -static inline void setup_y(void) { - palSetPadMode(GPIOC, 2, PAL_MODE_INPUT_ANALOG); - palSetPadMode(GPIOC, 3, PAL_MODE_INPUT_ANALOG); - palSetPadMode(GPIOC, 0, PAL_MODE_OUTPUT_PUSHPULL); - palSetPadMode(GPIOC, 1, PAL_MODE_OUTPUT_PUSHPULL); - - palSetPad(GPIOC, 1); - palClearPad(GPIOC, 0); - gfxSleepMilliseconds(1); -} - -static inline void setup_z(void) { - palSetPadMode(GPIOC, 0, PAL_MODE_INPUT_PULLDOWN); - palSetPadMode(GPIOC, 1, PAL_MODE_INPUT); - palSetPadMode(GPIOC, 2, PAL_MODE_INPUT); - palSetPadMode(GPIOC, 3, PAL_MODE_OUTPUT_PUSHPULL); - palSetPad(GPIOC, 3); -} - -static inline uint16_t read_x(void) { - uint16_t val1, val2; - adcsample_t samples[ADC_NUM_CHANNELS * ADC_BUF_DEPTH]; - - palSetPad(GPIOC, 2); - palClearPad(GPIOC, 3); - gfxSleepMilliseconds(1); - adcConvert(&ADCD1, &adc_x_config, samples, ADC_BUF_DEPTH); - val1 = ((samples[0] + samples[1])/2); - - palClearPad(GPIOC, 2); - palSetPad(GPIOC, 3); - gfxSleepMilliseconds(1); - adcConvert(&ADCD1, &adc_x_config, samples, ADC_BUF_DEPTH); - val2 = ((samples[0] + samples[1])/2); - - return ((val1+((1<<12)-val2))/4); -} - -static inline uint16_t read_y(void) { - uint16_t val1, val2; - adcsample_t samples[ADC_NUM_CHANNELS * ADC_BUF_DEPTH]; - - palSetPad(GPIOC, 1); - palClearPad(GPIOC, 0); - gfxSleepMilliseconds(1); - adcConvert(&ADCD1, &adc_y_config, samples, ADC_BUF_DEPTH); - val1 = ((samples[0] + samples[1])/2); - - palClearPad(GPIOC, 1); - palSetPad(GPIOC, 0); - gfxSleepMilliseconds(1); - adcConvert(&ADCD1, &adc_y_config, samples, ADC_BUF_DEPTH); - val2 = ((samples[0] + samples[1])/2); - - return ((val1+((1<<12)-val2))/4); -} - -static inline uint16_t read_z(void) { - if (palReadPad(GPIOC, 0)) - return 100; - else - return 0; -} - -#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ - diff --git a/boards/base/Olimex-STM32-LCD/ginput_lld_mouse_config.h b/boards/base/Olimex-STM32-LCD/ginput_lld_mouse_config.h deleted file mode 100644 index e8362219..00000000 --- a/boards/base/Olimex-STM32-LCD/ginput_lld_mouse_config.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _LLD_GINPUT_MOUSE_CONFIG_H -#define _LLD_GINPUT_MOUSE_CONFIG_H - -#define GINPUT_MOUSE_EVENT_TYPE GEVENT_TOUCH -#define GINPUT_MOUSE_NEED_CALIBRATION TRUE -#define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE -#define GINPUT_MOUSE_MAX_CALIBRATION_ERROR 12 -#define GINPUT_MOUSE_READ_CYCLES 1 -#define GINPUT_MOUSE_POLL_PERIOD 25 -#define GINPUT_MOUSE_MAX_CLICK_JITTER 2 -#define GINPUT_MOUSE_MAX_MOVE_JITTER 2 -#define GINPUT_MOUSE_CLICK_TIME 500 - -#endif /* _LLD_GINPUT_MOUSE_CONFIG_H */ - diff --git a/boards/base/Olimex-STM32-LCD/gmouse_lld_MCU_board.h b/boards/base/Olimex-STM32-LCD/gmouse_lld_MCU_board.h new file mode 100644 index 00000000..414587cf --- /dev/null +++ b/boards/base/Olimex-STM32-LCD/gmouse_lld_MCU_board.h @@ -0,0 +1,136 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _LLD_GMOUSE_MCU_BOARD_H +#define _LLD_GMOUSE_MCU_BOARD_H + +// Resolution and Accuracy Settings +#define GMOUSE_MCU_PEN_CALIBRATE_ERROR 8 +#define GMOUSE_MCU_PEN_CLICK_ERROR 6 +#define GMOUSE_MCU_PEN_MOVE_ERROR 4 +#define GMOUSE_MCU_FINGER_CALIBRATE_ERROR 14 +#define GMOUSE_MCU_FINGER_CLICK_ERROR 18 +#define GMOUSE_MCU_FINGER_MOVE_ERROR 14 +#define GMOUSE_MCU_Z_MIN 0 +#define GMOUSE_MCU_Z_MAX 1 +#define GMOUSE_MCU_Z_TOUCHON 1 +#define GMOUSE_MCU_Z_TOUCHOFF 0 + +// How much extra data to allocate at the end of the GMouse structure for the board's use +#define GMOUSE_MCU_BOARD_DATA_SIZE 0 + +#define ADC_NUM_CHANNELS 2 +#define ADC_BUF_DEPTH 1 + +static const ADCConversionGroup adc_y_config = { + FALSE, + ADC_NUM_CHANNELS, + 0, + 0, + 0, 0, + 0, 0, + ADC_SQR1_NUM_CH(ADC_NUM_CHANNELS), + 0, + ADC_SQR3_SQ2_N(ADC_CHANNEL_IN12) | ADC_SQR3_SQ1_N(ADC_CHANNEL_IN13) +}; + +static const ADCConversionGroup adc_x_config = { + FALSE, + ADC_NUM_CHANNELS, + 0, + 0, + 0, 0, + 0, 0, + ADC_SQR1_NUM_CH(ADC_NUM_CHANNELS), + 0, + ADC_SQR3_SQ2_N(ADC_CHANNEL_IN10) | ADC_SQR3_SQ1_N(ADC_CHANNEL_IN11) +}; + +static inline void setup_z(void) { + palSetPadMode(GPIOC, 0, PAL_MODE_INPUT_PULLDOWN); + palSetPadMode(GPIOC, 1, PAL_MODE_INPUT); + palSetPadMode(GPIOC, 2, PAL_MODE_INPUT); + palSetPadMode(GPIOC, 3, PAL_MODE_OUTPUT_PUSHPULL); + palSetPad(GPIOC, 3); +} + +static bool_t init_board(GMouse *m, unsigned driverinstance) { + (void) m; + + // Only one touch interface on this board + if (driverinstance) + return FALSE; + + adcStart(&ADCD1, 0); + + // Set up for reading Z + setup_z(); + chThdSleepMilliseconds(1); // Settling time + return TRUE; +} + +static bool_t read_xyz(GMouse *m, GMouseReading *prd) { + adcsample_t samples[ADC_NUM_CHANNELS * ADC_BUF_DEPTH]; + uint16_t val1, val2; + (void) m; + + // No buttons and assume touch off + prd->buttons = 0; + prd->z = 0; + + // Get the z reading (assumes we are ready to read z) + // Take a shortcut and don't read x, y if we know we are definitely not touched. + if (palReadPad(GPIOC, 0)) { + prd->z = 1; + + // Get the x reading - Weird but it works. Optimize later. + palSetPadMode(GPIOC, 0, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 1, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 2, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(GPIOC, 3, PAL_MODE_OUTPUT_PUSHPULL); + + palSetPad(GPIOC, 2); + palClearPad(GPIOC, 3); + gfxSleepMilliseconds(1); + adcConvert(&ADCD1, &adc_x_config, samples, ADC_BUF_DEPTH); + val1 = ((samples[0] + samples[1])/2); + + palClearPad(GPIOC, 2); + palSetPad(GPIOC, 3); + gfxSleepMilliseconds(1); + adcConvert(&ADCD1, &adc_x_config, samples, ADC_BUF_DEPTH); + val2 = ((samples[0] + samples[1])/2); + + prd->x = ((val1+((1<<12)-val2))/4); + + // Get the y reading - Weird but it works. Optimize later. + palSetPadMode(GPIOC, 2, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 3, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 0, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(GPIOC, 1, PAL_MODE_OUTPUT_PUSHPULL); + + palSetPad(GPIOC, 1); + palClearPad(GPIOC, 0); + gfxSleepMilliseconds(1); + adcConvert(&ADCD1, &adc_y_config, samples, ADC_BUF_DEPTH); + val1 = ((samples[0] + samples[1])/2); + + palClearPad(GPIOC, 1); + palSetPad(GPIOC, 0); + gfxSleepMilliseconds(1); + adcConvert(&ADCD1, &adc_y_config, samples, ADC_BUF_DEPTH); + val2 = ((samples[0] + samples[1])/2); + + prd->y = ((val1+((1<<12)-val2))/4); + + // Set up for reading z again. We know it will be 20ms before we get called again so don't worry about settling time + setup_z(); + } + return TRUE; +} + +#endif /* _LLD_GMOUSE_MCU_BOARD_H */ diff --git a/boards/base/STM32F429i-Discovery/board.mk b/boards/base/STM32F429i-Discovery/board.mk index c8dc7117..09116393 100644 --- a/boards/base/STM32F429i-Discovery/board.mk +++ b/boards/base/STM32F429i-Discovery/board.mk @@ -4,5 +4,4 @@ GFXSRC += $(GFXLIB)/boards/base/STM32F429i-Discovery/stm32f429i_discovery_sdram GFXDEFS += -DGFX_USE_OS_CHIBIOS=TRUE include $(GFXLIB)/drivers/gdisp/STM32F429iDiscovery/driver.mk -#include $(GFXLIB)/drivers/ginput/touch/MCU/driver.mk -#include $(GFXLIB)/drivers/gaudio/vs1053/driver.mk +include $(GFXLIB)/drivers/ginput/touch/STMPE811/driver.mk diff --git a/boards/base/STM32F429i-Discovery/example_chibios_2.x/halconf.h b/boards/base/STM32F429i-Discovery/example_chibios_2.x/halconf.h index e0ef55fe..8c45a63b 100644 --- a/boards/base/STM32F429i-Discovery/example_chibios_2.x/halconf.h +++ b/boards/base/STM32F429i-Discovery/example_chibios_2.x/halconf.h @@ -76,7 +76,7 @@ * @brief Enables the I2C subsystem. */ #if !defined(HAL_USE_I2C) || defined(__DOXYGEN__) -#define HAL_USE_I2C FALSE +#define HAL_USE_I2C TRUE #endif /** diff --git a/boards/base/STM32F429i-Discovery/example_chibios_2.x/mcuconf.h b/boards/base/STM32F429i-Discovery/example_chibios_2.x/mcuconf.h index d0b1d6a4..222958fe 100644 --- a/boards/base/STM32F429i-Discovery/example_chibios_2.x/mcuconf.h +++ b/boards/base/STM32F429i-Discovery/example_chibios_2.x/mcuconf.h @@ -138,7 +138,7 @@ */ #define STM32_I2C_USE_I2C1 FALSE #define STM32_I2C_USE_I2C2 FALSE -#define STM32_I2C_USE_I2C3 FALSE +#define STM32_I2C_USE_I2C3 TRUE #define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) #define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) #define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) diff --git a/boards/base/STM32F429i-Discovery/gmouse_lld_STMPE811_board.h b/boards/base/STM32F429i-Discovery/gmouse_lld_STMPE811_board.h new file mode 100644 index 00000000..f5bab2b9 --- /dev/null +++ b/boards/base/STM32F429i-Discovery/gmouse_lld_STMPE811_board.h @@ -0,0 +1,120 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _GINPUT_LLD_MOUSE_BOARD_H +#define _GINPUT_LLD_MOUSE_BOARD_H + +// Resolution and Accuracy Settings +#define GMOUSE_STMPE811_PEN_CALIBRATE_ERROR 8 +#define GMOUSE_STMPE811_PEN_CLICK_ERROR 6 +#define GMOUSE_STMPE811_PEN_MOVE_ERROR 4 +#define GMOUSE_STMPE811_FINGER_CALIBRATE_ERROR 14 +#define GMOUSE_STMPE811_FINGER_CLICK_ERROR 18 +#define GMOUSE_STMPE811_FINGER_MOVE_ERROR 14 + +// How much extra data to allocate at the end of the GMouse structure for the board's use +#define GMOUSE_STMPE811_BOARD_DATA_SIZE 0 + +// Options - Leave these commented to make it user configurable in the gfxconf.h +//#define GMOUSE_STMPE811_READ_PRESSURE FALSE +//#define GMOUSE_STMPE811_SELF_CALIBRATE FALSE +//#define GMOUSE_STMPE811_TEST_MODE FALSE + +// Set to FALSE because it does not work properly on this board even though the pin exists. +#define GMOUSE_STMPE811_GPIO_IRQPIN FALSE + +// If TRUE this is a really slow CPU and we should always clear the FIFO between reads. +#define GMOUSE_STMPE811_SLOW_CPU FALSE + +// Slave address +#define STMPE811_ADDR 0x41 + +// Maximum timeout +#define STMPE811_TIMEOUT 0x3000 + +static const I2CConfig i2ccfg = { + OPMODE_I2C, + 400000, + FAST_DUTY_CYCLE_2, +}; + +static bool_t init_board(GMouse* m, unsigned driverinstance) { + (void) m; + + // This board only supports one touch panel + if (driverinstance) + return FALSE; + + // Set pin modes + palSetPadMode(GPIOA, 15, PAL_MODE_INPUT | PAL_STM32_PUDR_FLOATING); /* TP IRQ */ + palSetPadMode(GPIOA, 8, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); /* SCL */ + palSetPadMode(GPIOC, 9, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); /* SDA */ + + // Start the I2C + i2cStart(&I2CD3, &i2ccfg); + + return TRUE; +} + +#if GMOUSE_STMPE811_GPIO_IRQPIN + static bool_t getpin_irq(GMouse* m) { + (void) m; + + return !palReadPad(GPIOA, 15); + } +#endif + +static inline void aquire_bus(GMouse* m) { + (void) m; + +} + +static inline void release_bus(GMouse* m) { + (void) m; + +} + +static void write_reg(GMouse* m, uint8_t reg, uint8_t val) { + uint8_t txbuf[2]; + (void) m; + + txbuf[0] = reg; + txbuf[1] = val; + + i2cAcquireBus(&I2CD3); + i2cMasterTransmitTimeout(&I2CD3, STMPE811_ADDR, txbuf, 2, 0, 0, MS2ST(STMPE811_TIMEOUT)); + i2cReleaseBus(&I2CD3); +} + +static uint8_t read_byte(GMouse* m, uint8_t reg) { + uint8_t rxbuf[1]; + (void) m; + + rxbuf[0] = 0; + + i2cAcquireBus(&I2CD3); + i2cMasterTransmitTimeout(&I2CD3, STMPE811_ADDR, ®, 1, rxbuf, 1, MS2ST(STMPE811_TIMEOUT)); + i2cReleaseBus(&I2CD3); + + return rxbuf[0]; +} + +static uint16_t read_word(GMouse* m, uint8_t reg) { + uint8_t rxbuf[2]; + (void) m; + + rxbuf[0] = 0; + rxbuf[1] = 0; + + i2cAcquireBus(&I2CD3); + i2cMasterTransmitTimeout(&I2CD3, STMPE811_ADDR, ®, 1, rxbuf, 2, MS2ST(STMPE811_TIMEOUT)); + i2cReleaseBus(&I2CD3); + + return (((uint16_t)rxbuf[0]) << 8) | rxbuf[1]; +} + +#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ diff --git a/demos/modules/gwin/button/main.c b/demos/modules/gwin/button/main.c index 15e8e5a7..1d8aa2e6 100644 --- a/demos/modules/gwin/button/main.c +++ b/demos/modules/gwin/button/main.c @@ -39,7 +39,7 @@ static void createWidgets(void) { gwinWidgetClearInit(&wi); wi.g.show = TRUE; - // Apply the button parameters + // Apply the button parameters wi.g.width = 100; wi.g.height = 30; wi.g.y = 10; @@ -67,9 +67,6 @@ int main(void) { gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); gdispClear(White); - // Attach the mouse input - gwinAttachMouse(0); - // create the widget createWidgets(); diff --git a/demos/modules/gwin/checkbox/main.c b/demos/modules/gwin/checkbox/main.c index 28122bee..22963e40 100644 --- a/demos/modules/gwin/checkbox/main.c +++ b/demos/modules/gwin/checkbox/main.c @@ -39,14 +39,14 @@ static void createWidgets(void) { gwinWidgetClearInit(&wi); wi.g.show = TRUE; - // Apply the checkbox parameters + // Apply the checkbox parameters wi.g.width = 100; // includes text wi.g.height = 20; wi.g.y = 10; wi.g.x = 10; wi.text = "Checkbox"; - // Create the actual checkbox + // Create the actual checkbox ghCheckbox1 = gwinCheckboxCreate(0, &wi); } @@ -61,9 +61,6 @@ int main(void) { gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); gdispClear(White); - // Attach the mouse input - gwinAttachMouse(0); - // create the widget createWidgets(); diff --git a/demos/modules/gwin/container/main.c b/demos/modules/gwin/container/main.c index 4e73b0c4..75e3f78b 100644 --- a/demos/modules/gwin/container/main.c +++ b/demos/modules/gwin/container/main.c @@ -19,7 +19,7 @@ static void createWidgets(void) { ghContainer = gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER); wi.g.show = TRUE; - // Apply the button parameters + // Apply the button parameters wi.g.width = 120; wi.g.height = 30; wi.g.y = 10; @@ -37,9 +37,6 @@ int main(void) { // Initialize the display gfxInit(); - // Attach the mouse input - gwinAttachMouse(0); - // Set the widget defaults gwinSetDefaultFont(gdispOpenFont("*")); gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); diff --git a/demos/modules/gwin/container_nested/main.c b/demos/modules/gwin/container_nested/main.c index 2d90f76b..5cd5e793 100644 --- a/demos/modules/gwin/container_nested/main.c +++ b/demos/modules/gwin/container_nested/main.c @@ -40,7 +40,7 @@ static void createWidgets(void) { wi.text = "Container 3"; ghContainer3 = gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER); - // Button 1 + // Button 1 wi.g.width = 80; wi.g.height = 20; wi.g.y = 10; @@ -49,7 +49,7 @@ static void createWidgets(void) { wi.g.parent = ghContainer2; ghButton1 = gwinButtonCreate(0, &wi); - // Button 2 + // Button 2 wi.g.width = 80; wi.g.height = 20; wi.g.y = 40; @@ -58,7 +58,7 @@ static void createWidgets(void) { wi.g.parent = ghContainer2; ghButton2 = gwinButtonCreate(0, &wi); - // Button 3 + // Button 3 wi.g.width = 80; wi.g.height = 20; wi.g.y = 10; @@ -67,7 +67,7 @@ static void createWidgets(void) { wi.g.parent = ghContainer3; ghButton3 = gwinButtonCreate(0, &wi); - // Button 4 + // Button 4 wi.g.width = 80; wi.g.height = 20; wi.g.y = 40; @@ -115,9 +115,6 @@ int main(void) { // Initialize the display gfxInit(); - // Attach the mouse input - gwinAttachMouse(0); - // Set the widget defaults gwinSetDefaultFont(gdispOpenFont("*")); gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); diff --git a/demos/modules/gwin/frame/main.c b/demos/modules/gwin/frame/main.c index fe956925..a97525ab 100644 --- a/demos/modules/gwin/frame/main.c +++ b/demos/modules/gwin/frame/main.c @@ -33,7 +33,7 @@ static void _createWidgets(void) { wi.text = "Surprise!"; gwinLabelCreate(0, &wi); - // Apply the frame parameters + // Apply the frame parameters wi.g.width = 300; wi.g.height = 200; wi.g.y = 10; @@ -107,7 +107,7 @@ static void _createWidgets(void) { wi.g.x = 10; wi.g.y = 90; ghWindow1 = gwinWindowCreate(0, &wi.g); - + _updateColor(); } @@ -117,9 +117,6 @@ int main(void) { // Initialize the display gfxInit(); - // Attach the mouse input - gwinAttachMouse(0); - // Set the widget defaults gwinSetDefaultFont(gdispOpenFont("*")); gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); diff --git a/demos/modules/gwin/label/main.c b/demos/modules/gwin/label/main.c index aab9cd76..425436ea 100644 --- a/demos/modules/gwin/label/main.c +++ b/demos/modules/gwin/label/main.c @@ -63,9 +63,6 @@ int main(void) { gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); gdispClear(White); - // Attach the mouse input - gwinAttachMouse(0); - // create the widget createWidgets(); diff --git a/demos/modules/gwin/list/main.c b/demos/modules/gwin/list/main.c index ed5b6905..0102f276 100644 --- a/demos/modules/gwin/list/main.c +++ b/demos/modules/gwin/list/main.c @@ -79,9 +79,6 @@ int main(void) { gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); gdispClear(White); - // Attach the mouse input - gwinAttachMouse(0); - // create the widget createWidgets(); diff --git a/demos/modules/gwin/radio/main.c b/demos/modules/gwin/radio/main.c index 7455c770..59b86983 100644 --- a/demos/modules/gwin/radio/main.c +++ b/demos/modules/gwin/radio/main.c @@ -83,9 +83,6 @@ int main(void) { gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); gdispClear(White); - // Attach the mouse input - gwinAttachMouse(0); - // create the widget createWidgets(); diff --git a/demos/modules/gwin/slider/main.c b/demos/modules/gwin/slider/main.c index ddcd90df..bf0aacfc 100644 --- a/demos/modules/gwin/slider/main.c +++ b/demos/modules/gwin/slider/main.c @@ -59,9 +59,6 @@ int main(void) { gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); gdispClear(White); - // Attach the mouse input - gwinAttachMouse(0); - // create the widget createWidgets(); diff --git a/demos/modules/gwin/widgets/main.c b/demos/modules/gwin/widgets/main.c index 3239ab4c..d2f6882b 100644 --- a/demos/modules/gwin/widgets/main.c +++ b/demos/modules/gwin/widgets/main.c @@ -418,11 +418,6 @@ int main(void) { // Initialize the display gfxInit(); - // Connect the mouse - #if GINPUT_NEED_MOUSE - gwinAttachMouse(0); - #endif - // Set the widget defaults font = gdispOpenFont("*"); // Get the first defined font. gwinSetDefaultFont(font); diff --git a/docs/releases.txt b/docs/releases.txt index cf401935..ef1e4547 100644 --- a/docs/releases.txt +++ b/docs/releases.txt @@ -32,6 +32,10 @@ FEATURE: Added transparent custom draws for GWIN containers and frame widgets FEATURE: Added image custom draws for GWIN containers and frame widgets FEATURE: Added GDRIVER infrastructure. Ported GDISP to use it. FEATURE: Added gdispDrawArcSectors() and gdispFillArcSectors(). +FEATURE: Ported GINPUT MOUSE to GDRIVER infrastructure. +FEATURE: Mouse/Touch now support both pen and finger mode. +DEPRECATE: gwinAttachMouse() is now handled automaticly. +FEATURE: Added MAX11802 touch driver by user steved *** Release 2.1 *** diff --git a/drivers/ginput/touch/ADS7843/driver.mk b/drivers/ginput/touch/ADS7843/driver.mk index 31e9ab2c..1a0eaf8e 100644 --- a/drivers/ginput/touch/ADS7843/driver.mk +++ b/drivers/ginput/touch/ADS7843/driver.mk @@ -1,5 +1,2 @@ # List the required driver. -GFXSRC += $(GFXLIB)/drivers/ginput/touch/ADS7843/ginput_lld_mouse.c - -# Required include directories -GFXINC += $(GFXLIB)/drivers/ginput/touch/ADS7843 +GFXSRC += $(GFXLIB)/drivers/ginput/touch/ADS7843/gmouse_lld_ADS7843.c diff --git a/drivers/ginput/touch/ADS7843/ginput_lld_mouse.c b/drivers/ginput/touch/ADS7843/ginput_lld_mouse.c deleted file mode 100644 index cb9b6f4e..00000000 --- a/drivers/ginput/touch/ADS7843/ginput_lld_mouse.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#include "gfx.h" - -#if (GFX_USE_GINPUT && GINPUT_NEED_MOUSE) /*|| defined(__DOXYGEN__)*/ - -#include "src/ginput/driver_mouse.h" - -#include "ginput_lld_mouse_board.h" - -#if defined(GINPUT_MOUSE_YX_INVERTED) && GINPUT_MOUSE_YX_INVERTED - #define CMD_X 0x91 - #define CMD_Y 0xD1 -#else - #define CMD_X 0xD1 - #define CMD_Y 0x91 -#endif - - -static uint16_t sampleBuf[7]; -static coord_t lastx, lasty; - -static void filter(void) { - uint16_t temp; - int i,j; - - for(i = 0; i < 4; i++) { - for(j = i; j < 7; j++) { - if(sampleBuf[i] > sampleBuf[j]) { - /* Swap the values */ - temp = sampleBuf[i]; - sampleBuf[i] = sampleBuf[j]; - sampleBuf[j] = temp; - } - } - } -} - -void ginput_lld_mouse_init(void) { - init_board(); -} - -void ginput_lld_mouse_get_reading(MouseReading *pt) { - uint16_t i; - - // If touch-off return the previous results - if (!getpin_pressed()) { - pt->x = lastx; - pt->y = lasty; - pt->z = 0; - pt->buttons = 0; - return; - } - - // Read the port to get the touch settings - aquire_bus(); - - /* Get the X value - * Discard the first conversion - very noisy and keep the ADC on hereafter - * till we are done with the sampling. Note that PENIRQ is disabled while reading. - * Finally switch on PENIRQ once again - perform a dummy read. - * Once we have the readings, find the medium using our filter function - */ - read_value(CMD_X); - for(i = 0; i < 7; i++) - sampleBuf[i] = read_value(CMD_X); - read_value(CMD_X-1); - filter(); - lastx = (coord_t)sampleBuf[3]; - - /* Get the Y value using the same process as above */ - read_value(CMD_Y); - for(i = 0; i < 7; i++) - sampleBuf[i] = read_value(CMD_Y); - read_value(CMD_Y-1); - filter(); - lasty = (coord_t)sampleBuf[3]; - - // Release the bus - release_bus(); - - // Return the results - pt->x = lastx; - pt->y = lasty; - pt->z = 100; - pt->buttons = GINPUT_TOUCH_PRESSED; -} - -#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */ diff --git a/drivers/ginput/touch/ADS7843/ginput_lld_mouse_board_template.h b/drivers/ginput/touch/ADS7843/ginput_lld_mouse_board_template.h deleted file mode 100644 index 09783adf..00000000 --- a/drivers/ginput/touch/ADS7843/ginput_lld_mouse_board_template.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _GINPUT_LLD_MOUSE_BOARD_H -#define _GINPUT_LLD_MOUSE_BOARD_H - -static inline void init_board(void) { - -} - -static inline bool_t getpin_pressed(void) { - -} - -static inline void aquire_bus(void) { - -} - -static inline void release_bus(void) { - -} - -static inline uint16_t read_value(uint16_t port) { - -} - -#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ diff --git a/drivers/ginput/touch/ADS7843/ginput_lld_mouse_config.h b/drivers/ginput/touch/ADS7843/ginput_lld_mouse_config.h deleted file mode 100644 index 31840a51..00000000 --- a/drivers/ginput/touch/ADS7843/ginput_lld_mouse_config.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _LLD_GINPUT_MOUSE_CONFIG_H -#define _LLD_GINPUT_MOUSE_CONFIG_H - -#define GINPUT_MOUSE_EVENT_TYPE GEVENT_TOUCH -#define GINPUT_MOUSE_NEED_CALIBRATION TRUE -#define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE -#define GINPUT_MOUSE_MAX_CALIBRATION_ERROR 5 -#define GINPUT_MOUSE_READ_CYCLES 4 -#define GINPUT_MOUSE_POLL_PERIOD 25 -#define GINPUT_MOUSE_MAX_CLICK_JITTER 10 -#define GINPUT_MOUSE_MAX_MOVE_JITTER 2 -#define GINPUT_MOUSE_CLICK_TIME 500 - -#endif /* _LLD_GINPUT_MOUSE_CONFIG_H */ diff --git a/drivers/ginput/touch/ADS7843/gmouse_lld_ADS7843.c b/drivers/ginput/touch/ADS7843/gmouse_lld_ADS7843.c new file mode 100644 index 00000000..5f1eb226 --- /dev/null +++ b/drivers/ginput/touch/ADS7843/gmouse_lld_ADS7843.c @@ -0,0 +1,80 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#include "gfx.h" + +#if (GFX_USE_GINPUT && GINPUT_NEED_MOUSE) + +#define GMOUSE_DRIVER_VMT GMOUSEVMT_ADS7843 +#include "src/ginput/driver_mouse.h" + +// Get the hardware interface +#include "gmouse_lld_ADS7843_board.h" + +#define CMD_X 0xD1 +#define CMD_Y 0x91 +#define CMD_ENABLE_IRQ 0x80 + +static bool_t MouseXYZ(GMouse* m, GMouseReading* pdr) +{ + (void)m; + + // No buttons + pdr->buttons = 0; + pdr->z = 0; + + if (getpin_pressed(m)) { + pdr->z = 1; // Set to Z_MAX as we are pressed + + aquire_bus(m); + + read_value(m, CMD_X); // Dummy read - disable PenIRQ + pdr->x = read_value(m, CMD_X); // Read X-Value + + read_value(m, CMD_Y); // Dummy read - disable PenIRQ + pdr->y = read_value(m, CMD_Y); // Read Y-Value + + read_value(m, CMD_ENABLE_IRQ); // Enable IRQ + + release_bus(m); + } + return TRUE; +} + +const GMouseVMT const GMOUSE_DRIVER_VMT[1] = {{ + { + GDRIVER_TYPE_TOUCH, + GMOUSE_VFLG_TOUCH | GMOUSE_VFLG_CALIBRATE | GMOUSE_VFLG_CAL_TEST | + GMOUSE_VFLG_ONLY_DOWN | GMOUSE_VFLG_POORUPDOWN, + sizeof(GMouse)+BOARD_DATA_SIZE, + _gmouseInitDriver, + _gmousePostInitDriver, + _gmouseDeInitDriver + }, + 1, // z_max - (currently?) not supported + 0, // z_min - (currently?) not supported + 1, // z_touchon + 0, // z_touchoff + { // pen_jitter + GMOUSE_ADS7843_PEN_CALIBRATE_ERROR, // calibrate + GMOUSE_ADS7843_PEN_CLICK_ERROR, // click + GMOUSE_ADS7843_PEN_MOVE_ERROR // move + }, + { // finger_jitter + GMOUSE_ADS7843_FINGER_CALIBRATE_ERROR, // calibrate + GMOUSE_ADS7843_FINGER_CLICK_ERROR, // click + GMOUSE_ADS7843_FINGER_MOVE_ERROR // move + }, + init_board, // init + 0, // deinit + MouseXYZ, // get + 0, // calsave + 0 // calload +}}; + +#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */ + diff --git a/drivers/ginput/touch/ADS7843/gmouse_lld_ADS7843_board_template.h b/drivers/ginput/touch/ADS7843/gmouse_lld_ADS7843_board_template.h new file mode 100644 index 00000000..0b9cc71b --- /dev/null +++ b/drivers/ginput/touch/ADS7843/gmouse_lld_ADS7843_board_template.h @@ -0,0 +1,42 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _GINPUT_LLD_MOUSE_BOARD_H +#define _GINPUT_LLD_MOUSE_BOARD_H + +// Resolution and Accuracy Settings +#define GMOUSE_ADS7843_PEN_CALIBRATE_ERROR 8 +#define GMOUSE_ADS7843_PEN_CLICK_ERROR 6 +#define GMOUSE_ADS7843_PEN_MOVE_ERROR 4 +#define GMOUSE_ADS7843_FINGER_CALIBRATE_ERROR 14 +#define GMOUSE_ADS7843_FINGER_CLICK_ERROR 18 +#define GMOUSE_ADS7843_FINGER_MOVE_ERROR 14 + +// How much extra data to allocate at the end of the GMouse structure for the board's use +#define GMOUSE_ADS7843_BOARD_DATA_SIZE 0 + +static bool_t init_board(GMouse* m, unsigned driverinstance) { + +} + +static inline bool_t getpin_pressed(GMouse* m) { + +} + +static inline void aquire_bus(GMouse* m) { + +} + +static inline void release_bus(GMouse* m) { + +} + +static inline uint16_t read_value(GMouse* m, uint16_t port) { + +} + +#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ diff --git a/drivers/ginput/touch/FT5x06/driver.mk b/drivers/ginput/touch/FT5x06/driver.mk index 17d38c61..741464e8 100644 --- a/drivers/ginput/touch/FT5x06/driver.mk +++ b/drivers/ginput/touch/FT5x06/driver.mk @@ -1,5 +1,2 @@ # List the required driver. -GFXSRC += $(GFXLIB)/drivers/ginput/touch/FT5x06/ginput_lld_mouse.c - -# Required include directories -GFXINC += $(GFXLIB)/drivers/ginput/touch/FT5x06 +GFXSRC += $(GFXLIB)/drivers/ginput/touch/FT5x06/gmouse_lld_FT5x06.c diff --git a/drivers/ginput/touch/FT5x06/ginput_lld_mouse.c b/drivers/ginput/touch/FT5x06/ginput_lld_mouse.c deleted file mode 100644 index 7a50c5f6..00000000 --- a/drivers/ginput/touch/FT5x06/ginput_lld_mouse.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#include "gfx.h" - -#if (GFX_USE_GINPUT && GINPUT_NEED_MOUSE) /*|| defined(__DOXYGEN__)*/ - -#include "src/ginput/driver_mouse.h" - -#include "drivers/ginput/touch/FT5x06/ft5x06.h" - -// include board abstraction -#include "ginput_lld_mouse_board.h" - -static coord_t x, y, z; -static uint8_t touched; - -void ginput_lld_mouse_init(void) { - init_board(); - - // Init default values. (From NHD-3.5-320240MF-ATXL-CTP-1 datasheet) - // Valid touching detect threshold - write_reg(FT5x06_ID_G_THGROUP, 1, 0x16); - - // valid touching peak detect threshold - write_reg(FT5x06_ID_G_THPEAK, 1, 0x3C); - - // Touch focus threshold - write_reg(FT5x06_ID_G_THCAL, 1, 0xE9); - - // threshold when there is surface water - write_reg(FT5x06_ID_G_THWATER, 1, 0x01); - - // threshold of temperature compensation - write_reg(FT5x06_ID_G_THTEMP, 1, 0x01); - - // Touch difference threshold - write_reg(FT5x06_ID_G_THDIFF, 1, 0xA0); - - // Delay to enter 'Monitor' status (s) - write_reg(FT5x06_ID_G_TIME_ENTER_MONITOR, 1, 0x0A); - - // Period of 'Active' status (ms) - write_reg(FT5x06_ID_G_PERIODACTIVE, 1, 0x06); - - // Timer to enter ÔidleÕ when in 'Monitor' (ms) - write_reg(FT5x06_ID_G_PERIODMONITOR, 1, 0x28); -} - -void ginput_lld_mouse_get_reading(MouseReading *pt) { - // Poll to get the touched status - uint8_t last_touched; - - last_touched = touched; - touched = (uint8_t)read_reg(FT5x06_TOUCH_POINTS, 1) & 0x07; - - // If not touched, return the previous results - if (touched == 0) { - pt->x = x; - pt->y = y; - pt->z = 0; - pt->buttons = 0; - return; - } - - /* Get the X, Y, Z values */ - x = (coord_t)(read_reg(FT5x06_TOUCH1_XH, 2) & 0x0fff); - y = (coord_t)read_reg(FT5x06_TOUCH1_YH, 2); - z = 100; - - // Rescale X,Y,Z - X & Y don't need scaling when you are using calibration! -#if !GINPUT_MOUSE_NEED_CALIBRATION - x = gdispGetWidth() - x / (4096/gdispGetWidth()); - y = y / (4096/gdispGetHeight()); -#endif - - // Return the results. ADC gives values from 0 to 2^12 (4096) - pt->x = x; - pt->y = y; - pt->z = z; - pt->buttons = GINPUT_TOUCH_PRESSED; -} - -#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */ diff --git a/drivers/ginput/touch/FT5x06/ginput_lld_mouse_board_template.h b/drivers/ginput/touch/FT5x06/ginput_lld_mouse_board_template.h deleted file mode 100644 index b7744a49..00000000 --- a/drivers/ginput/touch/FT5x06/ginput_lld_mouse_board_template.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _GINPUT_LLD_MOUSE_BOARD_H -#define _GINPUT_LLD_MOUSE_BOARD_H - -static void init_board(void) { - -} - -static inline bool_t getpin_irq(void) { - -} - -static void write_reg(uint8_t reg, uint8_t n, uint16_t val) { - -} - -static uint16_t read_reg(uint8_t reg, uint8_t n) { - -} - -#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ diff --git a/drivers/ginput/touch/FT5x06/ginput_lld_mouse_config.h b/drivers/ginput/touch/FT5x06/ginput_lld_mouse_config.h deleted file mode 100644 index 24335a0a..00000000 --- a/drivers/ginput/touch/FT5x06/ginput_lld_mouse_config.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _LLD_GINPUT_MOUSE_CONFIG_H -#define _LLD_GINPUT_MOUSE_CONFIG_H - -#define GINPUT_MOUSE_EVENT_TYPE GEVENT_TOUCH -#define GINPUT_MOUSE_NEED_CALIBRATION TRUE -#define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE -#define GINPUT_MOUSE_MAX_CALIBRATION_ERROR 15 -#define GINPUT_MOUSE_READ_CYCLES 1 -#define GINPUT_MOUSE_POLL_PERIOD 25 -#define GINPUT_MOUSE_MAX_CLICK_JITTER 10 -#define GINPUT_MOUSE_MAX_MOVE_JITTER 5 -#define GINPUT_MOUSE_CLICK_TIME 450 - -#endif /* _LLD_GINPUT_MOUSE_CONFIG_H */ diff --git a/drivers/ginput/touch/FT5x06/gmouse_lld_FT5x06.c b/drivers/ginput/touch/FT5x06/gmouse_lld_FT5x06.c new file mode 100644 index 00000000..6b0bcdb2 --- /dev/null +++ b/drivers/ginput/touch/FT5x06/gmouse_lld_FT5x06.c @@ -0,0 +1,121 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#include "gfx.h" + +#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE + +#define GMOUSE_DRIVER_VMT GMOUSEVMT_FT5x06 +#include "src/ginput/driver_mouse.h" + +// Get the hardware interface +#include "gmouse_lld_FT5x06_board.h" + +// Hardware definitions +#include "drivers/ginput/touch/FT5x06/ft5x06.h" + +static bool_t MouseInit(GMouse* m, unsigned driverinstance) { + if (!init_board(m, driverinstance)) + return FALSE; + + aquire_bus(m); + + // Init default values. (From NHD-3.5-320240MF-ATXL-CTP-1 datasheet) + // Valid touching detect threshold + write_reg(m, FT5x06_ID_G_THGROUP, 0x16); + + // valid touching peak detect threshold + write_reg(m, FT5x06_ID_G_THPEAK, 0x3C); + + // Touch focus threshold + write_reg(m, FT5x06_ID_G_THCAL, 0xE9); + + // threshold when there is surface water + write_reg(m, FT5x06_ID_G_THWATER, 0x01); + + // threshold of temperature compensation + write_reg(m, FT5x06_ID_G_THTEMP, 0x01); + + // Touch difference threshold + write_reg(m, FT5x06_ID_G_THDIFF, 0xA0); + + // Delay to enter 'Monitor' status (s) + write_reg(m, FT5x06_ID_G_TIME_ENTER_MONITOR, 0x0A); + + // Period of 'Active' status (ms) + write_reg(m, FT5x06_ID_G_PERIODACTIVE, 0x06); + + // Timer to enter 'idle' when in 'Monitor' (ms) + write_reg(m, FT5x06_ID_G_PERIODMONITOR, 0x28); + + release_bus(m); + return TRUE; +} + +static bool_t MouseXYZ(GMouse* m, GMouseReading* pdr) +{ + // Assume not touched. + pdr->buttons = 0; + pdr->z = 0; + + aquire_bus(m); + + // Only take a reading if we are touched. + if ((read_byte(m, FT5x06_TOUCH_POINTS) & 0x07)) { + + /* Get the X, Y, Z values */ + pdr->x = (coord_t)(read_word(m, FT5x06_TOUCH1_XH) & 0x0fff); + pdr->y = (coord_t)read_word(m, FT5x06_TOUCH1_YH); + pdr->z = 1; + + #if GMOUSE_FT5x06_SELF_CALIBRATE + // Rescale X,Y,Z - If we are using self-calibration + pdr->x = gdispGGetWidth(m->display) - pdr->x / (4096/gdispGGetWidth(m->display)); + pdr->y = pdr->y / (4096/gdispGGetHeight(m->display)); + #endif + } + + release_bus(m); + return TRUE; +} + +const GMouseVMT const GMOUSE_DRIVER_VMT[1] = {{ + { + GDRIVER_TYPE_TOUCH, + #if GMOUSE_FT5x06_SELF_CALIBRATE + GMOUSE_VFLG_TOUCH | GMOUSE_VFLG_ONLY_DOWN | GMOUSE_VFLG_POORUPDOWN, + #else + GMOUSE_VFLG_TOUCH | GMOUSE_VFLG_ONLY_DOWN | GMOUSE_VFLG_POORUPDOWN | GMOUSE_VFLG_CALIBRATE | GMOUSE_VFLG_CAL_TEST, + #endif + sizeof(GMouse) + GMOUSE_FT5x06_BOARD_DATA_SIZE, + _gmouseInitDriver, + _gmousePostInitDriver, + _gmouseDeInitDriver + }, + 1, // z_max - (currently?) not supported + 0, // z_min - (currently?) not supported + 1, // z_touchon + 0, // z_touchoff + { // pen_jitter + GMOUSE_FT5x06_PEN_CALIBRATE_ERROR, // calibrate + GMOUSE_FT5x06_PEN_CLICK_ERROR, // click + GMOUSE_FT5x06_PEN_MOVE_ERROR // move + }, + { // finger_jitter + GMOUSE_FT5x06_FINGER_CALIBRATE_ERROR, // calibrate + GMOUSE_FT5x06_FINGER_CLICK_ERROR, // click + GMOUSE_FT5x06_FINGER_MOVE_ERROR // move + }, + MouseInit, // init + 0, // deinit + read_xyz, // get + 0, // calsave + 0 // calload +}}; + +#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */ + diff --git a/drivers/ginput/touch/FT5x06/gmouse_lld_FT5x06_board_template.h b/drivers/ginput/touch/FT5x06/gmouse_lld_FT5x06_board_template.h new file mode 100644 index 00000000..46680a16 --- /dev/null +++ b/drivers/ginput/touch/FT5x06/gmouse_lld_FT5x06_board_template.h @@ -0,0 +1,46 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _GINPUT_LLD_MOUSE_BOARD_H +#define _GINPUT_LLD_MOUSE_BOARD_H + +// Resolution and Accuracy Settings +#define GMOUSE_FT5x06_PEN_CALIBRATE_ERROR 8 +#define GMOUSE_FT5x06_PEN_CLICK_ERROR 6 +#define GMOUSE_FT5x06_PEN_MOVE_ERROR 4 +#define GMOUSE_FT5x06_FINGER_CALIBRATE_ERROR 14 +#define GMOUSE_FT5x06_FINGER_CLICK_ERROR 18 +#define GMOUSE_FT5x06_FINGER_MOVE_ERROR 14 + +// How much extra data to allocate at the end of the GMouse structure for the board's use +#define GMOUSE_FT5x06_BOARD_DATA_SIZE 0 + +// Set this to TRUE if you want self-calibration. +// NOTE: This is not as accurate as real calibration. +// It requires the orientation of the touch panel to match the display. +// It requires the active area of the touch panel to exactly match the display size. +#define GMOUSE_FT5x06_SELF_CALIBRATE FALSE + +static bool_t init_board(GMouse* m, unsigned driverinstance) { +} + +static inline void aquire_bus(GMouse* m) { +} + +static inline void release_bus(GMouse* m) { +} + +static void write_reg(GMouse* m, uint8_t reg, uint8_t val) { +} + +static uint8_t read_byte(GMouse* m, uint8_t reg) { +} + +static uint16_t read_word(GMouse* m, uint8_t reg) { +} + +#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ diff --git a/drivers/ginput/touch/MAX11802/driver.mk b/drivers/ginput/touch/MAX11802/driver.mk new file mode 100644 index 00000000..246e48b3 --- /dev/null +++ b/drivers/ginput/touch/MAX11802/driver.mk @@ -0,0 +1,2 @@ +# List the required driver. +GFXSRC += $(GFXLIB)/drivers/ginput/touch/MAX11802/gmouse_lld_MAX11802.c diff --git a/drivers/ginput/touch/MAX11802/gmouse_lld_MAX11802.c b/drivers/ginput/touch/MAX11802/gmouse_lld_MAX11802.c new file mode 100644 index 00000000..d1435628 --- /dev/null +++ b/drivers/ginput/touch/MAX11802/gmouse_lld_MAX11802.c @@ -0,0 +1,189 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#include "gfx.h" + +#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE + +#define GMOUSE_DRIVER_VMT GMOUSEVMT_MAX11802 +#include "src/ginput/driver_mouse.h" + +// Hardware definitions +#include "drivers/ginput/touch/MAX11802/max11802.h" + +// Get the hardware interface +#include "gmouse_lld_MAX11802_board.h" + +// Register values to set +#define MAX11802_MODE 0x0E // Direct conversion with averaging +#define MAX11802_AVG 0x55 +#define MAX11802_TIMING 0x77 +#define MAX11802_DELAY 0x55 + +#define Z_MIN 0 +#define Z_MAX 1 + +static bool_t MouseInit(GMouse* m, unsigned driverinstance) +{ + uint8_t *p; + + static const uint8_t commandList[] = { + MAX11802_CMD_GEN_WR, 0xf0, // General config - leave TIRQ enabled, even though we ignore it ATM + MAX11802_CMD_RES_WR, 0x00, // A-D resolution, hardware config - rewriting default; all 12-bit resolution + MAX11802_CMD_AVG_WR, MAX11802_AVG, // A-D averaging - 8 samples, average four median samples + MAX11802_CMD_SAMPLE_WR, 0x00, // A-D sample time - use default + MAX11802_CMD_TIMING_WR, MAX11802_TIMING, // Setup timing + MAX11802_CMD_DELAY_WR, MAX11802_DELAY, // Conversion delays + MAX11802_CMD_TDPULL_WR, 0x00, // A-D resolution, hardware config - rewrite default + // MAX11802_CMD_MDTIM_WR, 0x00, // Autonomous mode timing - write default - only for MAX11800, MAX11801 + // MAX11802_CMD_APCONF_WR, 0x00, // Aperture config register - rewrite default - only for MAX11800, MAX11801 + // Ignore aux config register - not used + MAX11802_CMD_MODE_WR, MAX11802_MODE // Set mode last + }; + + if (!init_board(m, driverinstance)) + return FALSE; + + aquire_bus(m); + + for (p = commandList; p < commandList+sizeof(commandList); p += 2) + write_command(m, p[0], p[1]); + + // Read something as a test + if (write_command(m, MAX11802_CMD_MODE_RD, 0) != MAX11802_MODE) { + release_bus(m); + return FALSE; + } + + release_bus(m); + + return TRUE; +} + +static bool_t read_xyz(GMouse* m, GMouseReading* pdr) +{ + uint8_t readyCount; + uint8_t notReadyCount; + + // Assume not touched. + pdr->buttons = 0; + pdr->z = 0; + + aquire_bus(m); + + // Start the conversion + gfintWriteCommand(m, MAX11802_CMD_MEASUREXY); // just write command + + /** + * put a delay in here, since conversion will take a finite time - longer if reading Z as well + * Potentially 1msec for 3 axes with 8us conversion time per sample, 8 samples per average + * Note Maxim AN5435-software to do calculation (www.maximintegrated.com/design/tools/appnotes/5435/AN5435-software.zip) + * + * We'll just use a fixed delay to avoid too much polling/bus activity + */ + gfxSleepMilliseconds(2); // Was 1 - try 2 + + /* Wait for data ready + * Note: MAX11802 signals the readiness of the results using the lowest 4 bits of the result. However, these are the + * last bits to be read out of the device. It is possible for the hardware value to change in the middle of the read, + * causing the analog value to still be invalid even though the tags indicate a valid result. + * + * We work around this by reading the registers once more after the tags indicate they are ready. + * There's also a separate counter to guard against never getting valid readings. + * + * Read the two or three readings required in a single burst, swapping x and y order if necessary + * + * Reading Z is possible but complicated requiring two z readings, multiplication and division, various constant ratio's, + * and interpolation in relation to the X and Y readings. It is not a simple pressure reading. + * In other words, don't bother trying. + */ + + readyCount = notReadyCount = 0; + do { + // Get a set of readings + gfintWriteCommand(m, MAX11802_CMD_XPOSITION); + #if defined(GINPUT_MOUSE_YX_INVERTED) && GINPUT_MOUSE_YX_INVERTED + pdr->y = read_value(m); + pdr->x = read_value(m); + #else + pdr->x = read_value(m); + pdr->y = read_value(m); + #endif + + // Test the result validity + if (((pdr->x | pdr->y) & 0x03) == 0x03) { + + // Has it been too long? If so give up + if (++notReadyCount >= 5) { + release_bus(m); + return FALSE; + } + + // Give up the time slice to someone else and then try again + gfxYield(); + continue; + } + + // We have a result but we need two valid results to believe it + readyCount++; + + } while (readyCount < 2); + + release_bus(m); + + /** + * format of each value returned by MAX11802: + * Bits 15..4 - analog value + * Bits 3..2 - tag value - measurement type (X, Y, Z1, Z2) + * Bits 1..0 - tag value - event type (00 = valid touch, 10 - no touch, 11 - measurement in progress) + */ + + // Was there a valid touch? + if ((pt->x & 0x03) == 0x02) { + pdr->z = Z_MIN; + return TRUE; + } + + // Strip the tags + pt->x >>= 4; + pt->y >>= 4; + pdr->z = Z_MAX; + + return TRUE; +} + +const GMouseVMT const GMOUSE_DRIVER_VMT[1] = {{ + { + GDRIVER_TYPE_TOUCH, + GMOUSE_VFLG_TOUCH | GMOUSE_VFLG_ONLY_DOWN | GMOUSE_VFLG_POORUPDOWN | GMOUSE_VFLG_CALIBRATE | GMOUSE_VFLG_CAL_TEST, + sizeof(GMouse) + GMOUSE_MAX11802_BOARD_DATA_SIZE, + _gmouseInitDriver, + _gmousePostInitDriver, + _gmouseDeInitDriver + }, + Z_MAX, // z_max + Z_MIN, // z_min + Z_MIN, // z_touchoff + Z_MAX, // z_touchon + { // pen_jitter + GMOUSE_MAX11802_PEN_CALIBRATE_ERROR, // calibrate + GMOUSE_MAX11802_PEN_CLICK_ERROR, // click + GMOUSE_MAX11802_PEN_MOVE_ERROR // move + }, + { // finger_jitter + GMOUSE_MAX11802_FINGER_CALIBRATE_ERROR, // calibrate + GMOUSE_MAX11802_FINGER_CLICK_ERROR, // click + GMOUSE_MAX11802_FINGER_MOVE_ERROR // move + }, + MouseInit, // init + 0, // deinit + read_xyz, // get + 0, // calsave + 0 // calload +}}; + +#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */ diff --git a/drivers/ginput/touch/MAX11802/gmouse_lld_MAX11802_board_template.h b/drivers/ginput/touch/MAX11802/gmouse_lld_MAX11802_board_template.h new file mode 100644 index 00000000..6171089f --- /dev/null +++ b/drivers/ginput/touch/MAX11802/gmouse_lld_MAX11802_board_template.h @@ -0,0 +1,69 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _GINPUT_LLD_MOUSE_BOARD_H +#define _GINPUT_LLD_MOUSE_BOARD_H + +// Resolution and Accuracy Settings +#define GMOUSE_MAX11802_PEN_CALIBRATE_ERROR 8 +#define GMOUSE_MAX11802_PEN_CLICK_ERROR 6 +#define GMOUSE_MAX11802_PEN_MOVE_ERROR 4 +#define GMOUSE_MAX11802_FINGER_CALIBRATE_ERROR 14 +#define GMOUSE_MAX11802_FINGER_CLICK_ERROR 18 +#define GMOUSE_MAX11802_FINGER_MOVE_ERROR 14 + +// How much extra data to allocate at the end of the GMouse structure for the board's use +#define GMOUSE_MAX11802_BOARD_DATA_SIZE 0 + +/** + * Init the board + * + * Returns TRUE on success, FALSE on failure + */ +static inline bool_t init_board(GMouse* m, unsigned driverinstance) { + +} + +/** + * Acquire the bus + */ +static inline void aquire_bus(GMouse* m) { + +} + +/** + * Release the bus + */ +static inline void release_bus(GMouse* m) { + +} + +/** + * Send command (with parameter) to the MAX11802 + * + * Return the second byte read in case of interest + */ +static inline uint8_t write_command(GMouse* m, uint8_t command, uint8_t value) { +} + +/** + * Send command (no parameter) to the MAX11802 + * + * Return the byte read in case of interest + */ +static inline uint8_t gfintWriteCommand(GMouse* m, uint8_t command) { +} + +/* + * Read 2 bytes as 16-bit value (command to read must have been sent previously) + * Note: Analog value is in bits 15..4, tags (reading status) in bits 3..0 +*/ +static inline uint16_t read_value(GMouse* m) { + +} + +#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ diff --git a/drivers/ginput/touch/MAX11802/max11802.h b/drivers/ginput/touch/MAX11802/max11802.h new file mode 100644 index 00000000..2266bfa1 --- /dev/null +++ b/drivers/ginput/touch/MAX11802/max11802.h @@ -0,0 +1,31 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _MAX11802_H +#define _MAX11802_H + +#define MAX11802_CMD_XPOSITION ((0x52 << 1) | 1) +#define MAX11802_CMD_YPOSITION ((0x54 << 1) | 1) +#define MAX11802_CMD_ZPOSITION ((0x56 << 1) | 1) + +// LSB of register addresses specifies read (1) or write (0) +#define MAX11802_CMD_MEASUREXY (0x70 << 1) +#define MAX11802_CMD_MEASUREXYZ (0x72 << 1) +#define MAX11802_CMD_GEN_WR (0x01 << 1) // General config register +#define MAX11802_CMD_RES_WR (0x02 << 1) +#define MAX11802_CMD_AVG_WR (0x03 << 1) +#define MAX11802_CMD_SAMPLE_WR (0x04 << 1) +#define MAX11802_CMD_TIMING_WR (0x05 << 1) +#define MAX11802_CMD_DELAY_WR (0x06 << 1) +#define MAX11802_CMD_TDPULL_WR (0x07 << 1) +#define MAX11802_CMD_MDTIM_WR (0x08 << 1) +#define MAX11802_CMD_APCONF_WR (0x09 << 1) +#define MAX11802_CMD_MODE_WR (0x0B << 1) +#define MAX11802_CMD_MODE_RD ((0x0B << 1) | 1) +#define MAX11802_CMD_GSR_RD ((0x00 << 1) | 1) // General status register - read-only + +#endif /* _MAX11802_H */ diff --git a/drivers/ginput/touch/MCU/driver.mk b/drivers/ginput/touch/MCU/driver.mk index e771236a..c8c792b2 100644 --- a/drivers/ginput/touch/MCU/driver.mk +++ b/drivers/ginput/touch/MCU/driver.mk @@ -1,5 +1,2 @@ # List the required driver. -GFXSRC += $(GFXLIB)/drivers/ginput/touch/MCU/ginput_lld_mouse.c - -# Required include directories -GFXINC += $(GFXLIB)/drivers/ginput/touch/MCU +GFXSRC += $(GFXLIB)/drivers/ginput/touch/MCU/gmouse_lld_MCU.c diff --git a/drivers/ginput/touch/MCU/ginput_lld_mouse.c b/drivers/ginput/touch/MCU/ginput_lld_mouse.c deleted file mode 100644 index ad2519e4..00000000 --- a/drivers/ginput/touch/MCU/ginput_lld_mouse.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#include "gfx.h" - -#if (GFX_USE_GINPUT && GINPUT_NEED_MOUSE) /*|| defined(__DOXYGEN__)*/ - -#include "src/ginput/driver_mouse.h" - -#include "ginput_lld_mouse_board.h" - -static uint16_t sampleBuf[7]; - -static void filter(void) { - uint16_t temp; - int i,j; - - for(i = 0; i < 4; i++) { - for(j = i; j < 7; j++) { - if(sampleBuf[i] > sampleBuf[j]) { - /* Swap the values */ - temp = sampleBuf[i]; - sampleBuf[i] = sampleBuf[j]; - sampleBuf[j] = temp; - } - } - } -} - -void ginput_lld_mouse_init(void) { - init_board(); -} - -void ginput_lld_mouse_get_reading(MouseReading *pt) { - uint16_t i; - - // Obtain access to the bus - aquire_bus(); - - // Read the ADC for z, x, y and then z again - while(1) { - setup_z(); - for(i = 0; i < 7; i++) - sampleBuf[i] = read_z(); - filter(); - pt->z = (coord_t)sampleBuf[3]; - - setup_x(); - for(i = 0; i < 7; i++) - sampleBuf[i] = read_x(); - filter(); - pt->x = (coord_t)sampleBuf[3]; - - setup_y(); - for(i = 0; i < 7; i++) - sampleBuf[i] = read_y(); - filter(); - pt->y = (coord_t)sampleBuf[3]; - - pt->buttons = pt->z >= 80 ? GINPUT_TOUCH_PRESSED : 0; - - setup_z(); - for(i = 0; i < 7; i++) - sampleBuf[i] = read_z(); - filter(); - i = (coord_t)sampleBuf[3] >= 80 ? GINPUT_TOUCH_PRESSED : 0; - - if (pt->buttons == i) - break; - } - - // Release the bus - release_bus(); -} - -#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */ diff --git a/drivers/ginput/touch/MCU/ginput_lld_mouse_board_template.h b/drivers/ginput/touch/MCU/ginput_lld_mouse_board_template.h deleted file mode 100644 index e213bcb9..00000000 --- a/drivers/ginput/touch/MCU/ginput_lld_mouse_board_template.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _GINPUT_LLD_MOUSE_BOARD_H -#define _GINPUT_LLD_MOUSE_BOARD_H - -static inline void init_board(void) { -} - -static inline void aquire_bus(void) { -} - -static inline void release_bus(void) { -} - -static inline void setup_x(void) { -} - -static inline void setup_y(void) { -} - -static inline void setup_z(void) { - palClearPad(GPIOB, GPIOB_DRIVEA); - palClearPad(GPIOB, GPIOB_DRIVEB); - chThdSleepMilliseconds(2); -} - -static inline uint16_t read_x(void) { -} - -static inline uint16_t read_y(void) { -} - -static inline uint16_t read_z(void) { -} - -#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ diff --git a/drivers/ginput/touch/MCU/ginput_lld_mouse_config_template.h b/drivers/ginput/touch/MCU/ginput_lld_mouse_config_template.h deleted file mode 100644 index 328e6337..00000000 --- a/drivers/ginput/touch/MCU/ginput_lld_mouse_config_template.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _LLD_GINPUT_MOUSE_CONFIG_H -#define _LLD_GINPUT_MOUSE_CONFIG_H - -#define GINPUT_MOUSE_EVENT_TYPE GEVENT_TOUCH -#define GINPUT_MOUSE_NEED_CALIBRATION TRUE -#define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE -#define GINPUT_MOUSE_MAX_CALIBRATION_ERROR 12 -#define GINPUT_MOUSE_READ_CYCLES 1 -#define GINPUT_MOUSE_POLL_PERIOD 25 -#define GINPUT_MOUSE_MAX_CLICK_JITTER 2 -#define GINPUT_MOUSE_MAX_MOVE_JITTER 2 -#define GINPUT_MOUSE_CLICK_TIME 500 - -#endif /* _LLD_GINPUT_MOUSE_CONFIG_H */ diff --git a/drivers/ginput/touch/MCU/gmouse_lld_MCU.c b/drivers/ginput/touch/MCU/gmouse_lld_MCU.c new file mode 100644 index 00000000..babf8bc3 --- /dev/null +++ b/drivers/ginput/touch/MCU/gmouse_lld_MCU.c @@ -0,0 +1,50 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#include "gfx.h" + +#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE + +#define GMOUSE_DRIVER_VMT GMOUSEVMT_MCU +#include "src/ginput/driver_mouse.h" + +// Get the hardware interface +#include "gmouse_lld_MCU_board.h" + +const GMouseVMT const GMOUSE_DRIVER_VMT[1] = {{ + { + GDRIVER_TYPE_TOUCH, + GMOUSE_VFLG_TOUCH|GMOUSE_VFLG_CALIBRATE|GMOUSE_VFLG_CAL_TEST + |GMOUSE_VFLG_ONLY_DOWN|GMOUSE_VFLG_POORUPDOWN, + // Extra flags for testing only + //GMOUSE_VFLG_DEFAULTFINGER|GMOUSE_VFLG_CAL_EXTREMES - Possible + //GMOUSE_VFLG_NOPOLL|GMOUSE_VFLG_DYNAMICONLY|GMOUSE_VFLG_SELFROTATION|GMOUSE_VFLG_CAL_LOADFREE - unlikely + sizeof(GMouse) + GMOUSE_MCU_BOARD_DATA_SIZE, + _gmouseInitDriver, _gmousePostInitDriver, _gmouseDeInitDriver + }, + GMOUSE_MCU_Z_MAX, // z_max + GMOUSE_MCU_Z_MIN, // z_min + GMOUSE_MCU_Z_TOUCHON, // z_touchon + GMOUSE_MCU_Z_TOUCHOFF, // z_touchoff + { // pen_jitter + GMOUSE_MCU_PEN_CALIBRATE_ERROR, // calibrate + GMOUSE_MCU_PEN_CLICK_ERROR, // click + GMOUSE_MCU_PEN_MOVE_ERROR // move + }, + { // finger_jitter + GMOUSE_MCU_FINGER_CALIBRATE_ERROR, // calibrate + GMOUSE_MCU_FINGER_CLICK_ERROR, // click + GMOUSE_MCU_FINGER_MOVE_ERROR // move + }, + init_board, // init + 0, // deinit + read_xyz, // get + 0, // calsave + 0 // calload +}}; + +#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */ diff --git a/drivers/ginput/touch/MCU/gmouse_lld_MCU_board_template.h b/drivers/ginput/touch/MCU/gmouse_lld_MCU_board_template.h new file mode 100644 index 00000000..440d81fe --- /dev/null +++ b/drivers/ginput/touch/MCU/gmouse_lld_MCU_board_template.h @@ -0,0 +1,32 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _LLD_GMOUSE_MCU_BOARD_H +#define _LLD_GMOUSE_MCU_BOARD_H + +// Resolution and Accuracy Settings +#define GMOUSE_MCU_PEN_CALIBRATE_ERROR 8 +#define GMOUSE_MCU_PEN_CLICK_ERROR 6 +#define GMOUSE_MCU_PEN_MOVE_ERROR 4 +#define GMOUSE_MCU_FINGER_CALIBRATE_ERROR 14 +#define GMOUSE_MCU_FINGER_CLICK_ERROR 18 +#define GMOUSE_MCU_FINGER_MOVE_ERROR 14 +#define GMOUSE_MCU_Z_MIN 0 // The minimum Z reading +#define GMOUSE_MCU_Z_MAX 100 // The maximum Z reading +#define GMOUSE_MCU_Z_TOUCHON 80 // Values between this and Z_MAX are definitely pressed +#define GMOUSE_MCU_Z_TOUCHOFF 70 // Values between this and Z_MIN are definitely not pressed + +// How much extra data to allocate at the end of the GMouse structure for the board's use +#define GMOUSE_MCU_BOARD_DATA_SIZE 0 + +static bool_t init_board(GMouse *m, unsigned driverinstance) { +} + +static bool_t read_xyz(GMouse *m, GMouseReading *prd) { +} + +#endif /* _LLD_GMOUSE_MCU_BOARD_H */ diff --git a/drivers/ginput/touch/STMPE811/driver.mk b/drivers/ginput/touch/STMPE811/driver.mk index 5147e989..cf12507b 100644 --- a/drivers/ginput/touch/STMPE811/driver.mk +++ b/drivers/ginput/touch/STMPE811/driver.mk @@ -1,5 +1,2 @@ # List the required driver. -GFXSRC += $(GFXLIB)/drivers/ginput/touch/STMPE811/ginput_lld_mouse.c - -# Required include directories -GFXINC += $(GFXLIB)/drivers/ginput/touch/STMPE811 +GFXSRC += $(GFXLIB)/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811.c diff --git a/drivers/ginput/touch/STMPE811/ginput_lld_mouse.c b/drivers/ginput/touch/STMPE811/ginput_lld_mouse.c deleted file mode 100644 index e658fae2..00000000 --- a/drivers/ginput/touch/STMPE811/ginput_lld_mouse.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#include "gfx.h" - -#if (GFX_USE_GINPUT && GINPUT_NEED_MOUSE) /*|| defined(__DOXYGEN__)*/ - -#include "src/ginput/driver_mouse.h" - -#include "drivers/ginput/touch/STMPE811/stmpe811.h" - -#include "ginput_lld_mouse_board.h" - -#ifndef STMP811_NO_GPIO_IRQPIN - #define STMP811_NO_GPIO_IRQPIN FALSE -#endif -#ifndef STMP811_SLOW_CPU - #define STMP811_SLOW_CPU FALSE -#endif - -static coord_t x, y, z; -static uint8_t touched; - -/* set the active window of the stmpe811. bl is bottom left, tr is top right */ -static void setActiveWindow(uint16_t bl_x, uint16_t bl_y, uint16_t tr_x, uint16_t tr_y) -{ - write_reg(STMPE811_REG_WDW_TR_X, 2, tr_x); - write_reg(STMPE811_REG_WDW_TR_Y, 2, tr_y); - write_reg(STMPE811_REG_WDW_BL_X, 2, bl_x); - write_reg(STMPE811_REG_WDW_BL_Y, 2, bl_y); -} - -void ginput_lld_mouse_init(void) -{ - init_board(); - - write_reg(STMPE811_REG_SYS_CTRL1, 1, 0x02); // Software chip reset - gfxSleepMilliseconds(10); - - write_reg(STMPE811_REG_SYS_CTRL2, 1, 0x0C); // Temperature sensor clock off, GPIO clock off, touch clock on, ADC clock on -#if STMP811_NO_GPIO_IRQPIN - write_reg(STMPE811_REG_INT_EN, 1, 0x00); // Interrupt on INT pin when touch is detected -#else - write_reg(STMPE811_REG_INT_EN, 1, 0x01); // Interrupt on INT pin when touch is detected -#endif - write_reg(STMPE811_REG_ADC_CTRL1, 1, 0x48); // ADC conversion time = 80 clock ticks, 12-bit ADC, internal voltage refernce - gfxSleepMilliseconds(2); - - write_reg(STMPE811_REG_ADC_CTRL2, 1, 0x01); // ADC speed 3.25MHz - write_reg(STMPE811_REG_GPIO_AF, 1, 0x00); // GPIO alternate function - OFF - write_reg(STMPE811_REG_TSC_CFG, 1, 0x9A); // Averaging 4, touch detect delay 500 us, panel driver settling time 500 us - write_reg(STMPE811_REG_FIFO_TH, 1, 0x40); // FIFO threshold = 64 - write_reg(STMPE811_REG_FIFO_STA, 1, 0x01); // FIFO reset enable - write_reg(STMPE811_REG_FIFO_STA, 1, 0x00); // FIFO reset disable - write_reg(STMPE811_REG_TSC_FRACT_XYZ, 1, 0x07); // Z axis data format - write_reg(STMPE811_REG_TSC_I_DRIVE, 1, 0x01); // 50mA touchscreen line current - write_reg(STMPE811_REG_TSC_CTRL, 1, 0x00); // X&Y&Z - write_reg(STMPE811_REG_TSC_CTRL, 1, 0x01); // X&Y&Z, TSC enable - write_reg(STMPE811_REG_INT_STA, 1, 0xFF); // Clear all interrupts -#if !STMP811_NO_GPIO_IRQPIN - touched = (uint8_t)read_reg(STMPE811_REG_TSC_CTRL, 1) & 0x80; -#endif - write_reg(STMPE811_REG_INT_CTRL, 1, 0x01); // Level interrupt, enable intrrupts -} - -void ginput_lld_mouse_get_reading(MouseReading *pt) -{ - bool_t clearfifo; // Do we need to clear the FIFO - -#if STMP811_NO_GPIO_IRQPIN - // Poll to get the touched status - uint8_t last_touched; - - last_touched = touched; - touched = (uint8_t)read_reg(STMPE811_REG_TSC_CTRL, 1) & 0x80; - clearfifo = (touched != last_touched); -#else - // Check if the touch controller IRQ pin has gone off - clearfifo = false; - if(getpin_irq()) { // please rename this to getpin_irq - write_reg(STMPE811_REG_INT_STA, 1, 0xFF); // clear all interrupts - touched = (uint8_t)read_reg(STMPE811_REG_TSC_CTRL, 1) & 0x80; // set the new touched status - clearfifo = true; // only take the last FIFO reading - } -#endif - - // If not touched, return the previous results - if (!touched) { - pt->x = x; - pt->y = y; - pt->z = 0; - pt->buttons = 0; - return; - } - -#if !STMP811_SLOW_CPU - if (!clearfifo && (read_reg(STMPE811_REG_FIFO_STA, 1) & 0xD0)) -#endif - clearfifo = true; - - do { - /* Get the X, Y, Z values */ - /* This could be done in a single 4 byte read to STMPE811_REG_TSC_DATA_XYZ (incr or non-incr) */ - x = (coord_t)read_reg(STMPE811_REG_TSC_DATA_X, 2); - y = (coord_t)read_reg(STMPE811_REG_TSC_DATA_Y, 2); - z = (coord_t)read_reg(STMPE811_REG_TSC_DATA_Z, 1); - } while(clearfifo && !(read_reg(STMPE811_REG_FIFO_STA, 1) & 0x20)); - - // Rescale X,Y,Z - X & Y don't need scaling when you are using calibration! -#if !GINPUT_MOUSE_NEED_CALIBRATION - x = gdispGetWidth() - x / (4096/gdispGetWidth()); - y = y / (4096/gdispGetHeight()); -#endif - z = (((z&0xFF) * 100)>>8) + 1; - - // Return the results. ADC gives values from 0 to 2^12 (4096) - pt->x = x; - pt->y = y; - pt->z = z; - pt->buttons = GINPUT_TOUCH_PRESSED; - - /* Force another read if we have more results */ - if (!clearfifo && !(read_reg(STMPE811_REG_FIFO_STA, 1) & 0x20)) - ginputMouseWakeup(); - -} - -#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */ diff --git a/drivers/ginput/touch/STMPE811/ginput_lld_mouse_board_template.h b/drivers/ginput/touch/STMPE811/ginput_lld_mouse_board_template.h deleted file mode 100644 index b7744a49..00000000 --- a/drivers/ginput/touch/STMPE811/ginput_lld_mouse_board_template.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _GINPUT_LLD_MOUSE_BOARD_H -#define _GINPUT_LLD_MOUSE_BOARD_H - -static void init_board(void) { - -} - -static inline bool_t getpin_irq(void) { - -} - -static void write_reg(uint8_t reg, uint8_t n, uint16_t val) { - -} - -static uint16_t read_reg(uint8_t reg, uint8_t n) { - -} - -#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ diff --git a/drivers/ginput/touch/STMPE811/ginput_lld_mouse_config.h b/drivers/ginput/touch/STMPE811/ginput_lld_mouse_config.h deleted file mode 100644 index 5cd512eb..00000000 --- a/drivers/ginput/touch/STMPE811/ginput_lld_mouse_config.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _LLD_GINPUT_MOUSE_CONFIG_H -#define _LLD_GINPUT_MOUSE_CONFIG_H - -#define GINPUT_MOUSE_EVENT_TYPE GEVENT_TOUCH -#define GINPUT_MOUSE_NEED_CALIBRATION TRUE -#define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE -#define GINPUT_MOUSE_MAX_CALIBRATION_ERROR 5 -#define GINPUT_MOUSE_READ_CYCLES 1 -#define GINPUT_MOUSE_POLL_PERIOD 25 -#define GINPUT_MOUSE_MAX_CLICK_JITTER 10 -#define GINPUT_MOUSE_MAX_MOVE_JITTER 5 -#define GINPUT_MOUSE_CLICK_TIME 450 - -/* default values - over write these in your boad files */ -#define STMP811_SLOWER_RESPONSE FALSE -#define STMP811_NO_GPIO_IRQPIN FALSE - -#endif /* _LLD_GINPUT_MOUSE_CONFIG_H */ diff --git a/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811.c b/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811.c new file mode 100644 index 00000000..27bc280e --- /dev/null +++ b/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811.c @@ -0,0 +1,253 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#include "gfx.h" + +#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE + +#define GMOUSE_DRIVER_VMT GMOUSEVMT_STMPE811 +#include "src/ginput/driver_mouse.h" + +// Hardware definitions +#include "drivers/ginput/touch/STMPE811/stmpe811.h" + +// Get the hardware interface +#include "gmouse_lld_STMPE811_board.h" + +// Extra settings for the users gfxconf.h file. See readme.txt +#ifndef GMOUSE_STMPE811_SELF_CALIBRATE + #define GMOUSE_STMPE811_SELF_CALIBRATE FALSE +#endif +#ifndef GMOUSE_STMPE811_READ_PRESSURE + #define GMOUSE_STMPE811_READ_PRESSURE FALSE +#endif +#ifndef GMOUSE_STMPE811_TEST_MODE + #define GMOUSE_STMPE811_TEST_MODE FALSE +#endif + +/** + * Notes: + * + * This chip has some problems which required careful coding to overcome. + * + * The interrupt pin seems to be unreliable, at least on some boards, so we at most + * use the pin for filtering results to reduce cpu load. + * The symptoms are that readings will just stop due to the irq not being asserted + * even though there are items in the fifo. Another interrupt source such as a + * touch transition will restart the irq. + * + * There is no fifo entry created when a touch up event occurs. We must therefore + * generate a pseudo result on touch up. Fortunately the touch detection appears + * reliable and so we turn off the driver GMOUSE_VFLG_POORUPDOWN setting. In practice + * if touch is up we always return a pseudo event as this saves having to remember the + * previous touch state. + * + * Z readings range from around 90 (fully touched) to around 150 (on the verge of non-touched). + * Note the above is on the STM32F429i-Discovery board. Other boards may be different. + * To be conservative we use 255 as touch off, anything else is a touch on. + * + * GMOUSE_STMPE811_TEST_MODE is designed to be used with the "touch_raw_readings" tool which shows + * a steady stream of raw readings. + * + * Settings that may need tweaking on other hardware: + * The settling times. We have set these conservatively at 1ms. + * The reading window. We set this to 16 just to reduce noise. High-res panels may need a lower value. + */ +static bool_t MouseInit(GMouse* m, unsigned driverinstance) { + if (!init_board(m, driverinstance)) + return FALSE; + + aquire_bus(m); + + write_reg(m, STMPE811_REG_SYS_CTRL1, 0x02); // Software chip reset + gfxSleepMilliseconds(10); + + write_reg(m, STMPE811_REG_SYS_CTRL2, 0x0C); // Temperature sensor clock off, GPIO clock off, touch clock on, ADC clock on + + #if GMOUSE_STMPE811_GPIO_IRQPIN + write_reg(m, STMPE811_REG_INT_EN, 0x03); // Interrupt on INT pin when there is a sample or a touch transition. + #else + write_reg(m, STMPE811_REG_INT_EN, 0x00); // Don't Interrupt on INT pin + #endif + + write_reg(m, STMPE811_REG_ADC_CTRL1, 0x48); // ADC conversion time = 80 clock ticks, 12-bit ADC, internal voltage refernce + gfxSleepMilliseconds(2); + write_reg(m, STMPE811_REG_ADC_CTRL2, 0x01); // ADC speed 3.25MHz + write_reg(m, STMPE811_REG_GPIO_AF, 0x00); // GPIO alternate function - OFF + write_reg(m, STMPE811_REG_TSC_CFG, 0xA3); // Averaging 4, touch detect delay 1ms, panel driver settling time 1ms + write_reg(m, STMPE811_REG_FIFO_TH, 0x01); // FIFO threshold = 1 + write_reg(m, STMPE811_REG_FIFO_STA, 0x01); // FIFO reset enable + write_reg(m, STMPE811_REG_FIFO_STA, 0x00); // FIFO reset disable + write_reg(m, STMPE811_REG_TSC_FRACT_XYZ, 0x07); // Z axis data format + write_reg(m, STMPE811_REG_TSC_I_DRIVE, 0x01); // max 50mA touchscreen line current + #if GMOUSE_STMPE811_READ_PRESSURE + write_reg(m, STMPE811_REG_TSC_CTRL, 0x30); // X&Y&Z, 16 reading window + write_reg(m, STMPE811_REG_TSC_CTRL, 0x31); // X&Y&Z, 16 reading window, TSC enable + #else + write_reg(m, STMPE811_REG_TSC_CTRL, 0x32); // X&Y, 16 reading window + write_reg(m, STMPE811_REG_TSC_CTRL, 0x33); // X&Y, 16 reading window, TSC enable + #endif + write_reg(m, STMPE811_REG_INT_STA, 0xFF); // Clear all interrupts + write_reg(m, STMPE811_REG_INT_CTRL, 0x01); // Level interrupt, enable interrupts + + release_bus(m); + return TRUE; +} + +static bool_t read_xyz(GMouse* m, GMouseReading* pdr) +{ + #if GMOUSE_STMPE811_TEST_MODE + static GMouseReading n; + #endif + uint8_t status; + + // Button information will be regenerated + pdr->buttons = 0; + + #if GMOUSE_STMPE811_TEST_MODE + aquire_bus(m); + + // Set the buttons to match various touch signals + if ((read_byte(m, STMPE811_REG_TSC_CTRL) & 0x80)) + pdr->buttons |= 0x02; + + status = read_byte(m, STMPE811_REG_FIFO_STA); + if (!(status & 0x20)) + pdr->buttons |= 0x04; + + #if GMOUSE_STMPE811_GPIO_IRQPIN + if (getpin_irq(m)) + pdr->buttons |= 0x08; + #endif + + if ((status & 0x20)) { + // Nothing in the fifo - just return the last position and pressure + pdr->x = n.x; + pdr->y = n.y; + pdr->z = n.z; + #if GMOUSE_STMPE811_GPIO_IRQPIN + write_reg(m, STMPE811_REG_INT_STA, 0xFF); + #endif + release_bus(m); + return TRUE; + } + + #else + // Is there a new sample or a touch transition + #if GMOUSE_STMPE811_GPIO_IRQPIN + if(!getpin_irq(m)) + return FALSE; + #endif + + // Is there something in the fifo + status = read_byte(m, STMPE811_REG_FIFO_STA); + if ((status & 0x20)) { + + // Nothing in the fifo. + + // If not touched return the pseudo result + if (!(read_byte(m, STMPE811_REG_TSC_CTRL) & 0x80)) { + + pdr->z = gmvmt(m)->z_min; + #if GMOUSE_STMPE811_GPIO_IRQPIN + write_reg(m, STMPE811_REG_INT_STA, 0xFF); + #endif + release_bus(m); + return TRUE; + } + + // No new result + #if GMOUSE_STMPE811_GPIO_IRQPIN + write_reg(m, STMPE811_REG_INT_STA, 0xFF); + #endif + release_bus(m); + return FALSE; + } + + #endif + + // Time to get some readings + pdr->x = (coord_t)read_word(m, STMPE811_REG_TSC_DATA_X); + pdr->y = (coord_t)read_word(m, STMPE811_REG_TSC_DATA_Y); + #if GMOUSE_STMPE811_READ_PRESSURE + pdr->z = (coord_t)read_byte(m, STMPE811_REG_TSC_DATA_Z); + #else + pdr->z = gmvmt(m)->z_max; + #endif + + #if !GMOUSE_STMPE811_SLOW_CPU + if (!(status & 0xC0)) { + // Is there more data to come + if (!(read_byte(m, STMPE811_REG_FIFO_STA) & 0x20)) + _gmouseWakeup(m); + } else + #endif + + // Clear the rest of the fifo + { + write_reg(m, STMPE811_REG_FIFO_STA, 0x01); // FIFO reset enable + write_reg(m, STMPE811_REG_FIFO_STA, 0x00); // FIFO reset disable + } + + // All done + #if GMOUSE_STMPE811_GPIO_IRQPIN + write_reg(m, STMPE811_REG_INT_STA, 0xFF); + #endif + release_bus(m); + + #if GMOUSE_STMPE811_TEST_MODE + // Save the result for later + n.x = pdr->x; + n.y = pdr->y; + n.z = pdr->z; + #endif + + // Rescale X,Y if we are using self-calibration + #if GMOUSE_STMPE811_SELF_CALIBRATE + pdr->x = gdispGGetWidth(m->display) - pdr->x / (4096/gdispGGetWidth(m->display)); + pdr->y = pdr->y / (4096/gdispGGetHeight(m->display)); + #endif + + return TRUE; +} + +const GMouseVMT const GMOUSE_DRIVER_VMT[1] = {{ + { + GDRIVER_TYPE_TOUCH, + #if GMOUSE_STMPE811_SELF_CALIBRATE + GMOUSE_VFLG_TOUCH | GMOUSE_VFLG_ONLY_DOWN, + #else + GMOUSE_VFLG_TOUCH | GMOUSE_VFLG_ONLY_DOWN | GMOUSE_VFLG_CALIBRATE | GMOUSE_VFLG_CAL_TEST, + #endif + sizeof(GMouse) + GMOUSE_STMPE811_BOARD_DATA_SIZE, + _gmouseInitDriver, + _gmousePostInitDriver, + _gmouseDeInitDriver + }, + 0, // z_max - 0 indicates full touch + 255, // z_min + 150, // z_touchon + 255, // z_touchoff + { // pen_jitter + GMOUSE_STMPE811_PEN_CALIBRATE_ERROR, // calibrate + GMOUSE_STMPE811_PEN_CLICK_ERROR, // click + GMOUSE_STMPE811_PEN_MOVE_ERROR // move + }, + { // finger_jitter + GMOUSE_STMPE811_FINGER_CALIBRATE_ERROR, // calibrate + GMOUSE_STMPE811_FINGER_CLICK_ERROR, // click + GMOUSE_STMPE811_FINGER_MOVE_ERROR // move + }, + MouseInit, // init + 0, // deinit + read_xyz, // get + 0, // calsave + 0 // calload +}}; + +#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */ + diff --git a/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811_board_template.h b/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811_board_template.h new file mode 100644 index 00000000..4520cf67 --- /dev/null +++ b/drivers/ginput/touch/STMPE811/gmouse_lld_STMPE811_board_template.h @@ -0,0 +1,60 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _GINPUT_LLD_MOUSE_BOARD_H +#define _GINPUT_LLD_MOUSE_BOARD_H + +// Resolution and Accuracy Settings +#define GMOUSE_STMPE811_PEN_CALIBRATE_ERROR 8 +#define GMOUSE_STMPE811_PEN_CLICK_ERROR 6 +#define GMOUSE_STMPE811_PEN_MOVE_ERROR 4 +#define GMOUSE_STMPE811_FINGER_CALIBRATE_ERROR 14 +#define GMOUSE_STMPE811_FINGER_CLICK_ERROR 18 +#define GMOUSE_STMPE811_FINGER_MOVE_ERROR 14 + +// How much extra data to allocate at the end of the GMouse structure for the board's use +#define GMOUSE_STMPE811_BOARD_DATA_SIZE 0 + +// Options - Leave these commented to make it user configurable in the gfxconf.h +//#define GMOUSE_STMPE811_READ_PRESSURE FALSE +//#define GMOUSE_STMPE811_SELF_CALIBRATE FALSE +//#define GMOUSE_STMPE811_TEST_MODE FALSE + +// If TRUE this board has the STMPE811 IRQ pin connected to a GPIO. +// Note: For tested hardware this is unreliable and should be set to FALSE until tested. +// Symptoms are that mouse readings just appear to stop for a bit. Lifting the touch +// and re-applying the touch cause readings to start again. +#define GMOUSE_STMPE811_GPIO_IRQPIN FALSE + +// If TRUE this is a really slow CPU and we should always clear the FIFO between reads. +#define GMOUSE_STMPE811_SLOW_CPU FALSE + +static bool_t init_board(GMouse* m, unsigned driverinstance) { +} + +#if GMOUSE_STMPE811_GPIO_IRQPIN + static bool_t getpin_irq(GMouse* m) { + + } +#endif + +static inline void aquire_bus(GMouse* m) { +} + +static inline void release_bus(GMouse* m) { +} + +static void write_reg(GMouse* m, uint8_t reg, uint8_t val) { +} + +static uint8_t read_byte(GMouse* m, uint8_t reg) { +} + +static uint16_t read_word(GMouse* m, uint8_t reg) { +} + +#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ diff --git a/drivers/ginput/touch/STMPE811/readme.txt b/drivers/ginput/touch/STMPE811/readme.txt new file mode 100644 index 00000000..60d7f603 --- /dev/null +++ b/drivers/ginput/touch/STMPE811/readme.txt @@ -0,0 +1,11 @@ +This driver has a number of optional settings which can be specified in gfxconf.h: + +#define GMOUSE_STMPE811_READ_PRESSURE TRUE + Returns pressure values when the touch is down. On tested boards this ranges from 90 to 150. 255 is touch off. + +#define GMOUSE_STMPE811_SELF_CALIBRATE TRUE + Scale the touch readings to avoid calibration. This is not as accurate as real calibration. + +#define GMOUSE_STMPE811_TEST_MODE TRUE + Return raw readings for diagnostic use with the "touch_raw_readings" tool. + diff --git a/drivers/ginput/touch/STMPE811/stmpe811.h b/drivers/ginput/touch/STMPE811/stmpe811.h index 1ee9c211..df85889f 100644 --- a/drivers/ginput/touch/STMPE811/stmpe811.h +++ b/drivers/ginput/touch/STMPE811/stmpe811.h @@ -8,12 +8,6 @@ #ifndef _STMPE811_H #define _STMPE811_H -// Slave address -#define STMPE811_ADDR (0x82 >> 1) - -// Maximum timeout -#define STMPE811_TIMEOUT 0x3000 - // Identification registers #define STMPE811_REG_CHP_ID 0x00 // 16-bit #define STMPE811_REG_ID_VER 0x02 diff --git a/drivers/multiple/Win32/gdisp_lld_Win32.c b/drivers/multiple/Win32/gdisp_lld_Win32.c index 3643d727..13c5e544 100644 --- a/drivers/multiple/Win32/gdisp_lld_Win32.c +++ b/drivers/multiple/Win32/gdisp_lld_Win32.c @@ -10,7 +10,7 @@ #if GFX_USE_GDISP #define GDISP_DRIVER_VMT GDISPVMT_Win32 -#include "drivers/multiple/Win32/gdisp_lld_config.h" +#include "gdisp_lld_config.h" #include "src/gdisp/driver.h" #ifndef GDISP_SCREEN_WIDTH @@ -52,7 +52,6 @@ #define GDISP_FLG_READY (GDISP_FLG_DRIVER<<0) #define GDISP_FLG_HASTOGGLE (GDISP_FLG_DRIVER<<1) -#define GDISP_FLG_HASMOUSE (GDISP_FLG_DRIVER<<2) #if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ #define GDISP_FLG_WSTREAM (GDISP_FLG_DRIVER<<3) #define GDISP_FLG_WRAPPED (GDISP_FLG_DRIVER<<4) @@ -64,16 +63,50 @@ #endif #if GINPUT_NEED_MOUSE - /* Include mouse support code */ + // Include mouse support code + #define GMOUSE_DRIVER_VMT GMOUSEVMT_Win32 #include "src/ginput/driver_mouse.h" + + // Forward definitions + static bool_t Win32MouseInit(GMouse *m, unsigned driverinstance); + static bool_t Win32MouseRead(GMouse *m, GMouseReading *prd); + + const GMouseVMT const GMOUSE_DRIVER_VMT[1] = {{ + { + GDRIVER_TYPE_MOUSE, + GMOUSE_VFLG_NOPOLL|GMOUSE_VFLG_DYNAMICONLY, + // Extra flags for testing only + //GMOUSE_VFLG_TOUCH|GMOUSE_VFLG_SELFROTATION|GMOUSE_VFLG_DEFAULTFINGER + //GMOUSE_VFLG_CALIBRATE|GMOUSE_VFLG_CAL_EXTREMES|GMOUSE_VFLG_CAL_TEST|GMOUSE_VFLG_CAL_LOADFREE + //GMOUSE_VFLG_ONLY_DOWN|GMOUSE_VFLG_POORUPDOWN + sizeof(GMouse), + _gmouseInitDriver, _gmousePostInitDriver, _gmouseDeInitDriver + }, + 1, // z_max + 0, // z_min + 1, // z_touchon + 0, // z_touchoff + { // pen_jitter + 0, // calibrate + 0, // click + 0 // move + }, + { // finger_jitter + 0, // calibrate + 2, // click + 2 // move + }, + Win32MouseInit, // init + 0, // deinit + Win32MouseRead, // get + 0, // calsave + 0 // calload + }}; #endif static DWORD winThreadId; static volatile bool_t QReady; static HANDLE drawMutex; -#if GINPUT_NEED_MOUSE - static GDisplay * mouseDisplay; -#endif /*===========================================================================*/ /* Driver local routines . */ @@ -95,6 +128,7 @@ typedef struct winPriv { #if GINPUT_NEED_MOUSE coord_t mousex, mousey; uint16_t mousebuttons; + GMouse *mouse; #endif #if GINPUT_NEED_TOGGLE uint8_t toggles; @@ -149,7 +183,7 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) // Handle mouse down on the window #if GINPUT_NEED_MOUSE - if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) { priv->mousebuttons |= GINPUT_MOUSE_BTN_LEFT; goto mousemove; } @@ -198,7 +232,7 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) // Handle mouse up on the window #if GINPUT_NEED_MOUSE - if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) { priv->mousebuttons &= ~GINPUT_MOUSE_BTN_LEFT; goto mousemove; } @@ -210,7 +244,7 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) case WM_MBUTTONDOWN: g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); priv = (winPriv *)g->priv; - if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) { priv->mousebuttons |= GINPUT_MOUSE_BTN_MIDDLE; goto mousemove; } @@ -218,7 +252,7 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) case WM_MBUTTONUP: g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); priv = (winPriv *)g->priv; - if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) { priv->mousebuttons &= ~GINPUT_MOUSE_BTN_MIDDLE; goto mousemove; } @@ -226,7 +260,7 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) case WM_RBUTTONDOWN: g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); priv = (winPriv *)g->priv; - if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) { priv->mousebuttons |= GINPUT_MOUSE_BTN_RIGHT; goto mousemove; } @@ -234,7 +268,7 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) case WM_RBUTTONUP: g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); priv = (winPriv *)g->priv; - if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) { priv->mousebuttons &= ~GINPUT_MOUSE_BTN_RIGHT; goto mousemove; } @@ -242,14 +276,13 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) case WM_MOUSEMOVE: g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); priv = (winPriv *)g->priv; - if ((coord_t)HIWORD(lParam) >= GDISP_SCREEN_HEIGHT || !(g->flags & GDISP_FLG_HASMOUSE)) + if ((coord_t)HIWORD(lParam) >= GDISP_SCREEN_HEIGHT) break; mousemove: priv->mousex = (coord_t)LOWORD(lParam); priv->mousey = (coord_t)HIWORD(lParam); - #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE - ginputMouseWakeup(); - #endif + if ((gmvmt(priv->mouse)->d.flags & GMOUSE_VFLG_NOPOLL)) // For normal setup this is always TRUE + _gmouseWakeup(priv->mouse); break; #endif @@ -445,14 +478,6 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { g->flags |= GDISP_FLG_HASTOGGLE; #endif - // Only turn on mouse on the first window for now - #if GINPUT_NEED_MOUSE - if (!g->controllerdisplay) { - mouseDisplay = g; - g->flags |= GDISP_FLG_HASMOUSE; - } - #endif - // Create a private area for this window priv = gfxAlloc(sizeof(winPriv)); assert(priv != 0); @@ -471,6 +496,11 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { while(!(((volatile GDisplay *)g)->flags & GDISP_FLG_READY)) Sleep(1); + // Create the associated mouse + #if GINPUT_NEED_MOUSE + priv->mouse = (GMouse *)gdriverRegister((const GDriverVMT const *)GMOUSE_DRIVER_VMT, g); + #endif + sprintf(buf, APP_NAME " - %u", g->systemdisplay+1); SetWindowText(priv->hwnd, buf); ShowWindow(priv->hwnd, SW_SHOW); @@ -686,10 +716,10 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { winPriv * priv; int x, y; COLORREF color; - + priv = g->priv; color = gdispColor2Native(g->p.color); - + #if GDISP_NEED_CONTROL switch(g->g.Orientation) { case GDISP_ROTATE_0: @@ -818,7 +848,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { sz = (size_t)g->p.cx * (size_t)g->p.cy; if (!(dstbuf = (pixel_t *)malloc(sz * sizeof(pixel_t)))) return 0; - + // Copy the bits we need switch(g->g.Orientation) { case GDISP_ROTATE_0: @@ -847,7 +877,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { return dstbuf; } #endif - + #if GDISP_HARDWARE_BITFILLS #if COLOR_SYSTEM != GDISP_COLORSYSTEM_TRUECOLOR || COLOR_TYPE_BITS <= 8 #error "GDISP Win32: This driver's bitblit currently only supports true-color with bit depths > 8 bits." @@ -863,7 +893,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { priv = g->priv; buffer = g->p.ptr; buffer += g->p.x2*g->p.y1; - + memset(&bmpInfo, 0, sizeof(bmpInfo)); bmpInfo.bV4Size = sizeof(bmpInfo); bmpInfo.bV4Planes = 1; @@ -982,7 +1012,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { color = GetPixel(priv->dcBuffer, g->p.x, g->p.y); #endif ReleaseMutex(drawMutex); - + return gdispNative2Color(color); } #endif @@ -992,7 +1022,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { winPriv * priv; RECT rect; coord_t lines; - + priv = g->priv; #if GDISP_NEED_CONTROL @@ -1134,18 +1164,51 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #endif #if GINPUT_NEED_MOUSE - void ginput_lld_mouse_init(void) {} - void ginput_lld_mouse_get_reading(MouseReading *pt) { + static bool_t Win32MouseInit(GMouse *m, unsigned driverinstance) { + (void) m; + (void) driverinstance; + return TRUE; + } + static bool_t Win32MouseRead(GMouse *m, GMouseReading *pt) { GDisplay * g; winPriv * priv; - g = mouseDisplay; + g = m->display; priv = g->priv; pt->x = priv->mousex; - pt->y = priv->mousey > g->g.Height ? g->g.Height : priv->mousey; - pt->z = (priv->mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 100 : 0; + pt->y = priv->mousey; + pt->z = (priv->mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 1 : 0; pt->buttons = priv->mousebuttons; + + #if GDISP_NEED_CONTROL + // If the self-rotation has been set in the VMT then do that here (TESTING ONLY) + if ((gmvmt(m)->d.flags & GMOUSE_VFLG_SELFROTATION)) { // For normal setup this is always False + coord_t t; + + switch(gdispGGetOrientation(m->display)) { + case GDISP_ROTATE_0: + default: + break; + case GDISP_ROTATE_90: + t = pt->x; + pt->x = g->g.Width - 1 - pt->y; + pt->y = t; + break; + case GDISP_ROTATE_180: + pt->x = g->g.Width - 1 - pt->x; + pt->y = g->g.Height - 1 - pt->y; + break; + case GDISP_ROTATE_270: + t = pt->y; + pt->y = g->g.Height - 1 - pt->x; + pt->x = t; + break; + } + } + #endif + + return TRUE; } #endif /* GINPUT_NEED_MOUSE */ diff --git a/drivers/multiple/Win32/ginput_lld_mouse_config.h b/drivers/multiple/Win32/ginput_lld_mouse_config.h deleted file mode 100644 index 8263ebed..00000000 --- a/drivers/multiple/Win32/ginput_lld_mouse_config.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _LLD_GINPUT_MOUSE_CONFIG_H -#define _LLD_GINPUT_MOUSE_CONFIG_H - -// This driver supports being both a mouse or a touch device (we don't actually know which it really is) -// When operating in mouse mode a long left button click does not generate a context click. -// When operating in touch mode we allow sloppier clicks etc -#if 1 - #define GINPUT_MOUSE_EVENT_TYPE GEVENT_MOUSE - #define GINPUT_MOUSE_CLICK_TIME TIME_INFINITE // Long click != Context Click - #define GINPUT_MOUSE_NEED_CALIBRATION FALSE - #define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE - #define GINPUT_MOUSE_READ_CYCLES 1 - #define GINPUT_MOUSE_MAX_CALIBRATION_ERROR -1 - #define GINPUT_MOUSE_MAX_CLICK_JITTER 0 - #define GINPUT_MOUSE_MAX_MOVE_JITTER 0 -#else - #define GINPUT_MOUSE_EVENT_TYPE GEVENT_TOUCH - #define GINPUT_MOUSE_CLICK_TIME 700 // Long click = Context Click - #define GINPUT_MOUSE_NEED_CALIBRATION FALSE // Can be set to TRUE just for testing - #define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE - #define GINPUT_MOUSE_READ_CYCLES 1 - #define GINPUT_MOUSE_MAX_CALIBRATION_ERROR 2 - #define GINPUT_MOUSE_MAX_CLICK_JITTER 2 - #define GINPUT_MOUSE_MAX_MOVE_JITTER 2 -#endif - -// This driver supports both an "interrupt" mode, and a polled mode -#define GINPUT_MOUSE_POLL_PERIOD TIME_INFINITE // Interrupt driven by the Window thread -//#define GINPUT_MOUSE_POLL_PERIOD 25 // Poll driven - -#endif /* _LLD_GINPUT_MOUSE_CONFIG_H */ diff --git a/drivers/multiple/X/gdisp_lld_X.c b/drivers/multiple/X/gdisp_lld_X.c index 35cf250d..d62f52e6 100644 --- a/drivers/multiple/X/gdisp_lld_X.c +++ b/drivers/multiple/X/gdisp_lld_X.c @@ -10,7 +10,7 @@ #if GFX_USE_GDISP #define GDISP_DRIVER_VMT GDISPVMT_X11 -#include "drivers/multiple/X/gdisp_lld_config.h" +#include "gdisp_lld_config.h" #include "src/gdisp/driver.h" #ifndef GDISP_FORCE_24BIT @@ -27,8 +27,45 @@ #define GDISP_FLG_READY (GDISP_FLG_DRIVER<<0) #if GINPUT_NEED_MOUSE - /* Include mouse support code */ + // Include mouse support code + #define GMOUSE_DRIVER_VMT GMOUSEVMT_X11 #include "src/ginput/driver_mouse.h" + + // Forward definitions + static bool_t XMouseInit(GMouse *m, unsigned driverinstance); + static bool_t XMouseRead(GMouse *m, GMouseReading *prd); + + const GMouseVMT const GMOUSE_DRIVER_VMT[1] = {{ + { + GDRIVER_TYPE_MOUSE, + GMOUSE_VFLG_NOPOLL|GMOUSE_VFLG_DYNAMICONLY, + // Extra flags for testing only + //GMOUSE_VFLG_TOUCH|GMOUSE_VFLG_SELFROTATION|GMOUSE_VFLG_DEFAULTFINGER + //GMOUSE_VFLG_CALIBRATE|GMOUSE_VFLG_CAL_EXTREMES|GMOUSE_VFLG_CAL_TEST|GMOUSE_VFLG_CAL_LOADFREE + //GMOUSE_VFLG_ONLY_DOWN|GMOUSE_VFLG_POORUPDOWN + sizeof(GMouse), + _gmouseInitDriver, _gmousePostInitDriver, _gmouseDeInitDriver + }, + 1, // z_max + 0, // z_min + 1, // z_touchon + 0, // z_touchoff + { // pen_jitter + 0, // calibrate + 0, // click + 0 // move + }, + { // finger_jitter + 0, // calibrate + 2, // click + 2 // move + }, + XMouseInit, // init + 0, // deinit + XMouseRead, // get + 0, // calsave + 0 // calload + }}; #endif #include @@ -45,15 +82,16 @@ static Colormap cmap; static XVisualInfo vis; static XContext cxt; static Atom wmDelete; -#if GINPUT_NEED_MOUSE - static coord_t mousex, mousey; - static uint16_t mousebuttons; -#endif typedef struct xPriv { Pixmap pix; GC gc; Window win; + #if GINPUT_NEED_MOUSE + coord_t mousex, mousey; + uint16_t buttons; + GMouse * mouse; + #endif } xPriv; static void ProcessEvent(GDisplay *g, xPriv *priv) { @@ -80,37 +118,31 @@ static void ProcessEvent(GDisplay *g, xPriv *priv) { break; #if GINPUT_NEED_MOUSE case ButtonPress: - mousex = evt.xbutton.x; - mousey = evt.xbutton.y; + priv->mousex = evt.xbutton.x; + priv->mousey = evt.xbutton.y; switch(evt.xbutton.button){ - case 1: mousebuttons |= GINPUT_MOUSE_BTN_LEFT; break; - case 2: mousebuttons |= GINPUT_MOUSE_BTN_MIDDLE; break; - case 3: mousebuttons |= GINPUT_MOUSE_BTN_RIGHT; break; - case 4: mousebuttons |= GINPUT_MOUSE_BTN_4; break; + case 1: priv->buttons |= GINPUT_MOUSE_BTN_LEFT; break; + case 2: priv->buttons |= GINPUT_MOUSE_BTN_MIDDLE; break; + case 3: priv->buttons |= GINPUT_MOUSE_BTN_RIGHT; break; + case 4: priv->buttons |= GINPUT_MOUSE_BTN_4; break; } - #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE - ginputMouseWakeup(); - #endif + _gmouseWakeup(priv->mouse); break; case ButtonRelease: - mousex = evt.xbutton.x; - mousey = evt.xbutton.y; + priv->mousex = evt.xbutton.x; + priv->mousey = evt.xbutton.y; switch(evt.xbutton.button){ - case 1: mousebuttons &= ~GINPUT_MOUSE_BTN_LEFT; break; - case 2: mousebuttons &= ~GINPUT_MOUSE_BTN_MIDDLE; break; - case 3: mousebuttons &= ~GINPUT_MOUSE_BTN_RIGHT; break; - case 4: mousebuttons &= ~GINPUT_MOUSE_BTN_4; break; + case 1: priv->buttons &= ~GINPUT_MOUSE_BTN_LEFT; break; + case 2: priv->buttons &= ~GINPUT_MOUSE_BTN_MIDDLE; break; + case 3: priv->buttons &= ~GINPUT_MOUSE_BTN_RIGHT; break; + case 4: priv->buttons &= ~GINPUT_MOUSE_BTN_4; break; } - #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE - ginputMouseWakeup(); - #endif + _gmouseWakeup(priv->mouse); break; case MotionNotify: - mousex = evt.xmotion.x; - mousey = evt.xmotion.y; - #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE - ginputMouseWakeup(); - #endif + priv->mousex = evt.xmotion.x; + priv->mousey = evt.xmotion.y; + _gmouseWakeup(priv->mouse); break; #endif } @@ -231,6 +263,11 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { XSetBackground(dis, priv->gc, BlackPixel(dis, scr)); XSync(dis, TRUE); + // Create the associated mouse before the map + #if GINPUT_NEED_MOUSE + priv->mouse = (GMouse *)gdriverRegister((const GDriverVMT const *)GMOUSE_DRIVER_VMT, g); + #endif + XSelectInput(dis, priv->win, StructureNotifyMask); XMapWindow(dis, priv->win); @@ -322,16 +359,21 @@ LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) #endif #if GINPUT_NEED_MOUSE - - void ginput_lld_mouse_init(void) {} - - void ginput_lld_mouse_get_reading(MouseReading *pt) { - pt->x = mousex; - pt->y = mousey; - pt->z = (mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 100 : 0; - pt->buttons = mousebuttons; + static bool_t XMouseInit(GMouse *m, unsigned driverinstance) { + (void) m; + (void) driverinstance; + return TRUE; } + static bool_t XMouseRead(GMouse *m, GMouseReading *pt) { + xPriv * priv; + priv = m->display->priv; + pt->x = priv->mousex; + pt->y = priv->mousey; + pt->z = (priv->buttons & GINPUT_MOUSE_BTN_LEFT) ? 1 : 0; + pt->buttons = priv->buttons; + return TRUE; + } #endif /* GINPUT_NEED_MOUSE */ #endif /* GFX_USE_GDISP */ diff --git a/drivers/multiple/X/ginput_lld_mouse_config.h b/drivers/multiple/X/ginput_lld_mouse_config.h deleted file mode 100644 index 8263ebed..00000000 --- a/drivers/multiple/X/ginput_lld_mouse_config.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _LLD_GINPUT_MOUSE_CONFIG_H -#define _LLD_GINPUT_MOUSE_CONFIG_H - -// This driver supports being both a mouse or a touch device (we don't actually know which it really is) -// When operating in mouse mode a long left button click does not generate a context click. -// When operating in touch mode we allow sloppier clicks etc -#if 1 - #define GINPUT_MOUSE_EVENT_TYPE GEVENT_MOUSE - #define GINPUT_MOUSE_CLICK_TIME TIME_INFINITE // Long click != Context Click - #define GINPUT_MOUSE_NEED_CALIBRATION FALSE - #define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE - #define GINPUT_MOUSE_READ_CYCLES 1 - #define GINPUT_MOUSE_MAX_CALIBRATION_ERROR -1 - #define GINPUT_MOUSE_MAX_CLICK_JITTER 0 - #define GINPUT_MOUSE_MAX_MOVE_JITTER 0 -#else - #define GINPUT_MOUSE_EVENT_TYPE GEVENT_TOUCH - #define GINPUT_MOUSE_CLICK_TIME 700 // Long click = Context Click - #define GINPUT_MOUSE_NEED_CALIBRATION FALSE // Can be set to TRUE just for testing - #define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE - #define GINPUT_MOUSE_READ_CYCLES 1 - #define GINPUT_MOUSE_MAX_CALIBRATION_ERROR 2 - #define GINPUT_MOUSE_MAX_CLICK_JITTER 2 - #define GINPUT_MOUSE_MAX_MOVE_JITTER 2 -#endif - -// This driver supports both an "interrupt" mode, and a polled mode -#define GINPUT_MOUSE_POLL_PERIOD TIME_INFINITE // Interrupt driven by the Window thread -//#define GINPUT_MOUSE_POLL_PERIOD 25 // Poll driven - -#endif /* _LLD_GINPUT_MOUSE_CONFIG_H */ diff --git a/drivers/multiple/uGFXnet/gdisp_lld_uGFXnet.c b/drivers/multiple/uGFXnet/gdisp_lld_uGFXnet.c index 82c0e2ff..3b42bcda 100644 --- a/drivers/multiple/uGFXnet/gdisp_lld_uGFXnet.c +++ b/drivers/multiple/uGFXnet/gdisp_lld_uGFXnet.c @@ -10,7 +10,7 @@ #if GFX_USE_GDISP #define GDISP_DRIVER_VMT GDISPVMT_uGFXnet -#include "drivers/multiple/uGFXnet/gdisp_lld_config.h" +#include "gdisp_lld_config.h" #include "src/gdisp/driver.h" #include "uGFXnetProtocol.h" @@ -33,6 +33,48 @@ #define GDISP_GFXNET_BROKEN_LWIP_ACCEPT FALSE #endif +#if GINPUT_NEED_MOUSE + // Include mouse support code + #define GMOUSE_DRIVER_VMT GMOUSEVMT_uGFXnet + #include "src/ginput/driver_mouse.h" + + // Forward definitions + static bool_t NMouseInit(GMouse *m, unsigned driverinstance); + static bool_t NMouseRead(GMouse *m, GMouseReading *prd); + + const GMouseVMT const GMOUSE_DRIVER_VMT[1] = {{ + { + GDRIVER_TYPE_MOUSE, + GMOUSE_VFLG_NOPOLL|GMOUSE_VFLG_DYNAMICONLY, + // Extra flags for testing only + //GMOUSE_VFLG_TOUCH|GMOUSE_VFLG_SELFROTATION|GMOUSE_VFLG_DEFAULTFINGER + //GMOUSE_VFLG_CALIBRATE|GMOUSE_VFLG_CAL_EXTREMES|GMOUSE_VFLG_CAL_TEST|GMOUSE_VFLG_CAL_LOADFREE + //GMOUSE_VFLG_ONLY_DOWN|GMOUSE_VFLG_POORUPDOWN + sizeof(GMouse), + _gmouseInitDriver, _gmousePostInitDriver, _gmouseDeInitDriver + }, + 1, // z_max + 0, // z_min + 1, // z_touchon + 0, // z_touchoff + { // pen_jitter + 0, // calibrate + 0, // click + 0 // move + }, + { // finger_jitter + 0, // calibrate + 2, // click + 2 // move + }, + NMouseInit, // init + 0, // deinit + NMouseRead, // get + 0, // calsave + 0 // calload + }}; +#endif + #if GNETCODE_VERSION != GNETCODE_VERSION_1_0 #error "GDISP: uGFXnet - This driver only support protocol V1.0" #endif @@ -98,14 +140,8 @@ #endif #endif -#define GDISP_FLG_HASMOUSE (GDISP_FLG_DRIVER<<0) -#define GDISP_FLG_CONNECTED (GDISP_FLG_DRIVER<<1) -#define GDISP_FLG_HAVEDATA (GDISP_FLG_DRIVER<<2) - -#if GINPUT_NEED_MOUSE - /* Include mouse support code */ - #include "src/ginput/driver_mouse.h" -#endif +#define GDISP_FLG_CONNECTED (GDISP_FLG_DRIVER<<0) +#define GDISP_FLG_HAVEDATA (GDISP_FLG_DRIVER<<1) /*===========================================================================*/ /* Driver local routines . */ @@ -118,15 +154,12 @@ typedef struct netPriv { #if GINPUT_NEED_MOUSE coord_t mousex, mousey; uint16_t mousebuttons; + GMouse * mouse; #endif } netPriv; static gfxThreadHandle hThread; -#if GINPUT_NEED_MOUSE - static GDisplay * mouseDisplay; -#endif - #if GDISP_GFXNET_UNSAFE_SOCKETS static gfxMutex uGFXnetMutex; #define MUTEX_INIT gfxMutexInit(&uGFXnetMutex) @@ -156,15 +189,134 @@ static bool_t sendpkt(SOCKET_TYPE netfd, uint16_t *pkt, int len) { return send(netfd, (const char *)pkt, len, 0) == len; } +static bool_t newconnection(SOCKET_TYPE clientfd) { + GDisplay * g; + netPriv * priv; + + // Look for a display that isn't connected + for(g = 0; (g = (GDisplay *)gdriverGetNext(GDRIVER_TYPE_DISPLAY, (GDriver *)g));) { + // Ignore displays for other controllers + #ifdef GDISP_DRIVER_LIST + if (gvmt(g) != &GDISPVMT_uGFXnet) + continue; + #endif + if (!(g->flags & GDISP_FLG_CONNECTED)) + break; + } + + // Was anything found? + if (!g) + return FALSE; + + // Reset the priv area + priv = g->priv; + priv->netfd = clientfd; + priv->databytes = 0; + priv->mousebuttons = 0; + + // Send the initialisation data (2 words at a time) + priv->data[0] = GNETCODE_INIT; + priv->data[1] = GNETCODE_VERSION; + sendpkt(priv->netfd, priv->data, 2); + priv->data[0] = GDISP_SCREEN_WIDTH; + priv->data[1] = GDISP_SCREEN_HEIGHT; + sendpkt(priv->netfd, priv->data, 2); + priv->data[0] = GDISP_LLD_PIXELFORMAT; + priv->data[1] = 1; // We have a mouse + MUTEX_ENTER; + sendpkt(priv->netfd, priv->data, 2); + MUTEX_EXIT; + + // The display is now working + g->flags |= GDISP_FLG_CONNECTED; + + // Send a redraw all + #if GFX_USE_GWIN && GWIN_NEED_WINDOWMANAGER + gdispGClear(g, gwinGetDefaultBgColor()); + gwinRedrawDisplay(g, FALSE); + #endif + + return TRUE; +} + +static bool_t rxdata(SOCKET_TYPE fd) { + GDisplay * g; + netPriv * priv; + int len; + + // Look for a display that is connected and the socket descriptor matches + for(g = 0; (g = (GDisplay *)gdriverGetNext(GDRIVER_TYPE_DISPLAY, (GDriver *)g));) { + // Ignore displays for other controllers + #ifdef GDISP_DRIVER_LIST + if (gvmt(g) != &GDISPVMT_uGFXnet) + continue; + #endif + priv = g->priv; + if ((g->flags & GDISP_FLG_CONNECTED) && priv->netfd == fd) + break; + } + if (!g) + gfxHalt("GDISP: uGFXnet - Got data from unrecognized connection"); + + if ((g->flags & GDISP_FLG_HAVEDATA)) { + // The higher level is still processing the previous data. + // Give it a chance to run by coming back to this data. + gfxSleepMilliseconds(1); + return TRUE; + } + + /* handle data from a client */ + MUTEX_ENTER; + if ((len = recv(fd, ((char *)priv->data)+priv->databytes, sizeof(priv->data)-priv->databytes, 0)) <= 0) { + // Socket closed or in error state + MUTEX_EXIT; + g->flags &= ~GDISP_FLG_CONNECTED; + return FALSE; + } + MUTEX_EXIT; + + // Do we have a full reply yet + priv->databytes += len; + if (priv->databytes < sizeof(priv->data)) + return TRUE; + priv->databytes = 0; + + // Convert network byte or to host byte order + priv->data[0] = ntohs(priv->data[0]); + priv->data[1] = ntohs(priv->data[1]); + + // Process the data received + switch(priv->data[0]) { + #if GINPUT_NEED_MOUSE + case GNETCODE_MOUSE_X: priv->mousex = priv->data[1]; break; + case GNETCODE_MOUSE_Y: priv->mousey = priv->data[1]; break; + case GNETCODE_MOUSE_B: + priv->mousebuttons = priv->data[1]; + // Treat the button event as the sync signal + _gmouseWakeup(priv->mouse); + break; + #endif + case GNETCODE_CONTROL: + case GNETCODE_READ: + g->flags |= GDISP_FLG_HAVEDATA; + break; + case GNETCODE_KILL: + gfxHalt("GDISP: uGFXnet - Display sent KILL command"); + break; + + default: + // Just ignore unrecognised data + break; + } + return TRUE; +} + static DECLARE_THREAD_STACK(waNetThread, 512); static DECLARE_THREAD_FUNCTION(NetThread, param) { SOCKET_TYPE listenfd, fdmax, i, clientfd; socklen_t len; - int leni; fd_set master, read_fds; struct sockaddr_in addr; - GDisplay * g; - netPriv * priv; (void)param; // Start the sockets layer @@ -197,25 +349,13 @@ static DECLARE_THREAD_FUNCTION(NetThread, param) { fdmax = listenfd; /* so far, it's this one*/ #if GDISP_GFXNET_BROKEN_LWIP_ACCEPT - { #warning "Using GDISP_GFXNET_BROKEN_LWIP_ACCEPT limits the number of displays and the use of GFXNET. Avoid if possible!" len = sizeof(addr); if((clientfd = accept(listenfd, (struct sockaddr *)&addr, &len)) == (SOCKET_TYPE)-1) gfxHalt("GDISP: uGFXnet - Accept failed"); + //printf("New connection from %s on socket %d\n", inet_ntoa(addr.sin_addr), clientfd); - // Look for a display that isn't connected - for(g = 0; (g = (GDisplay *)gdriverGetNext(GDRIVER_TYPE_DISPLAY, (GDriver *)g));) { - // Ignore displays for other controllers - #ifdef GDISP_DRIVER_LIST - if (gvmt(g) != &GDISPVMT_uGFXnet) - continue; - #endif - if (!(g->flags & GDISP_FLG_CONNECTED)) - break; - } - - // Was anything found? - if (!g) { + if (!newconnection(clientfd)) { // No Just close the connection closesocket(clientfd); gfxHalt("GDISP: uGFXnet - Can't find display for connection"); @@ -225,33 +365,6 @@ static DECLARE_THREAD_FUNCTION(NetThread, param) { // Save the descriptor FD_SET(clientfd, &master); if (clientfd > fdmax) fdmax = clientfd; - priv = g->priv; - memset(priv, 0, sizeof(netPriv)); - priv->netfd = clientfd; - //printf(New connection from %s on socket %d allocated to display %u\n", inet_ntoa(addr.sin_addr), clientfd, disp+1); - - // Send the initialisation data (2 words at a time) - priv->data[0] = GNETCODE_INIT; - priv->data[1] = GNETCODE_VERSION; - sendpkt(priv->netfd, priv->data, 2); - priv->data[0] = GDISP_SCREEN_WIDTH; - priv->data[1] = GDISP_SCREEN_HEIGHT; - sendpkt(priv->netfd, priv->data, 2); - priv->data[0] = GDISP_LLD_PIXELFORMAT; - priv->data[1] = (g->flags & GDISP_FLG_HASMOUSE) ? 1 : 0; - MUTEX_ENTER; - sendpkt(priv->netfd, priv->data, 2); - MUTEX_EXIT; - - // The display is now working - g->flags |= GDISP_FLG_CONNECTED; - - // Send a redraw all - #if GFX_USE_GWIN && GWIN_NEED_WINDOWMANAGER - gdispGClear(g, gwinGetDefaultBgColor()); - gwinRedrawDisplay(g, FALSE); - #endif - } #endif /* loop */ @@ -268,132 +381,33 @@ static DECLARE_THREAD_FUNCTION(NetThread, param) { // Handle new connections if(i == listenfd) { + + // Accept the connection len = sizeof(addr); if((clientfd = accept(listenfd, (struct sockaddr *)&addr, &len)) == (SOCKET_TYPE)-1) gfxHalt("GDISP: uGFXnet - Accept failed"); + //printf("New connection from %s on socket %d\n", inet_ntoa(addr.sin_addr), clientfd); - // Look for a display that isn't connected - for(g = 0; (g = (GDisplay *)gdriverGetNext(GDRIVER_TYPE_DISPLAY, (GDriver *)g));) { - // Ignore displays for other controllers - #ifdef GDISP_DRIVER_LIST - if (gvmt(g) != &GDISPVMT_uGFXnet) - continue; - #endif - if (!(g->flags & GDISP_FLG_CONNECTED)) - break; - } + // Can we handle it? + if (!newconnection(clientfd)) { - // Was anything found? - if (!g) { - // No Just close the connection + // No - Just close the connection closesocket(clientfd); - //printf(New connection from %s on socket %d rejected as all displays are already connected\n", inet_ntoa(addr.sin_addr), clientfd); + + //printf("Rejected connection as all displays are already connected\n"); continue; } // Save the descriptor FD_SET(clientfd, &master); if (clientfd > fdmax) fdmax = clientfd; - priv = g->priv; - memset(priv, 0, sizeof(netPriv)); - priv->netfd = clientfd; - //printf(New connection from %s on socket %d allocated to display %u\n", inet_ntoa(addr.sin_addr), clientfd, disp+1); - - // Send the initialisation data (2 words at a time) - priv->data[0] = GNETCODE_INIT; - priv->data[1] = GNETCODE_VERSION; - sendpkt(priv->netfd, priv->data, 2); - priv->data[0] = GDISP_SCREEN_WIDTH; - priv->data[1] = GDISP_SCREEN_HEIGHT; - sendpkt(priv->netfd, priv->data, 2); - priv->data[0] = GDISP_LLD_PIXELFORMAT; - priv->data[1] = (g->flags & GDISP_FLG_HASMOUSE) ? 1 : 0; - MUTEX_ENTER; - sendpkt(priv->netfd, priv->data, 2); - MUTEX_EXIT; - - // The display is now working - g->flags |= GDISP_FLG_CONNECTED; - - // Send a redraw all - #if GFX_USE_GWIN && GWIN_NEED_WINDOWMANAGER - gdispGClear(g, gwinGetDefaultBgColor()); - gwinRedrawDisplay(g, FALSE); - #endif - continue; } // Handle data from a client - - // Look for a display that is connected and the socket descriptor matches - for(g = 0; (g = (GDisplay *)gdriverGetNext(GDRIVER_TYPE_DISPLAY, (GDriver *)g));) { - // Ignore displays for other controllers - #ifdef GDISP_DRIVER_LIST - if (gvmt(g) != &GDISPVMT_uGFXnet) - continue; - #endif - priv = g->priv; - if ((g->flags & GDISP_FLG_CONNECTED) && priv->netfd == i) - break; - } - if (!g) - gfxHalt("GDISP: uGFXnet - Got data from unrecognized connection"); - - if ((g->flags & GDISP_FLG_HAVEDATA)) { - // The higher level is still processing the previous data. - // Give it a chance to run by coming back to this data. - gfxSleepMilliseconds(1); - continue; - } - - /* handle data from a client */ - MUTEX_ENTER; - if ((leni = recv(i, ((char *)priv->data)+priv->databytes, sizeof(priv->data)-priv->databytes, 0)) <= 0) { - // Socket closed or in error state - MUTEX_EXIT; - g->flags &= ~GDISP_FLG_CONNECTED; - memset(priv, 0, sizeof(netPriv)); + if (!rxdata(i)) { closesocket(i); - FD_CLR(i, &master); - continue; - } - MUTEX_EXIT; - - // Do we have a full reply yet - priv->databytes += leni; - if (priv->databytes < sizeof(priv->data)) - continue; - priv->databytes = 0; - - // Convert network byte or to host byte order - priv->data[0] = ntohs(priv->data[0]); - priv->data[1] = ntohs(priv->data[1]); - - // Process the data received - switch(priv->data[0]) { - #if GINPUT_NEED_MOUSE - case GNETCODE_MOUSE_X: priv->mousex = priv->data[1]; break; - case GNETCODE_MOUSE_Y: priv->mousey = priv->data[1]; break; - case GNETCODE_MOUSE_B: - priv->mousebuttons = priv->data[1]; - // Treat the button event as the sync signal - #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE - ginputMouseWakeup(); - #endif - break; - #endif - case GNETCODE_CONTROL: - case GNETCODE_READ: - g->flags |= GDISP_FLG_HAVEDATA; - break; - case GNETCODE_KILL: - gfxHalt("GDISP: uGFXnet - Display sent KILL command"); - break; - - default: - // Just ignore unrecognised data - break; + FD_CLR(clientfd, &master); } } } @@ -414,14 +428,6 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { gfxThreadClose(hThread); } - // Only turn on mouse on the first window for now - #if GINPUT_NEED_MOUSE - if (!g->controllerdisplay) { - mouseDisplay = g; - g->flags |= GDISP_FLG_HASMOUSE; - } - #endif - // Create a private area for this window if (!(priv = gfxAlloc(sizeof(netPriv)))) gfxHalt("GDISP: uGFXnet - Memory allocation failed"); @@ -429,6 +435,11 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { g->priv = priv; g->board = 0; // no board interface for this controller + // Create the associated mouse + #if GINPUT_NEED_MOUSE + priv->mouse = (GMouse *)gdriverRegister((const GDriverVMT const *)GMOUSE_DRIVER_VMT, g); + #endif + // Initialise the GDISP structure g->g.Orientation = GDISP_ROTATE_0; g->g.Powermode = powerOn; @@ -694,18 +705,23 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #endif #if GINPUT_NEED_MOUSE - void ginput_lld_mouse_init(void) {} - void ginput_lld_mouse_get_reading(MouseReading *pt) { + static bool_t NMouseInit(GMouse *m, unsigned driverinstance) { + (void) m; + (void) driverinstance; + return TRUE; + } + static bool_t NMouseRead(GMouse *m, GMouseReading *pt) { GDisplay * g; netPriv * priv; - g = mouseDisplay; + g = m->display; priv = g->priv; pt->x = priv->mousex; pt->y = priv->mousey; - pt->z = (priv->mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 100 : 0; + pt->z = (priv->mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 1 : 0; pt->buttons = priv->mousebuttons; + return TRUE; } #endif /* GINPUT_NEED_MOUSE */ diff --git a/gfxconf.example.h b/gfxconf.example.h index 564c0c70..cea9bba7 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -211,6 +211,16 @@ //#define GFX_USE_GINPUT FALSE //#define GINPUT_NEED_MOUSE FALSE +// #define GINPUT_TOUCH_STARTRAW FALSE +// #define GINPUT_TOUCH_NOTOUCH FALSE +// #define GINPUT_TOUCH_NOCALIBRATE FALSE +// #define GINPUT_TOUCH_NOCALIBRATE_GUI FALSE +// #define GINPUT_MOUSE_POLL_PERIOD 25 +// #define GINPUT_MOUSE_CLICK_TIME 300 +// #define GINPUT_TOUCH_CXTCLICK_TIME 700 +// #define GINPUT_TOUCH_USER_CALIBRATION_LOAD FALSE +// #define GINPUT_TOUCH_USER_CALIBRATION_FREE FALSE +// #define GINPUT_TOUCH_USER_CALIBRATION_SAVE FALSE //#define GINPUT_NEED_KEYBOARD FALSE //#define GINPUT_NEED_TOGGLE FALSE //#define GINPUT_NEED_DIAL FALSE diff --git a/src/ginput/driver_mouse.h b/src/ginput/driver_mouse.h index 21d87dac..836ae1de 100644 --- a/src/ginput/driver_mouse.h +++ b/src/ginput/driver_mouse.h @@ -17,162 +17,159 @@ #ifndef _LLD_GINPUT_MOUSE_H #define _LLD_GINPUT_MOUSE_H -#if GINPUT_NEED_MOUSE || defined(__DOXYGEN__) +#if GINPUT_NEED_MOUSE //|| defined(__DOXYGEN__) -#include "ginput_lld_mouse_config.h" +// Include the GDRIVER infrastructure +#include "src/gdriver/sys_defs.h" -// GEVENT_MOUSE or GEVENT_TOUCH - What type of device is this. -#ifndef GINPUT_MOUSE_EVENT_TYPE - #define GINPUT_MOUSE_EVENT_TYPE GEVENT_MOUSE -#endif - -// TRUE/FALSE - Does the mouse/touch driver require calibration? -#ifndef GINPUT_MOUSE_NEED_CALIBRATION - #define GINPUT_MOUSE_NEED_CALIBRATION FALSE -#endif - -// TRUE/FALSE - Should the calibration happen at the extremes of the panel? -#ifndef GINPUT_MOUSE_CALIBRATE_EXTREMES - #define GINPUT_MOUSE_CALIBRATE_EXTREMES FALSE -#endif - -// TRUE/FALSE - Can the mouse/touch driver itself save calibration data? -#ifndef GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE - #define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE -#endif - -// n or -1 - n means to test calibration result (+/- pixels), -1 means not to. -#ifndef GINPUT_MOUSE_MAX_CALIBRATION_ERROR - #define GINPUT_MOUSE_MAX_CALIBRATION_ERROR -1 -#endif - -// n - How many times to read (and average) per poll -#ifndef GINPUT_MOUSE_READ_CYCLES - #define GINPUT_MOUSE_READ_CYCLES 1 -#endif - -// n - Millisecs between poll's -#ifndef GINPUT_MOUSE_POLL_PERIOD - #define GINPUT_MOUSE_POLL_PERIOD 25 -#endif - -// n - Movement allowed without discarding the CLICK or CLICKCXT event (+/- pixels) -#ifndef GINPUT_MOUSE_MAX_CLICK_JITTER - #define GINPUT_MOUSE_MAX_CLICK_JITTER 1 -#endif - -// n - Movement allowed without discarding the MOVE event (+/- pixels) -#ifndef GINPUT_MOUSE_MAX_MOVE_JITTER - #define GINPUT_MOUSE_MAX_MOVE_JITTER 0 -#endif - -// ms - Millisecs seperating a CLICK from a CXTCLICK -#ifndef GINPUT_MOUSE_CLICK_TIME - #define GINPUT_MOUSE_CLICK_TIME 700 -#endif - -// true/false - Whether the mouse driver internally handles screen rotation -#ifndef GINPUT_MOUSE_NO_ROTATION - #define GINPUT_MOUSE_NO_ROTATION FALSE -#endif - -typedef struct MouseReading_t { +typedef struct GMouseReading { coord_t x, y, z; uint16_t buttons; - } MouseReading; + } GMouseReading; + +#if !GINPUT_TOUCH_NOCALIBRATE + typedef struct GMouseCalibration { + float ax; + float bx; + float cx; + float ay; + float by; + float cy; + } GMouseCalibration; +#endif + +typedef struct GMouse { + GDriver d; // The driver overheads and vmt + GMouseReading r; // The current position and state + uint16_t flags; // Flags + #define GMOUSE_FLG_CLICK_TIMER 0x0001 // Currently timing a click + #define GMOUSE_FLG_INDELTA 0x0002 // Currently in a up/down transition test + #define GMOUSE_FLG_CLIP 0x0004 // Clip reading to the display + #define GMOUSE_FLG_CALIBRATE 0x0008 // Calibrate readings + #define GMOUSE_FLG_IN_CAL 0x0010 // Currently in calibration routine + #define GMOUSE_FLG_FINGERMODE 0x0020 // Mouse is currently in finger mode + #define GMOUSE_FLG_NEEDREAD 0x0040 // The mouse needs reading + #define GMOUSE_FLG_DRIVER_FIRST 0x0100 // The first flag available for the driver + point clickpos; // The position of the last click event + systemticks_t clicktime; // The time of the last click event + GDisplay * display; // The display the mouse is associated with + #if !GINPUT_TOUCH_NOCALIBRATE + GMouseCalibration caldata; // The calibration data + #endif + // Other driver specific fields may follow. +} GMouse; + +typedef struct GMouseJitter { + coord_t calibrate; // Maximum error for a calibration to succeed + coord_t click; // Movement allowed without discarding the CLICK or CLICKCXT event + coord_t move; // Movement allowed without discarding the MOVE event +} GMouseJitter; + +typedef struct GMouseVMT { + GDriverVMT d; // Device flags are part of the general vmt + #define GMOUSE_VFLG_TOUCH 0x0001 // This is a touch device (rather than a mouse). Button 1 is calculated from z value. + #define GMOUSE_VFLG_NOPOLL 0x0002 // Do not poll this device - it is purely interrupt driven + #define GMOUSE_VFLG_SELFROTATION 0x0004 // This device returns readings that are aligned with the display orientation + #define GMOUSE_VFLG_DEFAULTFINGER 0x0008 // Default to finger mode + #define GMOUSE_VFLG_CALIBRATE 0x0010 // This device requires calibration + #define GMOUSE_VFLG_CAL_EXTREMES 0x0020 // Use edge to edge calibration + #define GMOUSE_VFLG_CAL_TEST 0x0040 // Test the results of the calibration + #define GMOUSE_VFLG_CAL_LOADFREE 0x0080 // Call gfxFree on the buffer returned by the VMT calload() routine. + #define GMOUSE_VFLG_ONLY_DOWN 0x0100 // This device returns a valid position only when the mouse is down + #define GMOUSE_VFLG_POORUPDOWN 0x0200 // Position readings during up/down are unreliable + #define GMOUSE_VFLG_DYNAMICONLY 0x8000 // This mouse driver should not be statically initialized eg Win32 + coord_t z_max; // TOUCH: Maximum possible z value (fully touched) + coord_t z_min; // TOUCH: Minimum possible z value (touch off screen). Note may also be > z_max + coord_t z_touchon; // TOUCH: z values between z_max and this are a solid touch on + coord_t z_touchoff; // TOUCH: z values between z_min and this are a solid touch off + + GMouseJitter pen_jitter; // PEN MODE: Jitter settings + GMouseJitter finger_jitter; // FINGER MODE: Jitter settings + + bool_t (*init)(GMouse *m, unsigned driverinstance); // Required + void (*deinit)(GMouse *m); // Optional + bool_t (*get)(GMouse *m, GMouseReading *prd); // Required + void (*calsave)(GMouse *m, void *buf, size_t sz); // Optional + const char *(*calload)(GMouse *m, size_t sz); // Optional: Can return NULL if no data is saved. +} GMouseVMT; + +#define gmvmt(m) ((const GMouseVMT const *)((m)->d.vmt)) /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ +// If we are not using multiple mice then hard-code the VMT name +#if !defined(GINPUT_MOUSE_DRIVER_LIST) + #undef GMOUSE_DRIVER_VMT + #define GMOUSE_DRIVER_VMT GMOUSEVMT_OnlyOne +#endif + #ifdef __cplusplus extern "C" { #endif - /** - * @brief Initialise the mouse/touch. + * @brief Initialize a mouse driver + * + * @param[in] g The mouse driver + * @param[in] display The display to which the mouse shall be assigned + * @param[in] driverinstance The driver instance ToDo: Add some more details + * @param[in] systeminstance The mouse instance ToDo: Add some more details + * + * @return TRUE on success, FALSE otherwise + * @note This routine is provided by the high level code for + * use in the driver VMT's GMouseVMT.d structure. * * @notapi */ - void ginput_lld_mouse_init(void); + bool_t _gmouseInitDriver(GDriver *g, void *display, unsigned driverinstance, unsigned systeminstance); /** - * @brief Read the mouse/touch position. + * @brief Routine that is called after initialization * - * @param[in] pt A pointer to the structure to fill - * - * @note For drivers that don't support returning a position - * when the touch is up (most touch devices), it should - * return the previous position with the new Z value. - * The z value is the pressure for those touch devices - * that support it (-100 to 100 where > 0 is touched) - * or, 0 or 100 for those drivers that don't. + * @param[in] g The mouse driver + * @note This routine is provided by the high level code for + * use in the driver VMT's GMouseVMT.d structure. * * @notapi */ - void ginput_lld_mouse_get_reading(MouseReading *pt); + void _gmousePostInitDriver(GDriver *g); - #if GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE - /** - * @brief Load calibration data from a storage area on the touch controller. - * - * @param[in] instance The mouse instance number - * - * @note The instance parameter is currently always 0 as we only support - * one mouse/touch device at a time. - * @note This routine should only be provided if the driver has its own - * storage area where calibration data can be stored. The drivers - * option.h file should define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE = TRUE - * if it supports this. - * - * @notapi - */ - const char *ginput_lld_mouse_calibration_load(uint16_t instance); - /** - * @brief Save calibration data to a storage area on the touch controller. - * - * @param[in] instance The mouse instance number - * @param[in] calbuf The calibration data to be saved - * @param[in] sz The size of the calibration data - * - * @note The instance parameter is currently always 0 as we only support - * one mouse/touch device at a time. - * @note This routine should only be provided if the driver has its own - * storage area where calibration data can be stored. The drivers - * option.h file should define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE = TRUE - * if it supports this. - * - * @notapi - */ - void ginput_lld_mouse_calibration_save(uint16_t instance, const uint8_t *calbuf, size_t sz); - #endif + /** + * @brief Deinitialize a mouse driver + * + * @param[in] g The mouse driver + * @note This routine is provided by the high level code for + * use in the driver VMT's GMouseVMT.d structure. + * + * @notapi + */ + void _gmouseDeInitDriver(GDriver *g); /** * @brief Wakeup the high level code so that it attempts another read * * @note This routine is provided to low level drivers by the high level code - * @note Particularly useful if GINPUT_MOUSE_POLL_PERIOD = TIME_INFINITE * * @notapi */ - void ginputMouseWakeup(void); + void _gmouseWakeup(GMouse *m); /** * @brief Wakeup the high level code so that it attempts another read * * @note This routine is provided to low level drivers by the high level code - * @note Particularly useful if GINPUT_MOUSE_POLL_PERIOD = TIME_INFINITE * * @iclass * @notapi */ - void ginputMouseWakeupI(void); + void _gmouseWakeupI(GMouse *m); #ifdef __cplusplus } #endif -#endif /* GINPUT_NEED_MOUSE || GINPUT_NEED_TOUCH */ +#endif /* GINPUT_NEED_MOUSE */ #endif /* _LLD_GINPUT_MOUSE_H */ /** @} */ diff --git a/src/ginput/ginput_ginput.c b/src/ginput/ginput_ginput.c index 4197fa25..191ae025 100644 --- a/src/ginput/ginput_ginput.c +++ b/src/ginput/ginput_ginput.c @@ -16,10 +16,16 @@ #if GFX_USE_GINPUT +#if GINPUT_NEED_MOUSE + extern void _gmouseInit(void); + extern void _gmouseDeinit(void); +#endif + void _ginputInit(void) { - /* ToDo */ - + #if GINPUT_NEED_MOUSE + _gmouseInit(); + #endif /** * This should really call an init routine for each ginput sub-system. * Maybe we'll do this later. @@ -28,7 +34,9 @@ void _ginputInit(void) void _ginputDeinit(void) { - + #if GINPUT_NEED_MOUSE + _gmouseDeinit(); + #endif } #endif /* GFX_USE_GINPUT */ diff --git a/src/ginput/ginput_mouse.c b/src/ginput/ginput_mouse.c index a0daba98..570839a2 100644 --- a/src/ginput/ginput_mouse.c +++ b/src/ginput/ginput_mouse.c @@ -8,670 +8,815 @@ /** * @file src/ginput/ginput_mouse.c * @brief GINPUT mouse/touch code. - * - * @defgroup Mouse Mouse - * @ingroup GINPUT - * @{ */ #include "gfx.h" -#if (GFX_USE_GINPUT && GINPUT_NEED_MOUSE) || defined(__DOXYGEN__) +#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE -#include "driver_mouse.h" - -#if GINPUT_MOUSE_NEED_CALIBRATION - #if !defined(GFX_USE_GDISP) || !GFX_USE_GDISP - #error "GINPUT: GFX_USE_GDISP must be defined when mouse or touch calibration is required" - #endif - - #include // Required for memcpy - - #define GINPUT_MOUSE_CALIBRATION_FONT "* Double" - #define GINPUT_MOUSE_CALIBRATION_FONT2 "* Narrow" - #define GINPUT_MOUSE_CALIBRATION_TEXT "Calibration" - #define GINPUT_MOUSE_CALIBRATION_ERROR_TEXT "Failed - Please try again!" - #define GINPUT_MOUSE_CALIBRATION_SAME_TEXT "Error: Same Reading - Check Driver!" - - #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR < 0 - #define GINPUT_MOUSE_CALIBRATION_POINTS 3 - #else - #define GINPUT_MOUSE_CALIBRATION_POINTS 4 - #endif - - typedef struct Calibration_t { - float ax; - float bx; - float cx; - float ay; - float by; - float cy; - } Calibration; +// Just to make code easier +#if !GFX_USE_GDISP + #define GDISP 0 #endif -typedef struct MousePoint_t { - coord_t x, y; -} MousePoint; +// Local Settings +#define CALIBRATION_POLL_PERIOD 20 // milliseconds +#define CALIBRATION_MINPRESS_PERIOD 300 // milliseconds +#define CALIBRATION_MAXPRESS_PERIOD 5000 // milliseconds +#define CALIBRATION_FONT "* Double" +#define CALIBRATION_FONT2 "* Narrow" +#define CALIBRATION_BACKGROUND Blue + +#define CALIBRATION_CROSS_COLOR1 White +#define CALIBRATION_CROSS_COLOR2 RGB2COLOR(184,158,131) +#define CALIBRATION_CROSS_INNERGAP 2 +#define CALIBRATION_CROSS_RADIUS 15 + +#define CALIBRATION_TITLE "Calibration" +#define CALIBRATION_TITLE_Y 5 +#define CALIBRATION_TITLE_HEIGHT 30 +#define CALIBRATION_TITLE_COLOR White +#define CALIBRATION_TITLE_BACKGROUND Blue + +#define CALIBRATION_ERROR_TEXT "Calibration Failed!" +#define CALIBRATION_ERROR_DELAY 3000 +#define CALIBRATION_ERROR_COLOR Red +#define CALIBRATION_ERROR_BACKGROUND Yellow +#define CALIBRATION_ERROR_Y 35 +#define CALIBRATION_ERROR_HEIGHT 40 + +// Get the mouse driver interface +#include "driver_mouse.h" + +// The mouse poll timer static GTIMER_DECL(MouseTimer); -static struct MouseConfig_t { - MouseReading t; - MousePoint movepos; - MousePoint clickpos; - systemticks_t clicktime; - uint16_t last_buttons; - uint16_t flags; - #define FLG_INIT_DONE 0x8000 - #define FLG_CLICK_TIMER 0x0001 - #define FLG_IN_CAL 0x0010 - #define FLG_CAL_OK 0x0020 - #define FLG_CAL_SAVED 0x0040 - #define FLG_CAL_FREE 0x0080 - #define FLG_CAL_RAW 0x0100 - #if GINPUT_MOUSE_NEED_CALIBRATION - GMouseCalibrationSaveRoutine fnsavecal; - GMouseCalibrationLoadRoutine fnloadcal; - Calibration caldata; - #endif - GDisplay * display; -} MouseConfig; +// Calibration application +#if !GINPUT_TOUCH_NOCALIBRATE + #include // Required for memcpy -void _tsOrientClip(MouseReading *pt, GDisplay *g, bool_t doClip) { - coord_t w, h; - - w = gdispGGetWidth(g); - h = gdispGGetHeight(g); - - #if GDISP_NEED_CONTROL && !GINPUT_MOUSE_NO_ROTATION - switch(gdispGGetOrientation(g)) { - case GDISP_ROTATE_0: - break; - case GDISP_ROTATE_90: - { - coord_t t = pt->x; - pt->x = w - 1 - pt->y; - pt->y = t; - } - break; - case GDISP_ROTATE_180: - pt->x = w - 1 - pt->x; - pt->y = h - 1 - pt->y; - break; - case GDISP_ROTATE_270: - { - coord_t t = pt->y; - pt->y = h - 1 - pt->x; - pt->x = t; - } - break; - default: - break; - } - #endif - - if (doClip) { - if (pt->x < 0) pt->x = 0; - else if (pt->x >= w) pt->x = w-1; - if (pt->y < 0) pt->y = 0; - else if (pt->y >= h) pt->y = h-1; - } -} - -#if GINPUT_MOUSE_NEED_CALIBRATION - static inline void _tsSetIdentity(Calibration *c) { - c->ax = 1; - c->bx = 0; - c->cx = 0; - c->ay = 0; - c->by = 1; - c->cy = 0; - } - - static inline void _tsDrawCross(const MousePoint *pp) { - gdispGDrawLine(MouseConfig.display, pp->x-15, pp->y, pp->x-2, pp->y, White); - gdispGDrawLine(MouseConfig.display, pp->x+2, pp->y, pp->x+15, pp->y, White); - gdispGDrawLine(MouseConfig.display, pp->x, pp->y-15, pp->x, pp->y-2, White); - gdispGDrawLine(MouseConfig.display, pp->x, pp->y+2, pp->x, pp->y+15, White); - - gdispGDrawLine(MouseConfig.display, pp->x-15, pp->y+15, pp->x-7, pp->y+15, RGB2COLOR(184,158,131)); - gdispGDrawLine(MouseConfig.display, pp->x-15, pp->y+7, pp->x-15, pp->y+15, RGB2COLOR(184,158,131)); - - gdispGDrawLine(MouseConfig.display, pp->x-15, pp->y-15, pp->x-7, pp->y-15, RGB2COLOR(184,158,131)); - gdispGDrawLine(MouseConfig.display, pp->x-15, pp->y-7, pp->x-15, pp->y-15, RGB2COLOR(184,158,131)); - - gdispGDrawLine(MouseConfig.display, pp->x+7, pp->y+15, pp->x+15, pp->y+15, RGB2COLOR(184,158,131)); - gdispGDrawLine(MouseConfig.display, pp->x+15, pp->y+7, pp->x+15, pp->y+15, RGB2COLOR(184,158,131)); - - gdispGDrawLine(MouseConfig.display, pp->x+7, pp->y-15, pp->x+15, pp->y-15, RGB2COLOR(184,158,131)); - gdispGDrawLine(MouseConfig.display, pp->x+15, pp->y-15, pp->x+15, pp->y-7, RGB2COLOR(184,158,131)); - } - - static inline void _tsClearCross(const MousePoint *pp) { - gdispGFillArea(MouseConfig.display, pp->x - 15, pp->y - 15, 42, 42, Blue); - } - - static inline void _tsTransform(MouseReading *pt, const Calibration *c) { + static inline void CalibrationTransform(GMouseReading *pt, const GMouseCalibration *c) { pt->x = (coord_t) (c->ax * pt->x + c->bx * pt->y + c->cx); pt->y = (coord_t) (c->ay * pt->x + c->by * pt->y + c->cy); } +#endif - static inline void _tsDo3PointCalibration(const MousePoint *cross, const MousePoint *points, GDisplay *g, Calibration *c) { +static void SendMouseEvent(GSourceListener *psl, GMouse *m, GMouseReading *r) { + GEventMouse *pe; + + // If there is no event buffer just mark a missed event + if (!(pe = (GEventMouse *)geventGetEventBuffer(psl))) { + // This listener is missing - save the meta events that have happened + psl->srcflags |= ((r->buttons & GMETA_MASK)|GINPUT_MISSED_MOUSE_EVENT); + return; + } + + // If we haven't really moved (and there are no meta events) don't bother sending the event + if (!(r->buttons & GMETA_MASK) && !psl->srcflags && !(psl->listenflags & GLISTEN_MOUSENOFILTER) + && r->x == m->r.x && r->y == m->r.y && (r->buttons & GINPUT_MOUSE_BTN_MASK) == (m->r.buttons & GINPUT_MOUSE_BTN_MASK)) + return; + + // Send the event only if we are listening for it + if (!((r->buttons & GINPUT_MOUSE_BTN_LEFT) && (psl->listenflags & GLISTEN_MOUSEDOWNMOVES)) + && !(!(r->buttons & GINPUT_MOUSE_BTN_LEFT) && (psl->listenflags & GLISTEN_MOUSEUPMOVES)) + && !((r->buttons & GMETA_MASK) && (psl->listenflags & GLISTEN_MOUSEMETA))) + return; + + #if !GINPUT_TOUCH_NOTOUCH + pe->type = (gmvmt(m)->d.flags & GMOUSE_VFLG_TOUCH) ? GEVENT_TOUCH : GEVENT_MOUSE; + #else + pe->type = GEVENT_MOUSE; + #endif + pe->x = r->x; + pe->y = r->y; + pe->z = r->z; + pe->buttons = r->buttons | psl->srcflags; + psl->srcflags = 0; + pe->display = m->display; + geventSendEvent(psl); +} + +static void GetMouseReading(GMouse *m) { + GMouseReading r; + + // Step 1 - Get the Raw Reading + { + m->flags &= ~GMOUSE_FLG_NEEDREAD; + if (!gmvmt(m)->get(m, &r)) + return; + } + + // Step 2 - Handle touch and button 0 debouncing + { + // Clean off button garbage + r.buttons &= GINPUT_MOUSE_BTN_MASK; + + #if !GINPUT_TOUCH_NOTOUCH + // If touch then calculate button 0 from z + if ((gmvmt(m)->d.flags & GMOUSE_VFLG_TOUCH)) { + if (gmvmt(m)->z_min <= gmvmt(m)->z_max) { + if (r.z >= gmvmt(m)->z_touchon) r.buttons |= GINPUT_MOUSE_BTN_LEFT; + else if (r.z <= gmvmt(m)->z_touchoff) r.buttons &= ~GINPUT_MOUSE_BTN_LEFT; + else return; // bad transitional reading + } else { + if (r.z <= gmvmt(m)->z_touchon) r.buttons |= GINPUT_MOUSE_BTN_LEFT; + else if (r.z >= gmvmt(m)->z_touchoff) r.buttons &= ~GINPUT_MOUSE_BTN_LEFT; + else return; // bad transitional reading + } + } + + // Devices with poor button 0 transitioning need debouncing + if ((gmvmt(m)->d.flags & GMOUSE_VFLG_POORUPDOWN)) { + // Are we in a transition test + if ((m->flags & GMOUSE_FLG_INDELTA)) { + if (!((r.buttons ^ m->r.buttons) & GINPUT_MOUSE_BTN_LEFT)) { + // Transition failed + m->flags &= ~GMOUSE_FLG_INDELTA; + return; + } + // Transition succeeded + m->flags &= ~GMOUSE_FLG_INDELTA; + + // Should we start a transition test + } else if (((r.buttons ^ m->r.buttons) & GINPUT_MOUSE_BTN_LEFT)) { + m->flags |= GMOUSE_FLG_INDELTA; + return; + } + } + #endif + + #if !GINPUT_TOUCH_NOCALIBRATE_GUI + // Stop here with just the raw x,y reading during calibration + if ((m->flags & GMOUSE_FLG_IN_CAL)) { + if ((r.buttons & GINPUT_MOUSE_BTN_LEFT)) { + m->r.x = r.x; + m->r.y = r.y; + } + m->r.buttons = r.buttons; + return; + } + #endif + } + + // Step 3 - Apply calibration, rotation and display clipping + { + // If the mouse is up we may need to keep our previous position + if ((gmvmt(m)->d.flags & GMOUSE_VFLG_ONLY_DOWN) && !(r.buttons & GINPUT_MOUSE_BTN_LEFT)) { + r.x = m->r.x; + r.y = m->r.y; + + } else { + + #if !GINPUT_TOUCH_NOCALIBRATE + // Do we need to calibrate the reading? + if ((m->flags & GMOUSE_FLG_CALIBRATE)) + CalibrationTransform(&r, &m->caldata); + #endif + + // We can't clip or rotate if we don't have a display + if (m->display) { + coord_t w, h; + + // We now need display information + w = gdispGGetWidth(m->display); + h = gdispGGetHeight(m->display); + + #if GDISP_NEED_CONTROL + // Do we need to rotate the reading to match the display + if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_SELFROTATION)) { + coord_t t; + + switch(gdispGGetOrientation(m->display)) { + case GDISP_ROTATE_0: + break; + case GDISP_ROTATE_90: + t = r.x; + r.x = w - 1 - r.y; + r.y = t; + break; + case GDISP_ROTATE_180: + r.x = w - 1 - r.x; + r.y = h - 1 - r.y; + break; + case GDISP_ROTATE_270: + t = r.y; + r.y = h - 1 - r.x; + r.x = t; + break; + default: + break; + } + } + #endif + + // Do we need to clip the reading to the display + if ((m->flags & GMOUSE_FLG_CLIP)) { + if (r.x < 0) r.x = 0; + else if (r.x >= w) r.x = w-1; + if (r.y < 0) r.y = 0; + else if (r.y >= h) r.y = h-1; + } + } + } + } + + // Step 4 - Apply jitter detection + #if !GINPUT_TOUCH_NOTOUCH + { + const GMouseJitter *pj; + uint32_t diff; + + // Are we in pen or finger mode + pj = (m->flags & GMOUSE_FLG_FINGERMODE) ? &gmvmt(m)->finger_jitter : &gmvmt(m)->pen_jitter; + + // Is this just movement jitter + if (pj->move > 0) { + diff = (uint32_t)(r.x - m->r.x) * (uint32_t)(r.x - m->r.x) + (uint32_t)(r.y - m->r.y) * (uint32_t)(r.y - m->r.y); + if (diff < (uint32_t)pj->move * (uint32_t)pj->move) { + r.x = m->r.x; + r.y = m->r.y; + } + } + + // Check if the click has moved outside the click area and if so cancel the click + if (pj->click > 0 && (m->flags & GMOUSE_FLG_CLICK_TIMER)) { + diff = (uint32_t)(r.x - m->clickpos.x) * (uint32_t)(r.x - m->clickpos.x) + (uint32_t)(r.y - m->clickpos.y) * (uint32_t)(r.y - m->clickpos.y); + if (diff > (uint32_t)pj->click * (uint32_t)pj->click) + m->flags &= ~GMOUSE_FLG_CLICK_TIMER; + } + } + #endif + + // Step 5 - Click, context-click and other meta event detection + { + uint16_t upbtns, dnbtns; + + // Calculate button transitions + dnbtns = r.buttons & ~m->r.buttons; + upbtns = ~r.buttons & m->r.buttons; + + // Left mouse down generates the Mouse-down meta event + if ((dnbtns & GINPUT_MOUSE_BTN_LEFT)) + r.buttons |= GMETA_MOUSE_DOWN; + + // Left mouse up generates the Mouse-up meta event + if ((upbtns & GINPUT_MOUSE_BTN_LEFT)) + r.buttons |= GMETA_MOUSE_UP; + + // Left/Right mouse down starts the click timer + if ((dnbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT))) { + m->clickpos.x = r.x; + m->clickpos.y = r.y; + m->clicktime = gfxSystemTicks(); + m->flags |= GMOUSE_FLG_CLICK_TIMER; + } + + // Left/Right mouse up with the click timer still running may generate a click or context click + if ((upbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT)) && (m->flags & GMOUSE_FLG_CLICK_TIMER)) { + m->flags &= ~GMOUSE_FLG_CLICK_TIMER; + m->clicktime = gfxSystemTicks() - m->clicktime; + + // Was this a short click? + if (m->clicktime <= gfxMillisecondsToTicks(GINPUT_MOUSE_CLICK_TIME)) { + if ((upbtns & GINPUT_MOUSE_BTN_RIGHT)) + r.buttons |= GMETA_MOUSE_CXTCLICK; + if ((upbtns & GINPUT_MOUSE_BTN_LEFT)) + r.buttons |= GMETA_MOUSE_CLICK; + } + + #if !GINPUT_TOUCH_NOTOUCH + // Was this a long click on a touch device? + if ((gmvmt(m)->d.flags & GMOUSE_VFLG_TOUCH) && m->clicktime >= gfxMillisecondsToTicks(GINPUT_TOUCH_CXTCLICK_TIME)) + r.buttons |= GMETA_MOUSE_CXTCLICK; + #endif + } + } + + // Step 6 - Send the event to the listeners that are interested. + { + GSourceListener *psl; + + // Send to the "All Mice" source listeners + psl = 0; + while ((psl = geventGetSourceListener((GSourceHandle)&MouseTimer, psl))) + SendMouseEvent(psl, m, &r); + + // Send to the mouse specific source listeners + psl = 0; + while ((psl = geventGetSourceListener((GSourceHandle)m, psl))) + SendMouseEvent(psl, m, &r); + } + + // Step 7 - Finally save the results + m->r.x = r.x; + m->r.y = r.y; + m->r.z = r.z; + m->r.buttons = r.buttons; +} + +static void MousePoll(void *param) { + GMouse * m; + (void) param; + + for(m = (GMouse *)gdriverGetNext(GDRIVER_TYPE_MOUSE, 0); m; m = (GMouse *)gdriverGetNext(GDRIVER_TYPE_MOUSE, (GDriver *)m)) { + if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_NOPOLL) || (m->flags & GMOUSE_FLG_NEEDREAD)) + GetMouseReading(m); + } +} + +// Calibration user interface +#if !GINPUT_TOUCH_NOCALIBRATE_GUI + #if !defined(GFX_USE_GDISP) || !GFX_USE_GDISP + #error "GINPUT: GFX_USE_GDISP must be defined when calibration is required" + #endif + + static inline void CalibrationCrossDraw(GMouse *m, const point *pp) { + gdispGDrawLine(m->display, pp->x-CALIBRATION_CROSS_RADIUS, pp->y, pp->x-CALIBRATION_CROSS_INNERGAP, pp->y, CALIBRATION_CROSS_COLOR1); + gdispGDrawLine(m->display, pp->x+CALIBRATION_CROSS_INNERGAP, pp->y, pp->x+CALIBRATION_CROSS_RADIUS, pp->y, CALIBRATION_CROSS_COLOR1); + gdispGDrawLine(m->display, pp->x, pp->y-CALIBRATION_CROSS_RADIUS, pp->x, pp->y-CALIBRATION_CROSS_INNERGAP, CALIBRATION_CROSS_COLOR1); + gdispGDrawLine(m->display, pp->x, pp->y+CALIBRATION_CROSS_INNERGAP, pp->x, pp->y+CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_COLOR1); + gdispGDrawLine(m->display, pp->x-CALIBRATION_CROSS_RADIUS, pp->y+CALIBRATION_CROSS_RADIUS, pp->x-CALIBRATION_CROSS_RADIUS/2, pp->y+CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_COLOR2); + gdispGDrawLine(m->display, pp->x-CALIBRATION_CROSS_RADIUS, pp->y+CALIBRATION_CROSS_RADIUS/2, pp->x-CALIBRATION_CROSS_RADIUS, pp->y+CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_COLOR2); + gdispGDrawLine(m->display, pp->x-CALIBRATION_CROSS_RADIUS, pp->y-CALIBRATION_CROSS_RADIUS, pp->x-CALIBRATION_CROSS_RADIUS/2, pp->y-CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_COLOR2); + gdispGDrawLine(m->display, pp->x-CALIBRATION_CROSS_RADIUS, pp->y-CALIBRATION_CROSS_RADIUS/2, pp->x-CALIBRATION_CROSS_RADIUS, pp->y-CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_COLOR2); + gdispGDrawLine(m->display, pp->x+CALIBRATION_CROSS_RADIUS/2, pp->y+CALIBRATION_CROSS_RADIUS, pp->x+CALIBRATION_CROSS_RADIUS, pp->y+CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_COLOR2); + gdispGDrawLine(m->display, pp->x+CALIBRATION_CROSS_RADIUS, pp->y+CALIBRATION_CROSS_RADIUS/2, pp->x+CALIBRATION_CROSS_RADIUS, pp->y+CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_COLOR2); + gdispGDrawLine(m->display, pp->x+CALIBRATION_CROSS_RADIUS/2, pp->y-CALIBRATION_CROSS_RADIUS, pp->x+CALIBRATION_CROSS_RADIUS, pp->y-CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_COLOR2); + gdispGDrawLine(m->display, pp->x+CALIBRATION_CROSS_RADIUS, pp->y-CALIBRATION_CROSS_RADIUS, pp->x+CALIBRATION_CROSS_RADIUS, pp->y-CALIBRATION_CROSS_RADIUS/2, CALIBRATION_CROSS_COLOR2); + } + + static inline void CalibrationCrossClear(GMouse *m, const point *pp) { + gdispGFillArea(m->display, pp->x - CALIBRATION_CROSS_RADIUS, pp->y - CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_RADIUS*2+1, CALIBRATION_CROSS_RADIUS*2+1, CALIBRATION_BACKGROUND); + } + + static inline void CalibrationCalculate(GMouse *m, const point *cross, const point *points) { float dx; coord_t c0, c1, c2; + (void) m; + + // Work on x values + c0 = cross[0].x; + c1 = cross[1].x; + c2 = cross[2].x; #if GDISP_NEED_CONTROL - /* Convert all cross points back to GDISP_ROTATE_0 convention - * before calculating the calibration matrix. - */ - switch(gdispGGetOrientation(g)) { - case GDISP_ROTATE_90: - c0 = cross[0].y; - c1 = cross[1].y; - c2 = cross[2].y; - break; - case GDISP_ROTATE_180: - c0 = c1 = c2 = gdispGGetWidth(g) - 1; - c0 -= cross[0].x; - c1 -= cross[1].x; - c2 -= cross[2].x; - break; - case GDISP_ROTATE_270: - c0 = c1 = c2 = gdispGGetHeight(g) - 1; - c0 -= cross[0].y; - c1 -= cross[1].y; - c2 -= cross[2].y; - break; - case GDISP_ROTATE_0: - default: - c0 = cross[0].x; - c1 = cross[1].x; - c2 = cross[2].x; - break; + if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_SELFROTATION)) { + /* Convert all cross points back to GDISP_ROTATE_0 convention + * before calculating the calibration matrix. + */ + switch(gdispGGetOrientation(m->display)) { + case GDISP_ROTATE_90: + c0 = cross[0].y; + c1 = cross[1].y; + c2 = cross[2].y; + break; + case GDISP_ROTATE_180: + c0 = c1 = c2 = gdispGGetWidth(m->display) - 1; + c0 -= cross[0].x; + c1 -= cross[1].x; + c2 -= cross[2].x; + break; + case GDISP_ROTATE_270: + c0 = c1 = c2 = gdispGGetHeight(m->display) - 1; + c0 -= cross[0].y; + c1 -= cross[1].y; + c2 -= cross[2].y; + break; + default: + break; + } } - #else - (void) g; - - c0 = cross[0].x; - c1 = cross[1].x; - c2 = cross[2].x; #endif /* Compute all the required determinants */ dx = (float)(points[0].x - points[2].x) * (float)(points[1].y - points[2].y) - (float)(points[1].x - points[2].x) * (float)(points[0].y - points[2].y); - c->ax = ((float)(c0 - c2) * (float)(points[1].y - points[2].y) - - (float)(c1 - c2) * (float)(points[0].y - points[2].y)) / dx; - c->bx = ((float)(c1 - c2) * (float)(points[0].x - points[2].x) - - (float)(c0 - c2) * (float)(points[1].x - points[2].x)) / dx; - c->cx = (c0 * ((float)points[1].x * (float)points[2].y - (float)points[2].x * (float)points[1].y) - - c1 * ((float)points[0].x * (float)points[2].y - (float)points[2].x * (float)points[0].y) - + c2 * ((float)points[0].x * (float)points[1].y - (float)points[1].x * (float)points[0].y)) / dx; + m->caldata.ax = ((float)(c0 - c2) * (float)(points[1].y - points[2].y) + - (float)(c1 - c2) * (float)(points[0].y - points[2].y)) / dx; + m->caldata.bx = ((float)(c1 - c2) * (float)(points[0].x - points[2].x) + - (float)(c0 - c2) * (float)(points[1].x - points[2].x)) / dx; + m->caldata.cx = (c0 * ((float)points[1].x * (float)points[2].y - (float)points[2].x * (float)points[1].y) + - c1 * ((float)points[0].x * (float)points[2].y - (float)points[2].x * (float)points[0].y) + + c2 * ((float)points[0].x * (float)points[1].y - (float)points[1].x * (float)points[0].y)) / dx; + + // Work on y values + c0 = cross[0].y; + c1 = cross[1].y; + c2 = cross[2].y; #if GDISP_NEED_CONTROL - switch(gdispGGetOrientation(g)) { - case GDISP_ROTATE_90: - c0 = c1 = c2 = gdispGGetWidth(g) - 1; - c0 -= cross[0].x; - c1 -= cross[1].x; - c2 -= cross[2].x; - break; - case GDISP_ROTATE_180: - c0 = c1 = c2 = gdispGGetHeight(g) - 1; - c0 -= cross[0].y; - c1 -= cross[1].y; - c2 -= cross[2].y; - break; - case GDISP_ROTATE_270: - c0 = cross[0].x; - c1 = cross[1].x; - c2 = cross[2].x; - break; - case GDISP_ROTATE_0: - default: - c0 = cross[0].y; - c1 = cross[1].y; - c2 = cross[2].y; - break; - } - #else - c0 = cross[0].y; - c1 = cross[1].y; - c2 = cross[2].y; - #endif - - c->ay = ((float)(c0 - c2) * (float)(points[1].y - points[2].y) - - (float)(c1 - c2) * (float)(points[0].y - points[2].y)) / dx; - c->by = ((float)(c1 - c2) * (float)(points[0].x - points[2].x) - - (float)(c0 - c2) * (float)(points[1].x - points[2].x)) / dx; - c->cy = (c0 * ((float)points[1].x * (float)points[2].y - (float)points[2].x * (float)points[1].y) - - c1 * ((float)points[0].x * (float)points[2].y - (float)points[2].x * (float)points[0].y) - + c2 * ((float)points[0].x * (float)points[1].y - (float)points[1].x * (float)points[0].y)) / dx; - } -#endif - -#if GINPUT_MOUSE_READ_CYCLES > 1 - static void get_raw_reading(MouseReading *pt) { - int32_t x, y, z; - unsigned i; - - x = y = z = 0; - for(i = 0; i < GINPUT_MOUSE_READ_CYCLES; i++) { - ginput_lld_mouse_get_reading(pt); - x += pt->x; - y += pt->y; - z += pt->z; - } - - /* Take the average of the readings */ - pt->x = x / GINPUT_MOUSE_READ_CYCLES; - pt->y = y / GINPUT_MOUSE_READ_CYCLES; - pt->z = z / GINPUT_MOUSE_READ_CYCLES; - } -#else - #define get_raw_reading(pt) ginput_lld_mouse_get_reading(pt) -#endif - -static void get_calibrated_reading(MouseReading *pt) { - get_raw_reading(pt); - - #if GINPUT_MOUSE_NEED_CALIBRATION - _tsTransform(pt, &MouseConfig.caldata); - #endif - - _tsOrientClip(pt, MouseConfig.display, !(MouseConfig.flags & FLG_CAL_RAW)); -} - -static void MousePoll(void *param) { - (void) param; - GSourceListener *psl; - GEventMouse *pe; - unsigned meta; - uint16_t upbtns, dnbtns; - uint32_t cdiff; - uint32_t mdiff; - - // Save the last mouse state - MouseConfig.last_buttons = MouseConfig.t.buttons; - - // Get the new mouse reading - get_calibrated_reading(&MouseConfig.t); - - // Calculate out new event meta value and handle CLICK and CXTCLICK - dnbtns = MouseConfig.t.buttons & ~MouseConfig.last_buttons; - upbtns = ~MouseConfig.t.buttons & MouseConfig.last_buttons; - meta = GMETA_NONE; - - // As the touch moves up we need to return a point at the old position because some - // controllers return garbage with the mouse up - if ((upbtns & GINPUT_MOUSE_BTN_LEFT)) { - MouseConfig.t.x = MouseConfig.movepos.x; - MouseConfig.t.y = MouseConfig.movepos.y; - } - - // Calculate the position difference from our movement reference (update the reference if out of range) - mdiff = (MouseConfig.t.x - MouseConfig.movepos.x) * (MouseConfig.t.x - MouseConfig.movepos.x) + - (MouseConfig.t.y - MouseConfig.movepos.y) * (MouseConfig.t.y - MouseConfig.movepos.y); - if (mdiff > GINPUT_MOUSE_MAX_MOVE_JITTER * GINPUT_MOUSE_MAX_MOVE_JITTER) { - MouseConfig.movepos.x = MouseConfig.t.x; - MouseConfig.movepos.y = MouseConfig.t.y; - } - - // Check if the click has moved outside the click area and if so cancel the click - if ((MouseConfig.flags & FLG_CLICK_TIMER)) { - cdiff = (MouseConfig.t.x - MouseConfig.clickpos.x) * (MouseConfig.t.x - MouseConfig.clickpos.x) + - (MouseConfig.t.y - MouseConfig.clickpos.y) * (MouseConfig.t.y - MouseConfig.clickpos.y); - if (cdiff > GINPUT_MOUSE_MAX_CLICK_JITTER * GINPUT_MOUSE_MAX_CLICK_JITTER) - MouseConfig.flags &= ~FLG_CLICK_TIMER; - } - - // Mouse down - if ((dnbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT))) { - MouseConfig.clickpos.x = MouseConfig.t.x; - MouseConfig.clickpos.y = MouseConfig.t.y; - MouseConfig.clicktime = gfxSystemTicks(); - MouseConfig.flags |= FLG_CLICK_TIMER; - if ((dnbtns & GINPUT_MOUSE_BTN_LEFT)) - meta |= GMETA_MOUSE_DOWN; - } - - // Mouse up - if ((upbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT))) { - if ((upbtns & GINPUT_MOUSE_BTN_LEFT)) - meta |= GMETA_MOUSE_UP; - if ((MouseConfig.flags & FLG_CLICK_TIMER)) { - if ((upbtns & GINPUT_MOUSE_BTN_LEFT) - #if GINPUT_MOUSE_CLICK_TIME != TIME_INFINITE - && gfxSystemTicks() - MouseConfig.clicktime < gfxMillisecondsToTicks(GINPUT_MOUSE_CLICK_TIME) - #endif - ) - meta |= GMETA_MOUSE_CLICK; - else - meta |= GMETA_MOUSE_CXTCLICK; - MouseConfig.flags &= ~FLG_CLICK_TIMER; - } - } - - // Send the event to the listeners that are interested. - psl = 0; - while ((psl = geventGetSourceListener((GSourceHandle)(&MouseConfig), psl))) { - if (!(pe = (GEventMouse *)geventGetEventBuffer(psl))) { - // This listener is missing - save the meta events that have happened - psl->srcflags |= meta; - continue; - } - - // If we haven't really moved (and there are no meta events) don't bother sending the event - if (mdiff <= GINPUT_MOUSE_MAX_MOVE_JITTER * GINPUT_MOUSE_MAX_MOVE_JITTER && !psl->srcflags - && !meta && MouseConfig.last_buttons == MouseConfig.t.buttons && !(psl->listenflags & GLISTEN_MOUSENOFILTER)) - continue; - - // Send the event if we are listening for it - if (((MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT) && (psl->listenflags & GLISTEN_MOUSEDOWNMOVES)) - || (!(MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT) && (psl->listenflags & GLISTEN_MOUSEUPMOVES)) - || (meta && (psl->listenflags & GLISTEN_MOUSEMETA))) { - pe->type = GINPUT_MOUSE_EVENT_TYPE; - pe->instance = 0; - pe->x = MouseConfig.t.x; - pe->y = MouseConfig.t.y; - pe->z = MouseConfig.t.z; - pe->current_buttons = MouseConfig.t.buttons; - pe->last_buttons = MouseConfig.last_buttons; - pe->meta = meta; - if (psl->srcflags) { - pe->current_buttons |= GINPUT_MISSED_MOUSE_EVENT; - pe->meta |= psl->srcflags; - psl->srcflags = 0; - } - pe->display = MouseConfig.display; - geventSendEvent(psl); - } - } -} - -GSourceHandle ginputGetMouse(uint16_t instance) { - #if GINPUT_MOUSE_NEED_CALIBRATION - Calibration *pc; - #endif - - // We only support a single mouse instance currently - // Instance 9999 is the same as instance 0 except that it installs - // a special "raw" calibration if there isn't one we can load. - if (instance && instance != 9999) - return 0; - - // Make sure we have a valid mouse display - if (!MouseConfig.display) - MouseConfig.display = GDISP; - - // Do we need to initialise the mouse subsystem? - if (!(MouseConfig.flags & FLG_INIT_DONE)) { - ginput_lld_mouse_init(); - - #if GINPUT_MOUSE_NEED_CALIBRATION - #if GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE - if (!MouseConfig.fnloadcal) { - MouseConfig.fnloadcal = ginput_lld_mouse_calibration_load; - MouseConfig.flags &= ~FLG_CAL_FREE; + if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_SELFROTATION)) { + switch(gdispGGetOrientation(m->display)) { + case GDISP_ROTATE_90: + c0 = c1 = c2 = gdispGGetWidth(m->display) - 1; + c0 -= cross[0].x; + c1 -= cross[1].x; + c2 -= cross[2].x; + break; + case GDISP_ROTATE_180: + c0 = c1 = c2 = gdispGGetHeight(m->display) - 1; + c0 -= cross[0].y; + c1 -= cross[1].y; + c2 -= cross[2].y; + break; + case GDISP_ROTATE_270: + c0 = cross[0].x; + c1 = cross[1].x; + c2 = cross[2].x; + break; + default: + break; } - if (!MouseConfig.fnsavecal) - MouseConfig.fnsavecal = ginput_lld_mouse_calibration_save; - #endif - if (MouseConfig.fnloadcal && (pc = (Calibration *)MouseConfig.fnloadcal(instance))) { - memcpy(&MouseConfig.caldata, pc, sizeof(MouseConfig.caldata)); - MouseConfig.flags |= (FLG_CAL_OK|FLG_CAL_SAVED); - if ((MouseConfig.flags & FLG_CAL_FREE)) - gfxFree((void *)pc); - } else if (instance == 9999) { - _tsSetIdentity(&MouseConfig.caldata); - MouseConfig.flags |= (FLG_CAL_OK|FLG_CAL_SAVED|FLG_CAL_RAW); - } else - ginputCalibrateMouse(instance); + } #endif - // Get the first reading - MouseConfig.last_buttons = 0; - get_calibrated_reading(&MouseConfig.t); - - // Mark init as done and start the Poll timer - MouseConfig.flags |= FLG_INIT_DONE; - gtimerStart(&MouseTimer, MousePoll, 0, TRUE, GINPUT_MOUSE_POLL_PERIOD); + m->caldata.ay = ((float)(c0 - c2) * (float)(points[1].y - points[2].y) + - (float)(c1 - c2) * (float)(points[0].y - points[2].y)) / dx; + m->caldata.by = ((float)(c1 - c2) * (float)(points[0].x - points[2].x) + - (float)(c0 - c2) * (float)(points[1].x - points[2].x)) / dx; + m->caldata.cy = (c0 * ((float)points[1].x * (float)points[2].y - (float)points[2].x * (float)points[1].y) + - c1 * ((float)points[0].x * (float)points[2].y - (float)points[2].x * (float)points[0].y) + + c2 * ((float)points[0].x * (float)points[1].y - (float)points[1].x * (float)points[0].y)) / dx; } - // Return our structure as the handle - return (GSourceHandle)&MouseConfig; + static uint32_t CalibrateMouse(GMouse *m) { + coord_t w, h; + point cross[4]; // The locations of the test points on the display + point points[4]; // The x, y readings obtained from the mouse for each test point + uint32_t err; + #if GDISP_NEED_TEXT + font_t font1, font2; + #endif + + #if GDISP_NEED_TEXT + font1 = gdispOpenFont(CALIBRATION_FONT); + if (!font1) font1 = gdispOpenFont("*"); + font2 = gdispOpenFont(CALIBRATION_FONT2); + if (!font2) font2 = gdispOpenFont("*"); + #endif + err = 0; + w = gdispGGetWidth(m->display); + h = gdispGGetHeight(m->display); + #if GDISP_NEED_CLIP + gdispGSetClip(m->display, 0, 0, w, h); + #endif + + // Ensure we get minimaly processed readings for the calibration + m->flags |= GMOUSE_FLG_IN_CAL; + + // Set up our calibration locations + if ((gmvmt(m)->d.flags & GMOUSE_VFLG_CAL_EXTREMES)) { + cross[0].x = 0; cross[0].y = 0; + cross[1].x = w-1; cross[1].y = 0; + cross[2].x = w-1; cross[2].y = h-1; + cross[3].x = w/2; cross[3].y = h/2; + } else { + cross[0].x = w/4; cross[0].y = h/4; + cross[1].x = w-w/4; cross[1].y = h/4; + cross[2].x = w-w/4; cross[2].y = h-h/4; + cross[3].x = w/2; cross[3].y = h/2; + } + + // Set up the calibration display + gdispGClear(m->display, Blue); + #if GDISP_NEED_TEXT + gdispGFillStringBox(m->display, + 0, CALIBRATION_TITLE_Y, w, CALIBRATION_TITLE_HEIGHT, + CALIBRATION_TITLE, font1, CALIBRATION_TITLE_COLOR, CALIBRATION_TITLE_BACKGROUND, + justifyCenter); + #endif + + // Calculate the calibration + { + unsigned i, maxpoints; + + maxpoints = (gmvmt(m)->d.flags & GMOUSE_VFLG_CAL_TEST) ? 4 : 3; + + // Loop through the calibration points + for(i = 0; i < maxpoints; i++) { + int32_t px, py; + unsigned j; + + // Draw the current calibration point + CalibrationCrossDraw(m, &cross[i]); + + // Get a valid "point pressed" average reading + do { + // Wait for the mouse to be pressed + while(!(m->r.buttons & GINPUT_MOUSE_BTN_LEFT)) + gfxSleepMilliseconds(CALIBRATION_POLL_PERIOD); + + // Sum samples taken every CALIBRATION_POLL_PERIOD milliseconds while the mouse is down + px = py = j = 0; + while((m->r.buttons & GINPUT_MOUSE_BTN_LEFT)) { + // Limit sampling period to prevent overflow + if (j < CALIBRATION_MAXPRESS_PERIOD/CALIBRATION_POLL_PERIOD) { + px += m->r.x; + py += m->r.y; + j++; + } + gfxSleepMilliseconds(CALIBRATION_POLL_PERIOD); + } + + // Ignore presses less than CALIBRATION_MAXPRESS_PERIOD milliseconds + } while(j < CALIBRATION_MINPRESS_PERIOD/CALIBRATION_POLL_PERIOD); + points[i].x = px / j; + points[i].y = py / j; + + // Clear the current calibration point + CalibrationCrossClear(m, &cross[i]); + } + } + + // Apply 3 point calibration algorithm + CalibrationCalculate(m, cross, points); + + /* Verification of correctness of calibration (optional) : + * See if the 4th point (Middle of the screen) coincides with the calibrated + * result. If point is within +/- Squareroot(ERROR) pixel margin, then successful calibration + * Else return the error. + */ + if ((gmvmt(m)->d.flags & GMOUSE_VFLG_CAL_TEST)) { + const GMouseJitter *pj; + + // Are we in pen or finger mode + pj = (m->flags & GMOUSE_FLG_FINGERMODE) ? &gmvmt(m)->finger_jitter : &gmvmt(m)->pen_jitter; + + // Transform the co-ordinates + CalibrationTransform((GMouseReading *)&points[3], &m->caldata); + + // Do we need to rotate the reading to match the display + #if GDISP_NEED_CONTROL + if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_SELFROTATION)) { + coord_t t; + + switch(gdispGGetOrientation(m->display)) { + case GDISP_ROTATE_0: + break; + case GDISP_ROTATE_90: + t = points[3].x; + points[3].x = w - 1 - points[3].y; + points[3].y = t; + break; + case GDISP_ROTATE_180: + points[3].x = w - 1 - points[3].x; + points[3].y = h - 1 - points[3].y; + break; + case GDISP_ROTATE_270: + t = points[3].y; + points[3].y = h - 1 - points[3].x; + points[3].x = t; + break; + default: + break; + } + } + #endif + + // Is this accurate enough? + err = (points[3].x - cross[3].x) * (points[3].x - cross[3].x) + (points[3].y - cross[3].y) * (points[3].y - cross[3].y); + if (err > (uint32_t)pj->calibrate * (uint32_t)pj->calibrate) { + #if GDISP_NEED_TEXT + // No - Display error and return + gdispGFillStringBox(m->display, + 0, CALIBRATION_ERROR_Y, w, CALIBRATION_ERROR_HEIGHT, + CALIBRATION_ERROR_TEXT, font2, CALIBRATION_ERROR_COLOR, CALIBRATION_ERROR_BACKGROUND, + justifyCenter); + gfxSleepMilliseconds(CALIBRATION_ERROR_DELAY); + #endif + } else + err = 0; + } + + // We are done calibrating + #if GDISP_NEED_TEXT + gdispCloseFont(font1); + gdispCloseFont(font2); + #endif + m->flags &= ~GMOUSE_FLG_IN_CAL; + m->flags |= GMOUSE_FLG_CLIP; + + // Save the calibration data (if possible) + if (!err) { + m->flags |= GMOUSE_FLG_CALIBRATE; + + #if GINPUT_TOUCH_USER_CALIBRATION_SAVE + SaveMouseCalibration(gdriverGetDriverInstanceNumber((GDriver *)m), &m->caldata, sizeof(GMouseCalibration)); + #endif + if (gmvmt(m)->calsave) + gmvmt(m)->calsave(m, &m->caldata, sizeof(GMouseCalibration)); + } + + // Force an initial reading + m->r.buttons = 0; + GetMouseReading(m); + + // Clear the screen using the GWIN default background color + #if GFX_USE_GWIN + gdispGClear(m->display, gwinGetDefaultBgColor()); + #else + gdispGClear(m->display, GDISP_STARTUP_COLOR); + #endif + + return err; + } +#endif + +void _gmouseInit(void) { + // GINPUT_MOUSE_DRIVER_LIST is defined - create each driver instance + #if defined(GINPUT_MOUSE_DRIVER_LIST) + { + int i; + + extern GDriverVMTList GINPUT_MOUSE_DRIVER_LIST; + static const struct GDriverVMT const * dclist[] = {GINPUT_MOUSE_DRIVER_LIST}; + + for(i = 0; i < sizeof(dclist)/sizeof(dclist[0]); i++) { + if (!(dclist[i]->flags & GMOUSE_VFLG_DYNAMICONLY)) + gdriverRegister(dclist[i], GDISP); + } + } + + // One and only one mouse + #else + { + extern GDriverVMTList GMOUSEVMT_OnlyOne; + + if (!(GMOUSEVMT_OnlyOne->flags & GMOUSE_VFLG_DYNAMICONLY)) + gdriverRegister(GMOUSEVMT_OnlyOne, GDISP); + } + #endif + } -void ginputSetMouseDisplay(uint16_t instance, GDisplay *g) { - if (instance) +void _gmouseDeinit(void) { + gtimerDeinit(&MouseTimer); +} + +bool_t _gmouseInitDriver(GDriver *g, void *display, unsigned driverinstance, unsigned systeminstance) { + #define m ((GMouse *)g) + (void) systeminstance; + + // The initial display is passed in the parameter for mice + m->display = display; + + #if !GINPUT_TOUCH_NOTOUCH + // Should this mouse start in finger mode? (according to the VMT) + if ((gmvmt(m)->d.flags & GMOUSE_VFLG_DEFAULTFINGER)) + m->flags |= GMOUSE_FLG_FINGERMODE; + #endif + + // Init the mouse + if (!gmvmt(m)->init((GMouse *)g, driverinstance)) + return FALSE; + + // Ensure the Poll timer is started + if (!gtimerIsActive(&MouseTimer)) + gtimerStart(&MouseTimer, MousePoll, 0, TRUE, GINPUT_MOUSE_POLL_PERIOD); + + return TRUE; + + #undef m +} + +void _gmousePostInitDriver(GDriver *g) { + #define m ((GMouse *)g) + + #if !GINPUT_TOUCH_STARTRAW + m->flags |= GMOUSE_FLG_CLIP; + #endif + + #if !GINPUT_TOUCH_NOCALIBRATE && !GINPUT_TOUCH_STARTRAW + if ((gmvmt(m)->d.flags & GMOUSE_VFLG_CALIBRATE)) { + GMouseCalibration *pc; + + #if GINPUT_TOUCH_USER_CALIBRATION_LOAD + if ((pc = (GMouseCalibration *)LoadMouseCalibration(gdriverGetDriverInstanceNumber((GDriver *)m), sizeof(GMouseCalibration)))) { + memcpy(&m->caldata, pc, sizeof(GMouseCalibration)); + #if GINPUT_TOUCH_USER_CALIBRATION_FREE + gfxFree(pc); + #endif + m->flags |= GMOUSE_FLG_CALIBRATE; + } else + #endif + if (gmvmt(m)->calload && (pc = (GMouseCalibration *)gmvmt(m)->calload(m, sizeof(GMouseCalibration)))) { + memcpy(&m->caldata, pc, sizeof(GMouseCalibration)); + if ((gmvmt(m)->d.flags & GMOUSE_VFLG_CAL_LOADFREE)) + gfxFree(pc); + m->flags |= GMOUSE_FLG_CALIBRATE; + } + #if !GINPUT_TOUCH_NOCALIBRATE_GUI + else + while (CalibrateMouse(m)); + #endif + } + #endif + + // Get the first reading + GetMouseReading(m); + + #undef m +} + +void _gmouseDeInitDriver(GDriver *g) { + (void) g; +} + +GSourceHandle ginputGetMouse(unsigned instance) { + if (instance == GMOUSE_ALL_INSTANCES) + return (GSourceHandle)&MouseTimer; + return (GSourceHandle)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance); +} + +void ginputSetMouseDisplay(unsigned instance, GDisplay *g) { + GMouse *m; + + if (!(m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance))) return; - MouseConfig.display = g ? g : GDISP; + m->display = g ? g : GDISP; } -GDisplay *ginputGetMouseDisplay(uint16_t instance) { - if (instance) +GDisplay *ginputGetMouseDisplay(unsigned instance) { + GMouse *m; + + if (!(m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance))) return 0; - return MouseConfig.display; + return m->display; } -bool_t ginputGetMouseStatus(uint16_t instance, GEventMouse *pe) { +bool_t ginputGetMouseStatus(unsigned instance, GEventMouse *pe) { + GMouse *m; + // Win32 threads don't seem to recognise priority and/or pre-emption // so we add a sleep here to prevent 100% polled applications from locking up. gfxSleepMilliseconds(1); - if (instance || (MouseConfig.flags & (FLG_INIT_DONE|FLG_IN_CAL)) != FLG_INIT_DONE) + if (!(m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance))) return FALSE; - pe->type = GINPUT_MOUSE_EVENT_TYPE; - pe->instance = instance; - pe->x = MouseConfig.t.x; - pe->y = MouseConfig.t.y; - pe->z = MouseConfig.t.z; - pe->current_buttons = MouseConfig.t.buttons; - pe->last_buttons = MouseConfig.last_buttons; - if (pe->current_buttons & ~pe->last_buttons & GINPUT_MOUSE_BTN_LEFT) - pe->meta = GMETA_MOUSE_DOWN; - else if (~pe->current_buttons & pe->last_buttons & GINPUT_MOUSE_BTN_LEFT) - pe->meta = GMETA_MOUSE_UP; - else - pe->meta = GMETA_NONE; + #if !GINPUT_TOUCH_NOCALIBRATE_GUI + if ((m->flags & GMOUSE_FLG_IN_CAL)) + return FALSE; + #endif + + #if !GINPUT_TOUCH_NOTOUCH + pe->type = (gmvmt(m)->d.flags & GMOUSE_VFLG_TOUCH) ? GEVENT_TOUCH : GEVENT_MOUSE; + #else + pe->type = GEVENT_MOUSE; + #endif + pe->x = m->r.x; + pe->y = m->r.y; + pe->z = m->r.z; + pe->buttons = m->r.buttons; + pe->display = m->display; return TRUE; } -bool_t ginputCalibrateMouse(uint16_t instance) { - #if !GINPUT_MOUSE_NEED_CALIBRATION - (void) instance; - - return FALSE; - #else +#if !GINPUT_TOUCH_NOTOUCH + void ginputSetFingerMode(unsigned instance, bool_t on) { + GMouse *m; - const coord_t height = gdispGGetHeight(MouseConfig.display); - const coord_t width = gdispGGetWidth(MouseConfig.display); - #if GINPUT_MOUSE_CALIBRATE_EXTREMES - const MousePoint cross[] = {{0, 0}, - {(width - 1) , 0}, - {(width - 1) , (height - 1)}, - {(width / 2), (height / 2)}}; /* Check point */ - #else - const MousePoint cross[] = {{(width / 4), (height / 4)}, - {(width - (width / 4)) , (height / 4)}, - {(width - (width / 4)) , (height - (height / 4))}, - {(width / 2), (height / 2)}}; /* Check point */ - #endif - MousePoint points[GINPUT_MOUSE_CALIBRATION_POINTS]; - const MousePoint *pc; - MousePoint *pt; - int32_t px, py; - unsigned i, j; - font_t font1, font2; - #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0 - unsigned err; - #endif - - if (instance || (MouseConfig.flags & FLG_IN_CAL)) - return FALSE; - - font1 = gdispOpenFont(GINPUT_MOUSE_CALIBRATION_FONT); - font2 = gdispOpenFont(GINPUT_MOUSE_CALIBRATION_FONT2); - - MouseConfig.flags |= FLG_IN_CAL; - gtimerStop(&MouseTimer); - MouseConfig.flags &= ~(FLG_CAL_OK|FLG_CAL_SAVED|FLG_CAL_RAW); - - #if GDISP_NEED_CLIP - gdispGSetClip(MouseConfig.display, 0, 0, width, height); - #endif - - #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0 - while(1) { - #endif - gdispGClear(MouseConfig.display, Blue); - - gdispGFillStringBox(MouseConfig.display, 0, 5, width, 30, GINPUT_MOUSE_CALIBRATION_TEXT, font1, White, Blue, justifyCenter); - - for(i = 0, pt = points, pc = cross; i < GINPUT_MOUSE_CALIBRATION_POINTS; i++, pt++, pc++) { - _tsDrawCross(pc); - - do { - - /* Wait for the mouse to be pressed */ - while(get_raw_reading(&MouseConfig.t), !(MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT)) - gfxSleepMilliseconds(20); - - /* Average all the samples while the mouse is down */ - for(px = py = 0, j = 0; - gfxSleepMilliseconds(20), /* Settling time between readings */ - get_raw_reading(&MouseConfig.t), - (MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT); - j++) { - px += MouseConfig.t.x; - py += MouseConfig.t.y; - } - - } while(!j); - - pt->x = px / j; - pt->y = py / j; - - _tsClearCross(pc); - - if (i >= 1 && pt->x == (pt-1)->x && pt->y == (pt-1)->y) { - gdispGFillStringBox(MouseConfig.display, 0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_SAME_TEXT, font2, Red, Yellow, justifyCenter); - gfxSleepMilliseconds(5000); - gdispGFillArea(MouseConfig.display, 0, 35, width, 40, Blue); - } - - } - - /* Apply 3 point calibration algorithm */ - _tsDo3PointCalibration(cross, points, MouseConfig.display, &MouseConfig.caldata); - - /* Verification of correctness of calibration (optional) : - * See if the 4th point (Middle of the screen) coincides with the calibrated - * result. If point is within +/- Squareroot(ERROR) pixel margin, then successful calibration - * Else, start from the beginning. - */ - #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0 - /* Transform the co-ordinates */ - MouseConfig.t.x = points[3].x; - MouseConfig.t.y = points[3].y; - _tsTransform(&MouseConfig.t, &MouseConfig.caldata); - _tsOrientClip(&MouseConfig.t, MouseConfig.display, FALSE); - - /* Calculate the delta */ - err = (MouseConfig.t.x - cross[3].x) * (MouseConfig.t.x - cross[3].x) + - (MouseConfig.t.y - cross[3].y) * (MouseConfig.t.y - cross[3].y); - - if (err <= GINPUT_MOUSE_MAX_CALIBRATION_ERROR * GINPUT_MOUSE_MAX_CALIBRATION_ERROR) - break; - - gdispGFillStringBox(MouseConfig.display, 0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_ERROR_TEXT, font2, Red, Yellow, justifyCenter); - gfxSleepMilliseconds(5000); - } - #endif - - // Restart everything - gdispCloseFont(font1); - gdispCloseFont(font2); - MouseConfig.flags |= FLG_CAL_OK; - MouseConfig.last_buttons = 0; - get_calibrated_reading(&MouseConfig.t); - MouseConfig.flags &= ~FLG_IN_CAL; - if ((MouseConfig.flags & FLG_INIT_DONE)) - gtimerStart(&MouseTimer, MousePoll, 0, TRUE, GINPUT_MOUSE_POLL_PERIOD); - - // Save the calibration data (if possible) - if (MouseConfig.fnsavecal) { - MouseConfig.fnsavecal(instance, (const uint8_t *)&MouseConfig.caldata, sizeof(MouseConfig.caldata)); - MouseConfig.flags |= FLG_CAL_SAVED; - } - - // Clear the screen using the GWIN default background color - #if GFX_USE_GWIN - gdispGClear(MouseConfig.display, gwinGetDefaultBgColor()); - #else - gdispGClear(MouseConfig.display, Black); - #endif - - return TRUE; - #endif -} - -/* Set the routines to save and fetch calibration data. - * This function should be called before first calling ginputGetMouse() for a particular instance - * as the ginputGetMouse() routine may attempt to fetch calibration data and perform a startup calibration if there is no way to get it. - * If this is called after ginputGetMouse() has been called and the driver requires calibration storage, it will immediately save the data is has already obtained. - * The 'requireFree' parameter indicates if the fetch buffer must be free()'d to deallocate the buffer provided by the Fetch routine. - */ -void ginputSetMouseCalibrationRoutines(uint16_t instance, GMouseCalibrationSaveRoutine fnsave, GMouseCalibrationLoadRoutine fnload, bool_t requireFree) { - #if GINPUT_MOUSE_NEED_CALIBRATION - if (instance) + if (!(m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance))) return; - MouseConfig.fnloadcal = fnload; - MouseConfig.fnsavecal = fnsave; - if (requireFree) - MouseConfig.flags |= FLG_CAL_FREE; + if (on) + m->flags |= GMOUSE_FLG_FINGERMODE; else - MouseConfig.flags &= ~FLG_CAL_FREE; - #if GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE - if (!MouseConfig.fnloadcal) { - MouseConfig.fnloadcal = ginput_lld_mouse_calibration_load; - MouseConfig.flags &= ~FLG_CAL_FREE; - } - if (!MouseConfig.fnsavecal) - MouseConfig.fnsavecal = ginput_lld_mouse_calibration_save; - #endif - if (MouseConfig.fnsavecal && (MouseConfig.flags & (FLG_CAL_OK|FLG_CAL_SAVED)) == FLG_CAL_OK) { - MouseConfig.fnsavecal(instance, (const uint8_t *)&MouseConfig.caldata, sizeof(MouseConfig.caldata)); - MouseConfig.flags |= FLG_CAL_SAVED; - } - #else - (void)instance, (void)fnsave, (void)fnload, (void)requireFree; - #endif -} + m->flags &= ~GMOUSE_FLG_FINGERMODE; -/* Test if a particular mouse instance requires routines to save its calibration data. */ -bool_t ginputRequireMouseCalibrationStorage(uint16_t instance) { - if (instance) - return FALSE; + } +#endif - #if GINPUT_MOUSE_NEED_CALIBRATION && !GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE - return TRUE; - #else - return FALSE; - #endif -} +#if !GINPUT_TOUCH_NOCALIBRATE_GUI + uint32_t ginputCalibrateMouse(unsigned instance) { + GMouse *m; + + // Find the instance + if (!(m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance))) + return 0; + + // Check it needs calibration + if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_CALIBRATE)) + return 0; + + return CalibrateMouse(m); + } +#endif /* Wake up the mouse driver from an interrupt service routine (there may be new readings available) */ -void ginputMouseWakeup(void) { +void _gmouseWakeup(GMouse *m) { + if (m) + m->flags |= GMOUSE_FLG_NEEDREAD; gtimerJab(&MouseTimer); } /* Wake up the mouse driver from an interrupt service routine (there may be new readings available) */ -void ginputMouseWakeupI(void) { +void _gmouseWakeupI(GMouse *m) { + if (m) + m->flags |= GMOUSE_FLG_NEEDREAD; gtimerJabI(&MouseTimer); } diff --git a/src/ginput/ginput_mouse.h b/src/ginput/ginput_mouse.h index 61ad35e0..29405e50 100644 --- a/src/ginput/ginput_mouse.h +++ b/src/ginput/ginput_mouse.h @@ -17,7 +17,7 @@ * * @pre GFX_USE_GINPUT must be set to TRUE in your gfxconf.h * @pre GINPUT_NEED_MOUSE must be set to TRUE in your gfxconf.h - * + * * @{ */ @@ -32,32 +32,29 @@ /* This type definition is also used by touch */ typedef struct GEventMouse_t { - GEventType type; // The type of this event (GEVENT_MOUSE or GEVENT_TOUCH) - uint16_t instance; // The mouse/touch instance - coord_t x, y, z; // The position of the mouse. - // - For touch devices, Z is the current pressure if supported (otherwise 0) - // - For mice, Z is the 3rd dimension if supported (otherwise 0) - uint16_t current_buttons; // A bit is set if the button is down. - // - For touch only bit 0 is relevant - // - For mice the order of the buttons is (from 0 to n) left, right, middle, any other buttons - // - Bit 15 being set indicates that an important mouse event has been missed. - #define GINPUT_MOUSE_BTN_LEFT 0x0001 - #define GINPUT_MOUSE_BTN_RIGHT 0x0002 - #define GINPUT_MOUSE_BTN_MIDDLE 0x0004 - #define GINPUT_MOUSE_BTN_4 0x0008 - #define GINPUT_MISSED_MOUSE_EVENT 0x8000 - #define GINPUT_TOUCH_PRESSED GINPUT_MOUSE_BTN_LEFT - uint16_t last_buttons; // The value of current_buttons on the last event - enum GMouseMeta_e { - GMETA_NONE = 0, // There is no meta event currently happening - GMETA_MOUSE_DOWN = 1, // Button 0 has just gone down - GMETA_MOUSE_UP = 2, // Button 0 has just gone up - GMETA_MOUSE_CLICK = 4, // Button 0 has just gone through a short down - up cycle - GMETA_MOUSE_CXTCLICK = 8 // For mice - The right button has just been depressed - // For touch - a long press has just occurred - } meta; + GEventType type; // The type of this event (GEVENT_MOUSE or GEVENT_TOUCH) + coord_t x, y, z; // The position of the mouse. + // - For touch devices, Z is the current pressure if supported (values are device specific) + // - For mice, Z is the 3rd dimension if supported (values are device specific) + uint16_t buttons; // A bit is set if the button is down or a meta event has occurred. + #define GINPUT_MOUSE_BTN_MASK 0x000F // The "button is down" mask + #define GINPUT_MOUSE_BTN_LEFT 0x0001 // The left mouse button is currently down + #define GINPUT_MOUSE_BTN_RIGHT 0x0002 // The right mouse button is currently down + #define GINPUT_MOUSE_BTN_MIDDLE 0x0004 // The middle mouse button is currently down + #define GINPUT_MOUSE_BTN_4 0x0008 // The 4th mouse button is currently down + #define GINPUT_TOUCH_PRESSED 0x0001 // The touch surface is currently touched + + #define GMETA_MASK 0x00F0 // The "button transition" mask + #define GMETA_NONE 0x0000 // No "button transition" events + #define GMETA_MOUSE_DOWN 0x0010 // Left mouse/touch has just gone down + #define GMETA_MOUSE_UP 0x0020 // Left mouse/touch has just gone up + #define GMETA_MOUSE_CLICK 0x0040 // Left mouse/touch has just gone through a click (short down - up cycle) + #define GMETA_MOUSE_CXTCLICK 0x0080 // Right mouse has just been depressed or touch has gone through a long click + + #define GINPUT_MISSED_MOUSE_EVENT 0x8000 // Oops - a mouse event has previously been missed + GDisplay * display; // The display this mouse is currently associated with. - } GEventMouse; +} GEventMouse; // Mouse/Touch Listen Flags - passed to geventAddSourceToListener() #define GLISTEN_MOUSEMETA 0x0001 // Create events for meta events such as CLICK and CXTCLICK @@ -69,12 +66,13 @@ typedef struct GEventMouse_t { #define GLISTEN_TOUCHUPMOVES GLISTEN_MOUSEUPMOVES #define GLISTEN_TOUCHNOFILTER GLISTEN_MOUSENOFILTER -#define GINPUT_MOUSE_NUM_PORTS 1 // The total number of mouse/touch inputs supported - // Event types for the mouse ginput source #define GEVENT_MOUSE (GEVENT_GINPUT_FIRST+0) #define GEVENT_TOUCH (GEVENT_GINPUT_FIRST+1) +// All mice +#define GMOUSE_ALL_INSTANCES ((unsigned)-1) + /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ @@ -84,16 +82,32 @@ extern "C" { #endif /** - * @brief Creates an instance of a mouse and returns the Source handler - * @note HACK: if the instance is 9999, it is treated as instance 0 except - * that no calibration will be performed! + * @brief Get the Source handler for a mouse using the instance number * - * @param[in] instance The ID of the mouse input instance (from 0 to 9999) + * @param[in] instance The mouse instance number * - * @return The source handle of the created instance + * @return The source handle of the mouse or NULL + * @note You can use the special value of GMOUSE_ALL_INSTANCES to + * get a source handle that returns events for all mice rather + * than a specific mouse. Using GMOUSE_ALL_INSTANCES will always + * return a valid spurce handle even if there are currently no mice + * in the system. */ - GSourceHandle ginputGetMouse(uint16_t instance); - + GSourceHandle ginputGetMouse(unsigned instance); + + /** + * @brief Should this device be in Pen mode or Finger mode + * @note A touch device (and even theoritically a mouse) can operate + * in either pen or finger mode. In finger mode typically a + * touch device will be far more tolerant of movement and other + * inaccuracies. Each driver specifies its own tolerances for + * pen versus finger mode. + * + * @param[in] instance The ID of the mouse input instance + * @param[in] on If true then finger mode is turned on. + */ + void ginputSetFingerMode(unsigned instance, bool_t on); + /** * @brief Assign the display associated with the mouse * @note This only needs to be called if the mouse is associated with a display @@ -105,7 +119,7 @@ extern "C" { * @param[in] instance The ID of the mouse input instance * @param[in] g The GDisplay to which this mouse belongs */ - void ginputSetMouseDisplay(uint16_t instance, GDisplay *g); + void ginputSetMouseDisplay(unsigned instance, GDisplay *g); /** * @brief Get the display currently associated with the mouse @@ -113,7 +127,7 @@ extern "C" { * * @param[in] instance The ID of the mouse input instance */ - GDisplay *ginputGetMouseDisplay(uint16_t instance); + GDisplay *ginputGetMouseDisplay(unsigned instance); /** * @brief Get the current mouse position and button status @@ -125,51 +139,47 @@ extern "C" { * * @return FALSE on an error (eg. invalid instance) */ - bool_t ginputGetMouseStatus(uint16_t instance, GEventMouse *pmouse); + bool_t ginputGetMouseStatus(unsigned instance, GEventMouse *pmouse); /** * @brief Performs a calibration * * @param[in] instance The ID of the mouse input instance * - * @return FALSE if the driver dosen't support a calibration of if the handle is invalid + * @return The calibration error squared if calibration fails, or 0 on success or if the driver dosen't need calibration. + * @note An invalid instance will also return 0. */ - bool_t ginputCalibrateMouse(uint16_t instance); + uint32_t ginputCalibrateMouse(unsigned instance); - /* Set the routines to save and fetch calibration data. - * This function should be called before first calling ginputGetMouse() for a particular instance - * as the gdispGetMouse() routine may attempt to fetch calibration data and perform a startup calibration if there is no way to get it. - * If this is called after gdispGetMouse() has been called and the driver requires calibration storage, it will immediately save the data is has already obtained. - * The 'requireFree' parameter indicates if the fetch buffer must be free()'d to deallocate the buffer provided by the Fetch routine. - */ - typedef void (*GMouseCalibrationSaveRoutine)(uint16_t instance, const uint8_t *calbuf, size_t sz); // Save calibration data - typedef const char * (*GMouseCalibrationLoadRoutine)(uint16_t instance); // Load calibration data (returns NULL if not data saved) + /** + * @brief Load a set of mouse calibration data + * @return A pointer to the data or NULL on failure + * + * @param[in] instance The mouse input instance number + * @param[in] sz The size in bytes of the data to retrieve. + * + * @note This routine is provided by the user application. It is only + * called if GINPUT_TOUCH_USER_CALIBRATION_LOAD has been set to TRUE in the + * users gfxconf.h file. + * @note If GINPUT_TOUCH_USER_CALIBRATION_FREE has been set to TRUE in the users + * gfxconf.h file then the buffer returned will be free'd using gfxFree(). + */ + void *LoadMouseCalibration(unsigned instance, size_t sz); - /** - * @brief Set the routines to store and restore calibration data + /** + * @brief Save a set of mouse calibration data + * @return TRUE if the save operation was successful. + * + * @param[in] instance The mouse input instance number + * @param[in] data The data to save + * @param[in] sz The size in bytes of the data to retrieve. * - * @details This function should be called before first calling ginputGetMouse() for a particular instance - * as the gdispGetMouse() routine may attempt to fetch calibration data and perform a startup calibration if there is no way to get it. - * If this is called after gdispGetMouse() has been called and the driver requires calibration storage, it will immediately save the - * data is has already obtained. - * - * @param[in] instance The ID of the mouse input instance - * @param[in] fnsave The routine to save the data - * @param[in] fnload The routine to restore the data - * @param[in] requireFree TRUE if the buffer returned by the load function must be freed by the mouse code. - */ - void ginputSetMouseCalibrationRoutines(uint16_t instance, GMouseCalibrationSaveRoutine fnsave, GMouseCalibrationLoadRoutine fnload, bool_t requireFree); + * @note This routine is provided by the user application. It is only + * called if GINPUT_TOUCH_USER_CALIBRATION_SAVE has been set to TRUE in the + * users gfxconf.h file. + */ + bool_t SaveMouseCalibration(unsigned instance, const void *data, size_t sz); - /** - * @brief Test if a particular mouse/touch instance requires routines to save it's alibration data - * @note Not implemented yet - * - * @param[in] instance The ID of the mouse input instance - * - * @return TRUE if needed - */ - bool_t ginputRequireMouseCalibrationStorage(uint16_t instance); - #ifdef __cplusplus } #endif diff --git a/src/ginput/sys_options.h b/src/ginput/sys_options.h index c606262b..e67a03ce 100644 --- a/src/ginput/sys_options.h +++ b/src/ginput/sys_options.h @@ -73,40 +73,97 @@ * @{ */ /** - * @brief Use a custom board definition for the mouse/touch driver even if a board definition exists. + * @brief Start touch devices without loading or running calibration. * @details Defaults to FALSE - * @details If TRUE, add ginput_lld_mouse_board.h to your project directory and customise it. - * @note Not all GINPUT mouse/touch low level drivers use board definition files. + * @note This is used if you want to manually control the initial calibration + * process. In practice this is only useful for a touch driver test program. */ - #ifndef GINPUT_MOUSE_USE_CUSTOM_BOARD - #define GINPUT_MOUSE_USE_CUSTOM_BOARD FALSE + #ifndef GINPUT_TOUCH_STARTRAW + #define GINPUT_TOUCH_STARTRAW FALSE + #endif + /** + * @brief Turn off the touch calibration GUI. + * @details Defaults to FALSE + * @note Turning off the calibration GUI just turns off the manual calibration + * process. Readings may still be calibrated if calibration data + * can be loaded. + * @note Calibration requires a lot of code. If your device doesn't require it + * using this option can save a lot of space. + */ + #ifndef GINPUT_TOUCH_NOCALIBRATE_GUI + #define GINPUT_TOUCH_NOCALIBRATE_GUI FALSE #endif /** - * @brief Use a custom board definition for the keyboard driver even if a board definition exists. + * @brief Turn off all touch calibration support. * @details Defaults to FALSE - * @details If TRUE, add ginput_lld_keyboard_board.h to your project directory and customise it. - * @note Not all GINPUT keyboard low level drivers use board definition files. + * @note With this set to TRUE touch readings will not be calibrated. + * @note This automatically turns off the calibration GUI too! + * @note Calibration requires a lot of code. If your device doesn't require it + * using this option can save a lot of space. */ - #ifndef GINPUT_KEYBOARD_USE_CUSTOM_BOARD - #define GINPUT_KEYBOARD_USE_CUSTOM_BOARD FALSE + #ifndef GINPUT_TOUCH_NOCALIBRATE + #define GINPUT_TOUCH_NOCALIBRATE FALSE #endif /** - * @brief Use a custom board definition for the toggle driver even if a board definition exists. + * @brief Turn off all touch support. * @details Defaults to FALSE - * @details If TRUE, add ginput_lld_toggle_board.h to your project directory and customise it. - * @note Not all GINPUT toggle low level drivers use board definition files. + * @note This automatically turns off all calibration and the calibration GUI too! + * @note Touch device handling requires a lot of code. If your device doesn't require it + * using this option can save a lot of space. */ - #ifndef GINPUT_TOGGLE_USE_CUSTOM_BOARD - #define GINPUT_TOGGLE_USE_CUSTOM_BOARD FALSE + #ifndef GINPUT_TOUCH_NOTOUCH + #define GINPUT_TOUCH_NOTOUCH FALSE #endif /** - * @brief Use a custom board definition for the dial driver even if a board definition exists. - * @details Defaults to FALSE - * @details If TRUE, add ginput_lld_dial_board.h to your project directory and customise it. - * @note Not all GINPUT dial low level drivers use board definition files. + * @brief Milliseconds between mouse polls. + * @details Defaults to 25 millseconds + * @note How often mice should be polled. More often leads to smoother mouse movement + * but increases CPU usage. */ - #ifndef GINPUT_DIAL_USE_CUSTOM_BOARD - #define GINPUT_DIAL_USE_CUSTOM_BOARD FALSE + #ifndef GINPUT_MOUSE_POLL_PERIOD + #define GINPUT_MOUSE_POLL_PERIOD 25 + #endif + + /** + * @brief Maximum length of CLICK in milliseconds + * @details Defaults to 300 millseconds + * @note Mouse down to Mouse up times greater than this are not clicks. + */ + #ifndef GINPUT_MOUSE_CLICK_TIME + #define GINPUT_MOUSE_CLICK_TIME 300 + #endif + /** + * @brief Milliseconds to generate a CXTCLICK on a touch device. + * @details Defaults to 700 millseconds + * @note If you hold the touch down for longer than this a CXTCLICK is generated + * but only on a touch device. + */ + #ifndef GINPUT_TOUCH_CXTCLICK_TIME + #define GINPUT_TOUCH_CXTCLICK_TIME 700 + #endif + /** + * @brief There is a user supplied routine to load mouse calibration data + * @details Defaults to FALSE + * @note If TRUE the user must supply the @p LoadMouseCalibration() routine. + */ + #ifndef GINPUT_TOUCH_USER_CALIBRATION_LOAD + #define GINPUT_TOUCH_USER_CALIBRATION_LOAD FALSE + #endif + /** + * @brief The buffer returned by the users @p LoadMouseCalibration() routine must be gfxFree()'d + * by the mouse code. + * @details Defaults to FALSE + */ + #ifndef GINPUT_TOUCH_USER_CALIBRATION_FREE + #define GINPUT_TOUCH_USER_CALIBRATION_FREE FALSE + #endif + /** + * @brief There is a user supplied routine to save mouse calibration data + * @details Defaults to FALSE + * @note If TRUE the user must supply the @p SaveMouseCalibration() routine. + */ + #ifndef GINPUT_TOUCH_USER_CALIBRATION_SAVE + #define GINPUT_TOUCH_USER_CALIBRATION_SAVE FALSE #endif /** @} */ diff --git a/src/ginput/sys_rules.h b/src/ginput/sys_rules.h index f98cc469..d9a367ce 100644 --- a/src/ginput/sys_rules.h +++ b/src/ginput/sys_rules.h @@ -31,6 +31,21 @@ #undef GFX_USE_GTIMER #define GFX_USE_GTIMER TRUE #endif + #if GINPUT_NEED_MOUSE + #if GINPUT_TOUCH_NOTOUCH + // No warning needed for this + #undef GINPUT_TOUCH_NOCALIBRATE + #define GINPUT_TOUCH_NOCALIBRATE TRUE + #endif + #if GINPUT_TOUCH_NOCALIBRATE + // No warning needed for this + #undef GINPUT_TOUCH_NOCALIBRATE_GUI + #define GINPUT_TOUCH_NOCALIBRATE_GUI TRUE + #endif + #if !GINPUT_TOUCH_NOTOUCH && GINPUT_MOUSE_CLICK_TIME > GINPUT_TOUCH_CXTCLICK_TIME + #error "GINPUT MOUSE: The GINPUT_MOUSE_CLICK_TIME must be <= GINPUT_TOUCH_CXTCLICK_TIME" + #endif + #endif #endif #endif /* _GINPUT_RULES_H */ diff --git a/src/gwin/gwin_widget.c b/src/gwin/gwin_widget.c index f85e6f20..cf1f59c7 100644 --- a/src/gwin/gwin_widget.c +++ b/src/gwin/gwin_widget.c @@ -114,7 +114,7 @@ static void gwidgetEvent(void *param, GEvent *pe) { // Is the mouse currently captured by this widget? if ((h->flags & (GWIN_FLG_WIDGET|GWIN_FLG_MOUSECAPTURE)) == (GWIN_FLG_WIDGET|GWIN_FLG_MOUSECAPTURE)) { gh = h; - if ((pme->last_buttons & ~pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) { + if ((pme->buttons & GMETA_MOUSE_UP)) { gh->flags &= ~GWIN_FLG_MOUSECAPTURE; if (wvmt->MouseUp) wvmt->MouseUp(gw, pme->x - gh->x, pme->y - gh->y); @@ -133,7 +133,7 @@ static void gwidgetEvent(void *param, GEvent *pe) { // Process any mouse down over the highest order window if it is an enabled widget if (gh && (gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED)) == (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED)) { - if ((~pme->last_buttons & pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) { + if ((pme->buttons & GMETA_MOUSE_DOWN)) { gh->flags |= GWIN_FLG_MOUSECAPTURE; if (wvmt->MouseDown) wvmt->MouseDown(gw, pme->x - gh->x, pme->y - gh->y); @@ -234,6 +234,7 @@ void _gwidgetInit(void) { geventListenerInit(&gl); geventRegisterCallback(&gl, gwidgetEvent, 0); + geventAttachSource(&gl, ginputGetMouse(GMOUSE_ALL_INSTANCES), GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES); } void _gwidgetDeinit(void) @@ -427,13 +428,10 @@ bool_t gwinAttachListener(GListener *pl) { } #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE - bool_t gwinAttachMouse(uint16_t instance) { - GSourceHandle gsh; - - if (!(gsh = ginputGetMouse(instance))) - return FALSE; - - return geventAttachSource(&gl, gsh, GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES); + bool_t DEPRECATED("This call can now be removed. Attaching the mouse to GWIN is now automatic.") gwinAttachMouse(uint16_t instance) { + // This is now a NULL event because we automatically attach to all mice in the system. + (void) instance; + return TRUE; } #endif diff --git a/src/gwin/gwin_widget.h b/src/gwin/gwin_widget.h index 81c76263..c6bc6d4c 100644 --- a/src/gwin/gwin_widget.h +++ b/src/gwin/gwin_widget.h @@ -199,7 +199,7 @@ void gwinSetDefaultStyle(const GWidgetStyle *pstyle, bool_t updateAll); * @brief Get the current default style. * * @return The current default style. - * + * * @api */ const GWidgetStyle *gwinGetDefaultStyle(void); @@ -305,17 +305,7 @@ void gwinSetCustomDraw(GHandle gh, CustomWidgetDrawFunction fn, void *param); bool_t gwinAttachListener(GListener *pl); #if (GFX_USE_GINPUT && GINPUT_NEED_MOUSE) || defined(__DOXYGEN__) - /** - * @brief Set the mouse to be used to control the widgets - * @return TRUE on success - * - * @param[in] instance The mouse instance - * - * @note Every widget uses the same mouse. - * - * @api - */ - bool_t gwinAttachMouse(uint16_t instance); + bool_t DEPRECATED("This call can now be removed. Attaching the mouse to GWIN is now automatic.") gwinAttachMouse(uint16_t instance); #endif #if (GFX_USE_GINPUT && GINPUT_NEED_TOGGLE) || defined(__DOXYGEN__) diff --git a/tools/touch_driver_test/gfxconf.h b/tools/touch_driver_test/gfxconf.h index 9cd0cf1f..3d93a138 100644 --- a/tools/touch_driver_test/gfxconf.h +++ b/tools/touch_driver_test/gfxconf.h @@ -57,5 +57,6 @@ /* Features for the GINPUT sub-system. */ #define GINPUT_NEED_MOUSE TRUE +#define GINPUT_TOUCH_STARTRAW TRUE #endif /* _GFXCONF_H */ diff --git a/tools/touch_driver_test/main.c b/tools/touch_driver_test/main.c index a8318edd..13136a57 100644 --- a/tools/touch_driver_test/main.c +++ b/tools/touch_driver_test/main.c @@ -29,9 +29,57 @@ #include "gfx.h" +// We get nasty and look at some internal structures - get the relevant information +#include "src/gdriver/sys_defs.h" +#include "src/ginput/driver_mouse.h" + +#include + static GConsoleObject gc; static GListener gl; static font_t font; +static coord_t bWidth, bWidth2, bHeight; +static GHandle ghc; +static coord_t swidth, sheight; + +static void DrawHeader(const char *title, bool_t btnNext, bool_t btnPrev, bool_t btnPlusMinus) { + #if GDISP_NEED_CLIP + gdispSetClip(0, 0, swidth, sheight); + #endif + gdispFillStringBox(0, 0, swidth, bHeight, "Touch Calibration", font, Red, White, justifyLeft); + if (btnNext) + gdispFillStringBox(swidth-1*bWidth, 0, bWidth , bHeight, "Next", font, Black, Gray, justifyCenter); + if (btnPrev) + gdispFillStringBox(swidth-2*bWidth, 0, bWidth-1, bHeight, "Prev", font, Black, Gray, justifyCenter); + if (btnPlusMinus) { + gdispFillStringBox(swidth-2*bWidth-1*bWidth2, 0, bWidth2-1, bHeight, "+", font, Black, Gray, justifyCenter); + gdispFillStringBox(swidth-2*bWidth-2*bWidth2, 0, bWidth2-1, bHeight, "-", font, Black, Gray, justifyCenter); + } + gwinClear(ghc); + gwinSetColor(ghc, Yellow); + gwinPrintf(ghc, "\n%s\n\n", title); + gwinSetColor(ghc, White); +} + +#define BTN_NONE 0 +#define BTN_NEXT 1 +#define BTN_PREV 2 +#define BTN_PLUS 3 +#define BTN_MINUS 4 + +static int CheckButtons(GEventMouse *pem) { + if (pem->y < bHeight && (pem->buttons & GMETA_MOUSE_UP)) { + if (pem->x >= swidth-1*bWidth) + return BTN_NEXT; + if (pem->x >= swidth-2*bWidth) + return BTN_PREV; + if (pem->x >= swidth-2*bWidth-1*bWidth2) + return BTN_PLUS; + if (pem->x >= swidth-2*bWidth-2*bWidth2) + return BTN_MINUS; + } + return BTN_NONE; +} /*------------------------------------------------------------------------* * GINPUT Touch Driver Calibrator. * @@ -39,18 +87,22 @@ static font_t font; int main(void) { GSourceHandle gs; GEventMouse *pem; - coord_t swidth, sheight; - GHandle ghc; - GEventType deviceType; - bool_t calibrated; - coord_t bWidth, bHeight; + bool_t isFirstTime; + bool_t isCalibrated; + bool_t isTouch; + bool_t isFinger; + const char * isFingerText; + const char * deviceText; + GMouse * m; + GMouseVMT * vmt; + GMouseJitter * pjit; + uint32_t calerr; gfxInit(); // Initialize the display // Get the display dimensions swidth = gdispGetWidth(); sheight = gdispGetHeight(); - calibrated = FALSE; // Create our title font = gdispOpenFont("UI2"); @@ -59,8 +111,11 @@ int main(void) { bHeight = gdispGetStringWidth("Prev", font); if (bHeight > bWidth) bWidth = bHeight; bWidth += 4; - bHeight = gdispGetFontMetric(font, fontHeight)+2; - gdispFillStringBox(0, 0, swidth, bHeight, "Touch Calibration", font, Red, White, justifyLeft); + bWidth2 = gdispGetStringWidth("+", font)*2; + bHeight = gdispGetStringWidth("-", font)*2; + if (bHeight > bWidth2) bWidth2 = bHeight; + bWidth2 += 4; + bHeight = gdispGetFontMetric(font, fontHeight)*2+2; // Create our main display window { @@ -70,75 +125,98 @@ int main(void) { wi.show = TRUE; wi.x = 0; wi.y = bHeight; wi.width = swidth; wi.height = sheight-bHeight; ghc = gwinConsoleCreate(&gc, &wi); } - gwinClear(ghc); - // Initialize the mouse in our special no calibration mode. + // Initialize the listener geventListenerInit(&gl); - gs = ginputGetMouse(9999); + + // Copy the current mouse's VMT so we can play with it. + m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, 0); + if (!m) gfxHalt("No mouse instance 0"); + vmt = gfxAlloc(sizeof(GMouseVMT)); + if (!vmt) gfxHalt("Could not allocate memory for mouse VMT"); + memcpy(vmt, m->d.vmt, sizeof(GMouseVMT)); + + // Swap VMT's on the current mouse to our RAM copy + m->d.vmt = (const GDriverVMT *)vmt; + + // Listen for events + gs = ginputGetMouse(0); geventAttachSource(&gl, gs, GLISTEN_MOUSEDOWNMOVES|GLISTEN_MOUSEMETA); + // Get initial display settings for buttons + isFirstTime = TRUE; + isCalibrated = (vmt->d.flags & GMOUSE_VFLG_CALIBRATE) ? FALSE : TRUE; + calerr = 0; + /* * Test: Device Type */ StepDeviceType: - gwinClear(ghc); - gwinSetColor(ghc, Yellow); - gwinPrintf(ghc, "\n1. DEVICE TYPE\n\n"); + DrawHeader("1. Device Type", isCalibrated, isCalibrated && !isFirstTime, isCalibrated); - pem = (GEventMouse *)&gl.event; - ginputGetMouseStatus(0, pem); - deviceType = pem->type; + // Get the type of device and the current mode + isTouch = (vmt->d.flags & GMOUSE_VFLG_TOUCH) ? TRUE : FALSE; + isFinger = (m->flags & GMOUSE_FLG_FINGERMODE) ? TRUE : FALSE; + pjit = isFinger ? &vmt->finger_jitter : &vmt->pen_jitter; + isFingerText = isFinger ? "finger" : "pen"; + deviceText = isTouch ? isFingerText : "mouse"; - gwinSetColor(ghc, White); - gwinPrintf(ghc, "This is detected as a %s device\n\n", - deviceType == GEVENT_MOUSE ? "MOUSE" : (pem->type == GEVENT_TOUCH ? "TOUCH" : "UNKNOWN")); + gwinPrintf(ghc, "This is detected as a %s device\n\n", isTouch ? "TOUCH" : "MOUSE"); + gwinPrintf(ghc, "It is currently in %s mode\n\n", isFinger ? "FINGER" : "PEN"); - if (calibrated) - gwinPrintf(ghc, "Press Next or Back to continue.\n"); - else if (deviceType == GEVENT_MOUSE) - gwinPrintf(ghc, "Click the mouse button to move on to the next test.\n"); - else - gwinPrintf(ghc, "Press and release your finger to move on to the next test.\n"); + if (!isCalibrated) + gwinPrintf(ghc, "Press and release your %s to move on to the next test.\n", deviceText); + else { + gwinPrintf(ghc, "Press + for pen or - for finger.\n"); + if (isFirstTime) + gwinPrintf(ghc, "Press Next to continue.\n"); + else + gwinPrintf(ghc, "Press Next or Back to continue.\n"); + } while(1) { pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); - if (calibrated) { - if (pem->y < bHeight && pem->x >= swidth-2*bWidth) { - if ((pem->meta & GMETA_MOUSE_UP)) { - if (pem->x >= swidth-bWidth) - break; - goto StepClickJitter; - } + if (isCalibrated) { + switch (CheckButtons(pem)) { + case BTN_NEXT: + break; + case BTN_PREV: + if (!isFirstTime) + goto StepDrawing; + continue; + case BTN_PLUS: + m->flags &= ~GMOUSE_FLG_FINGERMODE; + goto StepDeviceType; + case BTN_MINUS: + m->flags |= GMOUSE_FLG_FINGERMODE; + goto StepDeviceType; + default: + continue; } - } else if ((pem->meta & GMETA_MOUSE_UP)) + break; + } + if ((pem->buttons & GMETA_MOUSE_UP)) break; } /* - * Test: Mouse raw reading jitter + * Test: Mouse raw reading */ -StepRawJitter: - gwinClear(ghc); - gwinSetColor(ghc, Yellow); - gwinPrintf(ghc, "\n2. GINPUT_MOUSE_READ_CYCLES\n\n"); - - gwinSetColor(ghc, White); - if (deviceType == GEVENT_MOUSE) - gwinPrintf(ghc, "Press and hold the mouse button.\n\n"); - else +StepRawReading: + DrawHeader("2. Raw Mouse Output", FALSE, FALSE, FALSE); + if (isTouch) gwinPrintf(ghc, "Press and hold on the surface.\n\n"); - gwinPrintf(ghc, "Numbers will display in this window.\n" - "Ensure that values don't jump around very much when your finger is stationary.\n\n" - "Increasing GINPUT_MOUSE_READ_CYCLES helps reduce jitter but increases CPU usage.\n\n"); - - if (calibrated) - gwinPrintf(ghc, "Press Next or Back to continue.\n"); - else if (deviceType == GEVENT_MOUSE) - gwinPrintf(ghc, "Release the mouse button to move on to the next test.\n"); else - gwinPrintf(ghc, "Release your finger to move on to the next test.\n"); + gwinPrintf(ghc, "Press and hold the mouse button.\n\n"); + gwinPrintf(ghc, "The raw values coming from your mouse driver will display.\n\n"); + gwinPrintf(ghc, "Make sure the x and y values change as you move.\n\n"); + + gwinPrintf(ghc, "Release your %s to move on to the next test.\n", deviceText); + + // Make sure we are in uncalibrated mode + m->flags &= ~(GMOUSE_FLG_CALIBRATE|GMOUSE_FLG_CLIP); // For this test turn on ALL mouse movement events geventAttachSource(&gl, gs, GLISTEN_MOUSEDOWNMOVES|GLISTEN_MOUSEUPMOVES|GLISTEN_MOUSEMETA|GLISTEN_MOUSENOFILTER); @@ -148,17 +226,16 @@ StepRawJitter: // mind missing events for this test. gfxSleepMilliseconds(100); pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); - if (calibrated) { - if (pem->y < bHeight && pem->x >= swidth-2*bWidth) { - if ((pem->meta & GMETA_MOUSE_UP)) { - if (pem->x >= swidth-bWidth) - break; - goto StepDeviceType; - } - } - } else if ((pem->meta & GMETA_MOUSE_UP)) + gwinPrintf(ghc, "%u, %u z=%u b=0x%04x\n", pem->x, pem->y, pem->z, pem->buttons & ~GINPUT_MISSED_MOUSE_EVENT); + if ((pem->buttons & GMETA_MOUSE_UP)) break; - gwinPrintf(ghc, "%u:%u z=%u b=0x%04x m=%04x\n", pem->x, pem->y, pem->z, pem->current_buttons, pem->meta); + } + + // Reset to calibrated condition + if (isCalibrated) { + m->flags |= GMOUSE_FLG_CLIP; + if ((vmt->d.flags & GMOUSE_VFLG_CALIBRATE)) + m->flags |= GMOUSE_FLG_CALIBRATE; } // Reset to just changed movements. @@ -169,62 +246,68 @@ StepRawJitter: */ StepCalibrate: - gwinClear(ghc); - gwinSetColor(ghc, Yellow); - gwinPrintf(ghc, "\n3. GINPUT_MOUSE_CALIBRATION_ERROR\n\n"); - gwinSetColor(ghc, Gray); - gwinPrintf(ghc, "Ensure GINPUT_MOUSE_NEED_CALIBRATION = TRUE and GINPUT_MOUSE_CALIBRATION_ERROR is >= 0\n\n"); - gwinSetColor(ghc, White); - gwinPrintf(ghc, "You will be presented with a number of points to touch.\nPress them in turn.\n\n" - "If the calibration repeatedly fails, increase GINPUT_MOUSE_CALIBRATION_ERROR and try again.\n\n"); - - if (calibrated) - gwinPrintf(ghc, "Press Next to start the calibration.\n"); - else if (deviceType == GEVENT_MOUSE) - gwinPrintf(ghc, "Click the mouse button to start the calibration.\n"); + DrawHeader("3. Calibration Jitter", isCalibrated, isCalibrated, isCalibrated); + if ((vmt->d.flags & GMOUSE_VFLG_CALIBRATE)) { + gwinPrintf(ghc, "You will be presented with a number of points to touch.\nPress them in turn.\n\n" + "If the calibration repeatedly fails, increase the jitter for %s calibration and try again.\n\n", isFingerText); + gwinPrintf(ghc, "Pressing the surface for longer gives more accurate results.\n\n"); + if (calerr) + gwinPrintf(ghc, "Last calibration error ^ 2 = %u\n", calerr); + gwinPrintf(ghc, "Calibration jitter (%s) = %u\n", isFingerText, pjit->calibrate); + if (isCalibrated) + gwinPrintf(ghc, "Press + or - to adjust.\n"); + } else { + gwinPrintf(ghc, "This device does not need calibration.\n\n"); + } + if (isCalibrated) + gwinPrintf(ghc, "Press Next or Back to continue.\n"); else - gwinPrintf(ghc, "Press and release your finger to start the calibration.\n"); + gwinPrintf(ghc, "Press and release your %s to move on to start calibration.\n", deviceText); while(1) { pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); - if (calibrated) { - if (pem->y < bHeight && pem->x >= swidth-2*bWidth) { - if ((pem->meta & GMETA_MOUSE_UP)) { - if (pem->x >= swidth-bWidth) - break; - goto StepRawJitter; - } + if (isCalibrated) { + switch (CheckButtons(pem)) { + case BTN_NEXT: + break; + case BTN_PREV: + goto StepRawReading; + case BTN_PLUS: + gwinPrintf(ghc, "Calibration jitter (%s) = %u", isFingerText, ++pjit->calibrate); + continue; + case BTN_MINUS: + gwinPrintf(ghc, "Calibration jitter (%s) = %u", isFingerText, --pjit->calibrate); + continue; + default: + continue; } - } else if ((pem->meta & GMETA_MOUSE_UP)) + break; + } + if ((pem->buttons & GMETA_MOUSE_UP)) break; } // Calibrate - ginputCalibrateMouse(0); - calibrated = TRUE; - - // Calibration used the whole screen - re-establish our title and Next and Previous Buttons - gdispFillStringBox(0, 0, swidth, bHeight, "Touch Calibration", font, Green, White, justifyLeft); - gdispFillStringBox(swidth-2*bWidth, 0, bWidth-1, bHeight, "Prev", font, Black, Gray, justifyCenter); - gdispFillStringBox(swidth-1*bWidth, 0, bWidth , bHeight, "Next", font, Black, Gray, justifyCenter); + if ((vmt->d.flags & GMOUSE_VFLG_CALIBRATE)) { + calerr = ginputCalibrateMouse(0); + if (calerr) + goto StepCalibrate; + isCalibrated = TRUE; + } /* * Test: Mouse coords */ StepMouseCoords: - gwinClear(ghc); - gwinSetColor(ghc, Yellow); - gwinPrintf(ghc, "\n4. Show Mouse Coordinates\n\n"); - - gwinSetColor(ghc, White); - if (deviceType == GEVENT_MOUSE) - gwinPrintf(ghc, "Press and hold the mouse button.\n\n"); - else + DrawHeader("4. Show Mouse Coordinates", TRUE, TRUE, TRUE); + if (isTouch) gwinPrintf(ghc, "Press and hold on the surface.\n\n"); - gwinPrintf(ghc, "Numbers will display in this window.\n" - "Check the coordinates against where it should be on the screen.\n\n"); - + else + gwinPrintf(ghc, "Press and hold the mouse button.\n\n"); + gwinPrintf(ghc, "Check the coordinates against where it should be on the screen.\n\n"); + gwinPrintf(ghc, "X should be 0 to %u\nY should be 0 to %u\n\n", swidth-1, sheight-1); + gwinPrintf(ghc, "Press + to retry using extremes or - for normal calibration.\n"); gwinPrintf(ghc, "Press Next or Back to continue.\n"); // For this test normal mouse movement events @@ -235,15 +318,23 @@ StepMouseCoords: // mind missing events for this test. gfxSleepMilliseconds(100); pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); - if (pem->y < bHeight && pem->x >= swidth-2*bWidth) { - if ((pem->meta & GMETA_MOUSE_UP)) { - if (pem->x >= swidth-bWidth) - break; - goto StepCalibrate; - } + + switch (CheckButtons(pem)) { + case BTN_NEXT: + break; + case BTN_PREV: + goto StepCalibrate; + case BTN_PLUS: + vmt->d.flags |= GMOUSE_VFLG_CAL_EXTREMES; + goto StepCalibrate; + case BTN_MINUS: + vmt->d.flags &= ~GMOUSE_VFLG_CAL_EXTREMES; + goto StepCalibrate; + default: + gwinPrintf(ghc, "%u, %u\n", pem->x, pem->y); + continue; } - if ((pem->current_buttons & GINPUT_MOUSE_BTN_LEFT)) - gwinPrintf(ghc, "%u:%u z=%u\n", pem->x, pem->y, pem->z); + break; } // Reset to just changed movements. @@ -253,66 +344,41 @@ StepMouseCoords: * Test: Mouse movement jitter */ -StepJitter: - gwinClear(ghc); - gwinSetColor(ghc, Yellow); - gwinPrintf(ghc, "\n4. GINPUT_MOUSE_MOVE_JITTER\n\n"); - - gwinSetColor(ghc, White); - if (deviceType == GEVENT_MOUSE) - gwinPrintf(ghc, "Press and hold the mouse button and move around as if to draw.\n\n"); - else +StepMovementJitter: + DrawHeader("5. Movement Jitter", TRUE, TRUE, TRUE); + if (isTouch) gwinPrintf(ghc, "Press firmly on the surface and move around as if to draw.\n\n"); + else + gwinPrintf(ghc, "Press and hold the mouse button and move around as if to draw.\n\n"); - gwinPrintf(ghc, "Dots will display in this window. Ensure that when you stop moving your finger that " - "new dots stop displaying.\nNew dots should only display when your finger is moving.\n\n" - "Adjust GINPUT_MOUSE_MOVE_JITTER to the smallest value that this reliably works for.\n\n"); + gwinPrintf(ghc, "Dots will display in this window. Ensure that when you stop moving your %s that " + "new dots stop displaying.\nNew dots should only display when your %s is moving.\n\n" + "Adjust %s movement jitter to the smallest value that this reliably works for.\n\n", deviceText, deviceText, isFingerText); + gwinPrintf(ghc, "Movement jitter (%s) = %u\n", isFingerText, pjit->move); + gwinPrintf(ghc, "Press + or - to adjust.\n"); gwinPrintf(ghc, "Press Next or Back to continue.\n\n"); while(1) { pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); - if (pem->y < bHeight && pem->x >= swidth-2*bWidth) { - if ((pem->meta & GMETA_MOUSE_UP)) { - if (pem->x >= swidth-bWidth) - break; - goto StepMouseCoords; - } + switch (CheckButtons(pem)) { + case BTN_NEXT: + break; + case BTN_PREV: + goto StepMouseCoords; + case BTN_PLUS: + gwinPrintf(ghc, "Movement jitter (%s) = %u", isFingerText, ++pjit->move); + continue; + case BTN_MINUS: + gwinPrintf(ghc, "Movement jitter (%s) = %u", isFingerText, --pjit->move); + continue; + default: + if ((pem->buttons & GINPUT_MOUSE_BTN_LEFT)) + gwinPrintf(ghc, "."); + continue; } - if ((pem->current_buttons & GINPUT_MOUSE_BTN_LEFT)) - gwinPrintf(ghc, "."); + break; } - /* - * Test: Polling frequency - */ - -StepPolling: - gwinClear(ghc); - gwinSetColor(ghc, Yellow); - gwinPrintf(ghc, "\n5. GINPUT_MOUSE_POLL_PERIOD\n\n"); - - gwinSetColor(ghc, White); - gwinPrintf(ghc, "Press firmly on the surface (or press and hold the mouse button) and move around as if to draw.\n\n"); - gwinPrintf(ghc, "A green line will follow your finger.\n" - "Adjust GINPUT_MOUSE_POLL_PERIOD to the highest value that provides a line without " - "gaps that are too big.\nDecreasing the value increases CPU usage.\n" - "About 25 (millisecs) normally produces good results." - "This test can be ignored for interrupt driven drivers.\n\n"); - gwinPrintf(ghc, "Press Next or Back to continue.\n\n"); - - while(1) { - pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); - if (pem->y < bHeight && pem->x >= swidth-2*bWidth) { - if ((pem->meta & GMETA_MOUSE_UP)) { - if (pem->x >= swidth-bWidth) - break; - goto StepJitter; - } - } - if ((pem->current_buttons & GINPUT_MOUSE_BTN_LEFT)) - gdispDrawPixel(pem->x, pem->y, Green); - } - /* * Test: Click Jitter */ @@ -320,38 +386,76 @@ StepPolling: StepClickJitter: gwinClear(ghc); gwinSetColor(ghc, Yellow); - gwinPrintf(ghc, "\n6. GINPUT_MOUSE_MAX_CLICK_JITTER\n\n"); + gwinPrintf(ghc, "\n6. Click Jitter\n\n"); gwinSetColor(ghc, White); - gwinPrintf(ghc, "Press and release the touch surface to \"click\".\nTry both short and long presses.\n"); - gwinPrintf(ghc, "For a mouse click with the left and right buttons.\n\n"); - gwinPrintf(ghc, "Dots will display in this window. A yellow dash is a left (or short) click. " + if (isTouch) + gwinPrintf(ghc, "Press and release the touch surface to \"click\".\nTry both short and long presses.\n"); + else + gwinPrintf(ghc, "Click the mouse with the left and right buttons.\n\n"); + gwinPrintf(ghc, "A yellow dash is a left (or short) click.\n" "A red x is a right (or long) click.\n\n" - "Adjust GINPUT_MOUSE_CLICK_JITTER to the smallest value that this reliably works for.\n" - "Adjust GINPUT_MOUSE_CLICK_TIME to adjust distinguishing short vs long presses.\n" - "TIME_INFINITE means there are no long presses (although a right mouse button will still work).\n\n" - "Note: moving your finger (mouse) during a click cancels it.\n\n"); - gwinPrintf(ghc, "This is the last test but you can press Next or Back to continue.\n\n"); + "Adjust %s click jitter to the smallest value that this reliably works for.\n" + "Note: moving your %s during a click cancels it.\n\n", isFingerText, deviceText); + gwinPrintf(ghc, "Click jitter (%s) = %u\n", isFingerText, pjit->click); + gwinPrintf(ghc, "Press + or - to adjust.\n"); + gwinPrintf(ghc, "Press Next or Back to continue.\n\n"); + + while(1) { + pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); + switch (CheckButtons(pem)) { + case BTN_NEXT: + break; + case BTN_PREV: + goto StepMovementJitter; + case BTN_PLUS: + gwinPrintf(ghc, "Click jitter (%s) = %u", isFingerText, ++pjit->click); + continue; + case BTN_MINUS: + gwinPrintf(ghc, "Click jitter (%s) = %u", isFingerText, --pjit->click); + continue; + default: + if ((pem->buttons & GMETA_MOUSE_CLICK)) { + gwinSetColor(ghc, Yellow); + gwinPrintf(ghc, "-"); + } + if ((pem->buttons & GMETA_MOUSE_CXTCLICK)) { + gwinSetColor(ghc, Red); + gwinPrintf(ghc, "x"); + } + continue; + } + break; + } + + /* + * Test: Polling frequency + */ + +StepDrawing: + gwinClear(ghc); + gwinSetColor(ghc, Yellow); + gwinPrintf(ghc, "\n7. Drawing\n\n"); + + gwinSetColor(ghc, White); + gwinPrintf(ghc, "Press firmly on the surface (or press and hold the mouse button) and move around as if to draw.\n\n"); + gwinPrintf(ghc, "A green line will follow your %s.\n\n", deviceText); + gwinPrintf(ghc, "Pressing Next will start the tests again but with the option of changing pen/finger mode.\n\n"); + gwinPrintf(ghc, "Press Next or Back to continue.\n\n"); while(1) { pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); if (pem->y < bHeight && pem->x >= swidth-2*bWidth) { - if ((pem->meta & GMETA_MOUSE_UP)) { + if ((pem->buttons & GMETA_MOUSE_UP)) { if (pem->x >= swidth-bWidth) break; - goto StepPolling; + goto StepClickJitter; } } - if ((pem->meta & GMETA_MOUSE_CLICK)) { - gwinSetColor(ghc, Yellow); - gwinPrintf(ghc, "-"); - } - if ((pem->meta & GMETA_MOUSE_CXTCLICK)) { - gwinSetColor(ghc, Red); - gwinPrintf(ghc, "x"); - } + gdispDrawPixel(pem->x, pem->y, Green); } // Can't let this really exit + isFirstTime = FALSE; goto StepDeviceType; } diff --git a/tools/touch_raw_readings/gfxconf.h b/tools/touch_raw_readings/gfxconf.h new file mode 100644 index 00000000..3d93a138 --- /dev/null +++ b/tools/touch_raw_readings/gfxconf.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu + * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _GFXCONF_H +#define _GFXCONF_H + +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE + +/* GFX sub-systems to turn on */ +#define GFX_USE_GDISP TRUE +#define GFX_USE_GWIN TRUE +#define GFX_USE_GEVENT TRUE +#define GFX_USE_GTIMER TRUE +#define GFX_USE_GINPUT TRUE + +/* Features for the GDISP sub-system. */ +#define GDISP_NEED_VALIDATION TRUE +#define GDISP_NEED_CLIP TRUE +#define GDISP_NEED_TEXT TRUE +#define GDISP_NEED_MULTITHREAD TRUE + +/* Builtin Fonts */ +#define GDISP_INCLUDE_FONT_UI2 TRUE + +/* Features for the GWIN sub-system. */ +#define GWIN_NEED_CONSOLE TRUE + +/* Features for the GINPUT sub-system. */ +#define GINPUT_NEED_MOUSE TRUE +#define GINPUT_TOUCH_STARTRAW TRUE + +#endif /* _GFXCONF_H */ diff --git a/tools/touch_raw_readings/main.c b/tools/touch_raw_readings/main.c new file mode 100644 index 00000000..d6c97920 --- /dev/null +++ b/tools/touch_raw_readings/main.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu + * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gfx.h" + +// We get nasty and look at some internal structures - get the relevant information +#include "src/gdriver/sys_defs.h" +#include "src/ginput/driver_mouse.h" + +#include + +static GConsoleObject gc; +static GListener gl; +static font_t font; +static coord_t bHeight; +static GHandle ghc; +static coord_t swidth, sheight; + +/*------------------------------------------------------------------------* + * GINPUT Touch Driver Calibrator. * + *------------------------------------------------------------------------*/ +int main(void) { + GSourceHandle gs; + GEventMouse *pem; + GMouse * m; + GMouseVMT * vmt; + + gfxInit(); // Initialize the display + + // Get the display dimensions + swidth = gdispGetWidth(); + sheight = gdispGetHeight(); + + // Create our title + font = gdispOpenFont("UI2"); + gwinSetDefaultFont(font); + bHeight = gdispGetFontMetric(font, fontHeight)+4; + gdispFillStringBox(0, 0, swidth, bHeight, "Raw Touch Readings", font, Red, White, justifyCenter); + + // Create our main display writing window + { + GWindowInit wi; + + gwinClearInit(&wi); + wi.show = TRUE; wi.x = 0; wi.y = bHeight; wi.width = swidth; wi.height = sheight-bHeight; + ghc = gwinConsoleCreate(&gc, &wi); + } + + // Initialize the listener + geventListenerInit(&gl); + + // Copy the current mouse's VMT so we can play with it. + m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, 0); + if (!m) gfxHalt("No mouse instance 0"); + vmt = gfxAlloc(sizeof(GMouseVMT)); + if (!vmt) gfxHalt("Could not allocate memory for mouse VMT"); + memcpy(vmt, m->d.vmt, sizeof(GMouseVMT)); + + // Swap VMT's on the current mouse to our RAM copy + m->d.vmt = (const GDriverVMT *)vmt; + + // Listen for events + gs = ginputGetMouse(0); + geventAttachSource(&gl, gs, GLISTEN_MOUSEDOWNMOVES|GLISTEN_MOUSEMETA); + + // Make sure we are in uncalibrated pen mode + m->flags &= ~(GMOUSE_FLG_CALIBRATE|GMOUSE_FLG_CLIP|GMOUSE_FLG_FINGERMODE); + + // Pretend we are a mouse, turn off all touch processing, turn off move and click filtering + vmt->d.flags &= ~(GMOUSE_VFLG_TOUCH | GMOUSE_VFLG_ONLY_DOWN | GMOUSE_VFLG_POORUPDOWN); + vmt->pen_jitter.move = 0; + vmt->pen_jitter.click = 0; + + // For this test turn on ALL mouse movement events + geventAttachSource(&gl, gs, GLISTEN_MOUSEDOWNMOVES|GLISTEN_MOUSEUPMOVES|GLISTEN_MOUSEMETA|GLISTEN_MOUSENOFILTER); + + while(1) { + pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); + gwinPrintf(ghc, "%u, %u z=%u b=0x%04x\n", pem->x, pem->y, pem->z, pem->buttons & ~GINPUT_MISSED_MOUSE_EVENT); + + // Always sleep a bit first to enable other events. We actually don't mind missing events. + gfxSleepMilliseconds(100); + } +}