• This looks great - I'm glad you got the setWatch-based touch detection working so well... It'd be really neat on battery powered devices. Now we just need a touchscreen LCD that doesn't draw loads of power! Actually I wonder how well those 320x240 LCDs cope without a backlight - I've never tried them.

    By the way, on the other touchscreen modules I've done before like this I've tended to just have a single callback, and to call it with no arguments when a finger is lifted off. It's probably not better, but it might be best to keep the APIs the same.

  • Now we just need a touchscreen LCD that doesn't draw loads of power!

    1. Without power, you see nothing at all on the LCD, even with white text on black background... So I have to think about some power management to save power: PWM instead of B2.set().
    2. The read xy() could 'de-power' the powered plane to save power.
    3. The scan/poll rate for tracking can be modified from 'snappy to ok' to save some power as well - of course not too much to avoid a too sluggish UI feel...
    4. There may be other power saving options - with the LCD controller chip. Have to look into it.

    ...other touchscreen modules I've done before...

    For a decent touch interface - touch duration (at one point), stay or drag and drag-drop - it is not good enough to have only an onUp... but my API can do all. I picked down as the primary because it enables all options, even just an onUp. And beyond that, whit the down at a particular location, the onTrack and onUp can be modified to that particular location in order to simplify and speed-up the subsequently needed detection processing... Looking at the ADS7843 implementation, the question arise: how much or little - no insult here - a module should do... Initially I had only one callback that received a touch object with the defining parameters inside, such as x and y, time, and state - down, track, up. I dropped it - at least for now - for several reasons, mainly for speed and directness in resource constraint environment, such as Espruino, and because JavaScript applications at first sight use just global functions... hence JavaScript being at first sight 'just' a functional language. I intentionally flipped the 'chicken and egg'... (That JavaScript is at first sight a functional language is last but not least noticeably too by the needed hassle of var _this = this; all over the place when going light-weight object-oriented... alleviated though by some frameworks which introduce an optional parameter following the callback function to provide that 'deferred' resolved this context object. But that becomes cumbersome when having multiple callbacks).

    I'm about to publish a calibration module - it is already working. I needed the code to do initial settings in the TOUCH module for transforming the analog value into pixel coordinates. In the calibration module I just use the onUp - with the very same TOUCH module. Notice the context/callback stack that is implemented in the [0v02] TOUCH module!

    This is the current [0v02] state of the TOUCH nodule:

    // TOUCH.js [0v02] [1v70] 20141018 (c) muet.com
    
    // suggested pins for connect: C0(xn=X-),C1(xp=X+),C2(yn=Y-),C3(yp=Y+)
    // callbacks optional on connect 
    function TOUCH(xn,xp,yn,yp,onDownCB,onTrackCB,onU­pCB) {
      this.xn = xn; this.xp = xp; this.yn = yn; this.yp = yp;
      this.cbs = [[onDownCB,onTrackCB,onUpCB]]; this.upCnt = 0; this.up = true;
      this.x = this.x0 = this.x1 = -1;
      this.y = this.y0 = this.y1 = -1;
      this.t = this.t0 = this.t1 =  0;
      this.tc = 0; this.calib = null;
    }
    
    var pt = TOUCH.prototype;
    
    // tracking Interval in [ms], upThresholds, required up counts
    pt.C =
    { trkIv: 100
    , upThX: 0.08
    , upThY: 0.05
    , upCnt: 2
    , clbTme: 5000
    };
    
    pt.listen = function() {
      var _this = this;
      pinMode(this.xn,"input_pulldown");
      digitalRead(this.xp);
      digitalWrite([this.yn,this.yp],3);
      setWatch( function(){
        pinMode(_this.xn);
        _this.xy(_this._onDown);
       }, this.xp, {edge:rising, repeat:false} );
    };
    
    pt._onDown = function() {
      this.x0 = this.x1 = this.x; this.y0 = this.y1 = this.y;
      this.tc = this.t0 = this.t1 = this.t; this.up = false;
      var q = this.cbs.length - 1;
      if (this.cbs[q][0]) { this.cbs[q][0](this, this.x, this.y, this.t); }
      this.track();
    };
    
    pt.onTrack = function(onTrackCB,onUpCB) {
      var q = this.cbs.length - 1;
      this.cbs[q][1] = onTrackCB;
      this.cbs[q][2] = onUpCB;
    };
    
    pt.track = function() {
      var _this = this; 
      setTimeout(function(){
        _this.xy(_this._onTrack);
       },this.C.trkIv);
    };
    
    
    pt._onTrack = function() {
      var q = this.cbs.length - 1;
      if ((this.x > this.C.upThX) || (this.y > this.C.upThdY)) {
        this.x1 = this.x; this.y1 = this.y; this.t1 = this.t; this.upCnt = 0;
        if (this.t1 - this.tc > this.C.clbTme) {
          if (    (Math.abs((this.x0 - this.x1) / this.x0) < 0.1)
               && (Math.abs((this.y0 - this.y1) / this.y0) < 0.1)
               && this.calib
               && this.calib.step == -1 ) {
            this.tc = -1;
            this.calib.enter();
          } else {
            this.tc = this.t;
          }
        }
        if (this.tc > 0) {
          if (this.cbs[q][1]) { this.cbs[q][1](this, this.x, this.y, this.t); }
          this.track();
        }
      } else {
        if (this.upCnt++ < this.C.upCnt) {
          this.track();
        } else {
          this.x = this.x1; this.y = this.y1; this.t = this.t1; this.up = true;
          if (this.cbs[q][2]) { this.cbs[q][2](this, this.x, this.y, this.t); }
          this.listen();
        }
      }
    };
    
    pt.xy = function(callback) {
      this.t = new Date().getTime();
      pinMode(this.yn,"input_pulldown");
      digitalRead(this.yp);
      digitalWrite([this.xn,this.xp],2);
      this.x = (analogRead(this.yn)+analogRead(this.yn)­+analogRead(this.yn))/3;   
      pinMode(this.xn,"input_pulldown");
      digitalRead(this.xp);
      digitalWrite([this.yn,this.yp],2);
      this.y = (analogRead(this.xn)+analogRead(this.xn)­+analogRead(this.xn))/3;
      if (callback) { callback.call(this); }
    };
    
    exports.connect = function(xn,xp,yn,yp,onDown) {
        var touch = new TOUCH(xn,xp,yn,yp,onDown); touch.listen();
        return touch;
    };
    
    

    So much for calibration for now: TOUCH enters the calibration - or callout - when touching for longer than a specified quite long time at the same location (within +-10% in regard to the onDown). For calibration, the callout darks the screen for a bit for UI feedback, and comes back with five markers to touch - one after the other - to gather data and then perform the calibration / adjustment. The calibration has also a timeout to return when accidentally entered or/and not completed. With more experience, calibration may be needed only once to get a particular type and instance of touch screen going. After that it may not be needed anymore, because the once set parameters stay accurate enough over time. If so, I'n thinking of enabling additional optional parms to provide these values on connect (which leads me to think for some JS extensions, such as the very convenient mix(), mixin(), saveMixin()... I may start other conversations for those matters).

    I have also some thoughts about naming the things... to not restrict the mind when thinking how applying modules. For example, the (optional) calibration intercept/interrupt related things are called something calib..., but it can be used for just anything a user likes to do. Any callback (or callout) could be set, even with coexistence of different ones at different times/states. For a final settling some feedback from the community could help. The current forum does not have a voting implemented/enabled, which could be used for a RFC process... ;-) - Btw, I did not get a single response for the RFC for my Software Buttons - Many buttons from just one hardware button at http://forum.espruino.com/comments/49040­59/.

    Having now some +-experience with the 'cheap' resistive touch screen technology, I'm thinking about capacitive touch screen technology... I do not like the spongy feeling and the noise rate. But first things first: bring the began project(s) to the finish line.

    Attached file: TOUCH.js [0v02]


    1 Attachment

About

Avatar for allObjects @allObjects started