#include "uDisplay.h" #include "uDisplay_config.h" #ifdef USE_UNIVERSAL_TOUCH // ===== Touch IRQ Handler ===== uint8_t ut_irq_flg; void IRAM_ATTR ut_touch_irq(void) { ut_irq_flg = 1; } // ===== Touch Initialization ===== bool uDisplay::utouch_Init(char **name) { *name = ut_name; if (ut_init_code) { if (ut_reset >= 0) { pinMode(ut_reset, OUTPUT); digitalWrite(ut_reset, HIGH); delay(10); digitalWrite(ut_reset, LOW); delay(5); digitalWrite(ut_reset, HIGH); delay(10); } if (ut_irq >= 0) { pinMode(ut_irq, INPUT); attachInterrupt(ut_irq, ut_touch_irq, FALLING); } if (ut_wire) { // I2C touch - no SPI needed ut_spi = nullptr; } else if (spiController && ut_spi_nr == spiController->spi_config.bus_nr) { // SPI touch using same bus as display ut_spi = spiController->getSPI(); } else { // SPI touch using different bus or display doesn't use SPI #ifdef ESP32 ut_spi = SpiBegin(ut_spi_nr); #endif } return ut_execute(ut_init_code); } return false; } // ===== Touch Detection ===== uint16_t uDisplay::touched(void) { if (ut_irq >= 0) { if (!ut_irq_flg) { return false; } ut_irq_flg = 0; } if (ut_touch_code) { return ut_execute(ut_touch_code); } return 0; } // ===== Touch Coordinate Reading ===== int16_t uDisplay::getPoint_x(void) { if (ut_getx_code) { return ut_execute(ut_getx_code); } return 0; } int16_t uDisplay::getPoint_y(void) { if (ut_gety_code) { return ut_execute(ut_gety_code); } return 0; } // ===== Touch Command Execution ===== // ===== Touch Code Translation ===== void uDisplay::ut_trans(char **sp, uint8_t **code) { char *cp = *sp; uint16_t wval; uint8_t tmp_code[64]; uint8_t *ut_code = tmp_code; while (*cp) { if (*cp == ':' || *cp == '#') { break; } if (*cp == ';') { // skip comment line while (*cp) { if (*cp == '\n') { cp++; break; } cp++; } } if (!strncmp(cp, "RDWM", 4)) { // read word many *ut_code++ = UT_RDWM; wval = ut_par(&cp, 0); *ut_code++ = wval>>8; *ut_code++ = wval; wval = ut_par(&cp, 1); if (wval > sizeof(ut_array)) { wval = sizeof(ut_array); } *ut_code++ = wval; } else if (!strncmp(cp, "RDW", 3)) { // read word one *ut_code++ = UT_RDW; wval = ut_par(&cp, 0); *ut_code++ = wval>>8; *ut_code++ = wval; } else if (!strncmp(cp, "RDM", 3)) { // read many *ut_code++ = UT_RDM; *ut_code++ = ut_par(&cp, 0); wval = ut_par(&cp, 1); if (wval > sizeof(ut_array)) { wval = sizeof(ut_array); } *ut_code++ = wval; } else if (!strncmp(cp, "RD", 2)) { // read one *ut_code++ = UT_RD; *ut_code++ = ut_par(&cp, 0); } else if (!strncmp(cp, "CPR", 3)) { // cmp and set *ut_code++ = UT_CPR; *ut_code++ = ut_par(&cp, 0); } else if (!strncmp(cp, "CPM", 3)) { // cmp multiple and set *ut_code++ = UT_CPM; uint8_t num = ut_par(&cp, 0); *ut_code++ = num; for (uint32_t cnt = 0; cnt < num; cnt++) { *ut_code++ = ut_par(&cp, 0); } } else if (!strncmp(cp, "CP", 2)) { // cmp and set *ut_code++ = UT_CP; *ut_code++ = ut_par(&cp, 0); } else if (!strncmp(cp, "RTF", 3)) { // return when false *ut_code++ = UT_RTF; } else if (!strncmp(cp, "RTT", 3)) { // return when true *ut_code++ = UT_RTT; } else if (!strncmp(cp, "MVB", 3)) { // move *ut_code++ = UT_MVB; *ut_code++ = ut_par(&cp, 1); *ut_code++ = ut_par(&cp, 1); } else if (!strncmp(cp, "MV", 2)) { // move *ut_code++ = UT_MV; *ut_code++ = ut_par(&cp, 1); *ut_code++ = ut_par(&cp, 1); } else if (!strncmp(cp, "RT", 2)) { // return status *ut_code++ = UT_RT; } else if (!strncmp(cp, "WRW", 3)) { *ut_code++ = UT_WRW; wval = ut_par(&cp, 0); *ut_code++ = wval>>8; *ut_code++ = wval; wval = ut_par(&cp, 0); *ut_code++ = wval; } else if (!strncmp(cp, "WR", 2)) { *ut_code++ = UT_WR; wval = ut_par(&cp, 0); *ut_code++ = wval; wval = ut_par(&cp, 0); *ut_code++ = wval; } else if (!strncmp(cp, "AND", 3)) { *ut_code++ = UT_AND; wval = ut_par(&cp, 0); *ut_code++ = wval >> 8; *ut_code++ = wval; } else if (!strncmp(cp, "SCL", 3)) { *ut_code++ = UT_SCALE; wval = ut_par(&cp, 1); *ut_code++ = wval >> 8; *ut_code++ = wval; uint32_t lval = ut_par(&cp, 2); *ut_code++ = lval >> 24; *ut_code++ = lval >> 16; *ut_code++ = lval >> 8; *ut_code++ = lval; } else if (!strncmp(cp, "LIM", 3)) { *ut_code++ = UT_LIM; wval = ut_par(&cp, 1); *ut_code++ = wval >> 8; *ut_code++ = wval; } else if (!strncmp(cp, "GSRT", 4)) { *ut_code++ = UT_GSRT; wval = ut_par(&cp, 1); *ut_code++ = wval >> 8; *ut_code++ = wval; } else if (!strncmp(cp, "XPT", 3)) { *ut_code++ = UT_XPT; wval = ut_par(&cp, 1); *ut_code++ = wval >> 8; *ut_code++ = wval; } else if (!strncmp(cp, "DBG", 3)) { *ut_code++ = UT_DBG; wval = ut_par(&cp, 1); *ut_code++ = wval; } cp++; } *ut_code++ = UT_END; *sp = cp - 1; uint16_t memsize = (uint32_t)ut_code - (uint32_t)tmp_code; // allocate memory uint8_t *mp = (uint8_t*)malloc(memsize + 2); if (mp) { memmove(mp, tmp_code, memsize); *code = mp; } } // ===== Touch Parameter Parsing ===== uint32_t uDisplay::ut_par(char **lp, uint32_t mode) { char *cp = *lp; while (*cp != ' ') { if (!cp) break; cp++; } cp++; uint32_t result; if (!mode) { // hex result = strtol(cp, &cp, 16); } else if (mode == 1) { // word result = strtol(cp, &cp, 10); } else { // float as 32bit integer float fval = CharToFloat(cp); result = *(uint32_t*)&fval; while (*cp) { if (*cp == ' ' || *cp =='\n') { break; } cp++; } } *lp = cp; return result; } int16_t uDisplay::ut_execute(uint8_t *ut_code) { int16_t result = 0; uint8_t iob, len; uint16_t wval; while (*ut_code != UT_END) { iob = *ut_code++; switch (iob) { case UT_RD: // read 1 byte ut_code = ut_rd(ut_code, 1, 1); break; case UT_RDM: // read multiple bytes ut_code = ut_rd(ut_code, 2, 1); break; case UT_RDW: // read 1 byte ut_code = ut_rd(ut_code, 1, 2); break; case UT_RDWM: // read multiple bytes ut_code = ut_rd(ut_code, 2, 2); break; case UT_WR: ut_code = ut_wr(ut_code, 1); break; case UT_WRW: ut_code = ut_wr(ut_code, 2); break; case UT_CP: // compare iob = *ut_code++; result = (iob == ut_array[0]); break; case UT_CPM: // compare multiple len = *ut_code++; result = 0; for (uint32_t cnt = 0; cnt < len; cnt++) { iob = *ut_code++; result |= (iob == ut_array[0]); } break; case UT_CPR: // compare iob = *ut_code++; result = (iob == result); break; case UT_RTF: // return when false if (result == 0) { return false; } break; case UT_RTT: // return when true if (result > 0) { return false; } break; case UT_MVB: // move byte from index to high or low result wval = *ut_code++; iob = *ut_code++; if (wval == 0) { result &= 0xff00; result |= ut_array[iob]; } else { result &= 0x00ff; result |= (ut_array[iob] << 8); } break; case UT_MV: // move // source result = *ut_code++; iob = *ut_code++; if (iob == 1) { result = ut_array[result]; } else if (iob == 2) { iob = result; result = ut_array[iob] << 8; result |= ut_array[iob + 1]; } else { iob = result; result = ut_array[iob + 1] << 8; result |= ut_array[iob]; } result &= 0xfff; break; case UT_AND: // and wval = *ut_code++ << 8; wval |= *ut_code++; result &= wval; break; case UT_SCALE: { wval = *ut_code++ << 8; wval |= *ut_code++; result -= wval; uint32_t lval = (uint32_t)*ut_code++ << 24; lval |= (uint32_t)*ut_code++ << 16; lval |= (uint32_t)*ut_code++ << 8; lval |= (uint32_t)*ut_code++; float fval = *(float*)&lval; fval *= (float)result; result = fval; } break; case UT_LIM: wval = *ut_code++ << 8; wval |= *ut_code++; if (result > wval) { result = wval; } break; case UT_RT: // result return result; break; case UT_GSRT: #ifdef UDISPLAY_I80 { // Simple resistive touch using I80 data pins uint32_t val = get_sr_touch(panel_config->i80.data_pins_low[1], // XP panel_config->i80.cs_pin, // XM panel_config->i80.dc_pin, // YP panel_config->i80.data_pins_low[0]); // YM if (val == 0) { return false; } uint16_t xp = val >> 16; uint16_t yp = val; wval = *ut_code++ << 8; wval |= *ut_code++; if (xp > wval && yp > wval) { ut_array[0] = val >> 24; ut_array[1] = val >> 16; ut_array[2] = val >> 8; ut_array[3] = val; return true; } return false; } #endif // UDISPLAY_I80 break; case UT_XPT: wval = *ut_code++ << 8; wval |= *ut_code++; result = ut_XPT2046(wval); break; case UT_DBG: // debug show result wval = *ut_code++; AddLog(LOG_LEVEL_INFO, PSTR("UTDBG %d: %02x : %02x,%02x,%02x,%02x"), wval, result, ut_array[0], ut_array[1], ut_array[2], ut_array[3]); break; case UT_END: break; } } return result; } // ===== Low-Level Touch Communication ===== uint8_t *uDisplay::ut_rd(uint8_t *iop, uint32_t len, uint32_t amode) { if (ut_wire) { // i2c mode ut_wire->beginTransmission(ut_i2caddr); ut_wire->write(*iop++); if (amode == 2) { ut_wire->write(*iop++); } ut_wire->endTransmission(false); if (len > 1) { len = *iop++; } ut_wire->requestFrom(ut_i2caddr, (size_t)len); uint8_t index = 0; while (ut_wire->available()) { ut_array[index++] = ut_wire->read(); } } else { // spi mode if (amode == 1) { uint16_t val = *iop++; uint16_t len = *iop++; if (ut_spi) { digitalWrite(ut_spi_cs, LOW); ut_spi->beginTransaction(ut_spiSettings); ut_spi->transfer(val); val = ut_spi->transfer16(0); ut_spi->endTransaction(); ut_array[len] = val << 8; ut_array[len + 1] = val; digitalWrite(ut_spi_cs, HIGH); } } } return iop; } uint8_t *uDisplay::ut_wr(uint8_t *iop, uint32_t amode) { if (ut_wire) { // i2c mode ut_wire->beginTransmission(ut_i2caddr); ut_wire->write(*iop++); if (amode == 2) { ut_wire->write(*iop++); } ut_wire->write(*iop++); ut_wire->endTransmission(true); } else { // spi mode } return iop; } // ===== XPT2046 Touch Controller ===== uint16_t uDisplay::ut_XPT2046(uint16_t z_th) { uint16_t result = 0; if (ut_spi) { int16_t data[6]; ut_spi->beginTransaction(ut_spiSettings); digitalWrite(ut_spi_cs, LOW); ut_spi->transfer(0xB1 /* Z1 */); int16_t z1 = ut_spi->transfer16(0xC1 /* Z2 */) >> 3; int16_t z = z1 + 4095; int16_t z2 = ut_spi->transfer16(0x91 /* X */) >> 3; z -= z2; if (z >= z_th) { ut_spi->transfer16(0x91 /* X */); // dummy X measure, 1st is always noisy data[0] = ut_spi->transfer16(0xD1 /* Y */) >> 3; data[1] = ut_spi->transfer16(0x91 /* X */) >> 3; // make 3 x-y measurements data[2] = ut_spi->transfer16(0xD1 /* Y */) >> 3; data[3] = ut_spi->transfer16(0x91 /* X */) >> 3; result = 1; } else { data[0] = data[1] = data[2] = data[3] = 0; } data[4] = ut_spi->transfer16(0xD0 /* Y */) >> 3; // Last Y touch power down data[5] = ut_spi->transfer16(0) >> 3; digitalWrite(ut_spi_cs, HIGH); ut_spi->endTransaction(); uint16_t x = besttwoavg(data[0], data[2], data[4]); uint16_t y = besttwoavg(data[1], data[3], data[5]); ut_array[0] = x >> 8; ut_array[1] = x; ut_array[2] = y >> 8; ut_array[3] = y; } return result; } // ===== Touch Data Processing ===== int16_t uDisplay::besttwoavg(int16_t x, int16_t y, int16_t z) { int16_t da, db, dc; int16_t reta = 0; if (x > y) da = x - y; else da = y - x; if (x > z) db = x - z; else db = z - x; if (z > y) dc = z - y; else dc = y - z; if (da <= db && da <= dc) reta = (x + y) >> 1; else if (db <= da && db <= dc) reta = (x + z) >> 1; else reta = (y + z) >> 1; return (reta); } #endif // USE_UNIVERSAL_TOUCH