-
Yeah!... got my first module running... in the sandbox... anyway... thanks for the posts Writing modular code using "require" at http://forum.espruino.com/conversations/256773. I knew about and used the Web available modules from repository only, so far... Now I can easily QA the modules locally before thinking about publishing for use from the Web.
I created a folder, registered it in Web IDE Settings - Project - Sandbox, and placed the TOUCH.js module file in the sandbox's modules folder.
The TOUCH module is now at a stage where I need to combine the TOUCH SCREEN with the LCD for calibration purposes to finish the implementations of the onTouch, onTrack (while touching) and onUp functions. The TOUCH module goes into calibration mode on a very long touch - 5 [s] - with 'no' movement/dragging (<10%) anywhere on the screen. Calibration mode will show spots on the LCD to touch / tap. The spots' x-y coordinates are then formula-mapped to the related, read x-y coordinate values (0.000..0.999) for the calculation of the x-y pixel coordinates of the 240 horizontal x 320 vertical (2.8" TFT 262K Color) LCD.
The TOUCH module so far:
// TOUCH.js [0v01] [1v70] // pins for connect in example: C0,C1,C2,C3 // callbacks optional on connect function TOUCH(xn,xp,yn,yp,onDownCB,onTrackCB,onUpCB) { this.xn = xn; // ...C0 this.xp = xp; // ...C1 this.yn = yn; // ...C2 this.yp = yp; // ...C3 this.onDownCB = onDownCB; this.onTrackCB = onTrackCB; this.onUpCB = onUpCB; this.upCnt = 0; this.x = this.x0 = this.x1 = -1; this.y = this.y0 = this.y1 = -1; this.t = this.t0 = this.t1 = 0; this.tc = 0; } var pt = TOUCH.prototype; // tracking Interval in [ms], upThreshold, required up counts pt.C = { trkIv: 100 , upThX: 0.08 , upThY: 0.05 , upCnt: 2 }; 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; if (this.onDownCB) { this.onDownCB(this, this.x, this.y, this.t); } this.track(); }; pt.onTrack = function(onTrackCB,onUpCB) { this.onTrackCB = onTrackCB; this.onUpCB = onUpCB; }; pt.track = function() { var _this = this; setTimeout(function(){ _this.xy(_this._onTrack); },this.C.trkIv); }; pt._onTrack = function() { 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 > 5000) { if ( (Math.abs((this.x0 - this.x1) / this.x0) < 0.1) && (Math.abs((this.y0 - this.y1) / this.y0) < 0.1) ) { this.tc = -1; this.calib(); } else { this.tc = this.t; } } if (this.tc > 0) { if (this.onTrackCB) { this.onTrackCB(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; if (this.onUpCB) { this.onUpCB(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); } }; pt.calib = function() { // ...(empty) placeholder console.log("*********** calibrate..."); var _this = this; setTimeout(function(){ _this.resume(); },3000); }; pt.resume = function() { console.log("...done **********"); this.listen(); }; exports.connect = function(xn,xp,yn,yp,onDown) { var touch = new TOUCH(xn,xp,yn,yp,onDown); touch.listen(); return touch; };
The TOUCH module usage example (sampling/polling interval on tracking/while touching is 100 [ms] / 10Hz / 10 times per second - defined in .C.trkIv constant):
var cnt = -1, cnt2; require("TOUCH").connect(C0,C1,C2,C3, // suggested default ADC pins function(touch,x,y,t){ // --- onDown callback function cnt2 = 0; console.log(++cnt,cnt2,"onDown:",x,"-",y,"@",t); touch.onTrack( function(touch,x,y,t){ // --- onTrack callback function console.log(cnt,++cnt2,"onTrack:",x,"-",y,"@",t); },function(touch,x,y,t){ // --- onUp callback function // x, y, t values are the same as touch.x1, .y1, and .t1 values console.log(cnt,++cnt2,"onUp:",touch.x0,"-",touch.y0," X ",touch.x1,"-",touch.y1); console.log("...in ",touch.t1 - touch.t0,"[ms]"); touch.xy(); console.log("up:",touch.x,"-",touch.y); }); });
The examples output:
The first number on line - cnt - counts the touches, second number counts the track events. Lines with 5 dots (.....) indicated removed ('redundandent/boring' ) output to keep post conciser.
>echo(0); =undefined " top-left (0,0) corner touch " 0 0 onDown: 0.13021032018 - 0.08894992497 @ 10273559.50381679460 0 1 onTrack: 0.13037308308 - 0.08862439917 @ 10273666.97709923610 0 2 onUp: 0.13021032018 - 0.08894992497 X 0.13037308308 - 0.08862439917 ...in 107.47328244149 [ms] up: 0.04728262251 - 0.02799521883 " top-right (239,0) corner touch " 1 0 onDown: 0.84099590549 - 0.10091299814 @ 10276249.70896946638 ..... 1 3 onUp: 0.84099590549 - 0.10091299814 X 0.84335596754 - 0.10107576104 ...in 214.33396946452 [ms] " bottom-left (0,319) corner touch " 2 0 onDown: 0.14705628035 - 0.85393555606 @ 10277957.31583969481 ..... 2 3 onUp: 0.14705628035 - 0.85393555606 X 0.14062714579 - 0.85491213346 ..... " bottom-right (239,319) corner touch " 3 0 onDown: 0.84058899824 - 0.84799471020 @ 10279814.59160305373 ..... 3 2 onUp: 0.84058899824 - 0.84799471020 X 0.84905266905 - 0.84823885455 ..... " Diagonal touch-drag [top-left (0,0) to bottom-right (239,319)] in 0.5 sec " 4 0 onDown: 0.14648661020 - 0.09521629663 @ 10283725.73377862572 4 1 onTrack: 0.25952544441 - 0.22501970956 @ 10283833.24904580228 4 2 onTrack: 0.46045624475 - 0.42757813890 @ 10283940.03148854896 4 3 onTrack: 0.64901706467 - 0.66057323058 @ 10284046.82061068713 4 4 onTrack: 0.76742707459 - 0.77947152920 @ 10284153.65076335892 4 5 onTrack: 0.80779227384 - 0.82219679051 @ 10284260.44942748174 4 6 onUp: 0.14648661020 - 0.09521629663 X 0.80779227384 - 0.82219679051 ...in 534.71564885601 [ms] " calibration touch/tap of more than 5 secs in the center of the screen " 5 0 onDown: 0.46851300831 - 0.47632562752 @ 10287615.08874045871 5 1 onTrack: 0.47518628722 - 0.47193102922 @ 10287722.65458015352 ..... ..... ..... 5 45 onTrack: 0.47510490577 - 0.47543043157 @ 10292422.00858778692 5 46 onTrack: 0.47616286462 - 0.47559319447 @ 10292528.86354961805 *********** calibrate... ...done ********** " touch in the center of the screen " 6 0 onDown: 0.46590880191 - 0.51237760992 @ 10299584.01717557199 6 1 onTrack: 0.46607156481 - 0.51172655832 @ 10299691.64503816701 6 2 onUp: 0.46590880191 - 0.51237760992 X 0.46607156481 - 0.51172655832 >
Notes:
- All short touches / taps were actually longer then the tracking 100[ms] / 0.1[s] interval / 10Hz
- onUp: row shows the down and up touch/untouch coordinate values.
- The onUp: values are the same as the last onTrack ones...If there is no onTrack event - in other words: the touch was of shorter duration than the tracking interval (of 0.1 [s]) - then the values are the same as the onDown ones.
- For first touch the measured (typical) values for up: are shown (not blanked out).
- Tracking including the (slow) console output used less than 10% of elapsed time: the code made it to 46 of theoretical 50 track points before entering the calibration (placeholder).
- More applications samples - from very simple to quite advanced will be posted at a later time.
- All short touches / taps were actually longer then the tracking 100[ms] / 0.1[s] interval / 10Hz
-
...like that and just took advantage of the Project-Sanbox feature for my Resistive Touchscreen directly (no touch controller) (sub) project at http://forum.espruino.com/conversations/256122
Thanks @DaveNI / / @JumJum for bringing that up and to my attention as a posting subject... (...and same time shame on me not having worked through all tutorials (yet)). - :(< ... :-)
-
After backing out and rebuilding up to including the onDown touch event and investigating how to detect an onUp untouch event, I ended up with a code containing the core elements shown below as listen() and read xy() methods (code uploaded as touch4.js). The read xy() method is not just for reading the coordinates onDown, but later also for possible dragging while touching (onTrack), and - last but not least - for 'untouch' (onUp). Since with every event time is provided in addition to the x-y coordinates, touch durations can be used to determine short, long, very long, and dobule touches or taps.
The code incorporates the suggestions from @Gordon. The essentials in a nutshell:
- detect a touch by hardware event using setWatch() in listen() method- rational: no continuous polling; enter polling mode only while touching for tracking
eliminate the setTimeout() for reading x and y in read xy() method - rational: execution of the JS code provides enough time for the pins to settle on output for powering plane one and on input for analog-reading of plane two.
// touch4.js [1v70] function TOUCH(xn,xp,yn,yp,onDownCB) { // pins in example: C0,C1,C2,C3... this.xn = xn; // ...C0 this.xp = xp; // ...C1 this.yn = yn; // ...C2 this.yp = yp; // ...C3 this.onDownCB = onDownCB; this.x = this.x0 = this.x1 = -1; this.y = this.y0 = this.y1 = -1; this.t = this.t0 = this.t1 = 0; } var pt = TOUCH.prototype; 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.onDownCB(this, this.x0 = this.x, this.y0 = this.y, this.t0 = this.t); }; pt.xy = function(callback) { this.t = new Date().getTime(); digitalRead([this.yn,this.yp]); digitalWrite([this.xn,this.xp],2); this.x = (analogRead(this.yn)+analogRead(this.yn)+analogRead(this.yn))/3; digitalRead([this.xn,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); } }; // ----- var touchModule = { connect: function(xn,xp,yn,yp,onDown) { var touch = new TOUCH(xn,xp,yn,yp,onDown); touch.listen(); return touch; } }; var cnt = -1, cnt2; touchModule.connect(C0,C1,C2,C3,function(touch,x,y,t){ cnt2 = 0; console.log(++cnt,cnt2,"onDown:",x,"-",y,"@",t); setTimeout(function(){ touch.xy(); setTimeout(function(){ console.log("untouched: ",touch.x,"-",touch.y,"@",touch.t); console.log("---"); setTimeout(function(){ touch.listen(); },100); },100); },800); });
This is the output for touching the four corners ( 240 (x) px horizontal x 320 (y) px vertical screen):
- top-left corner (x=0, y=0)
- top-right corner (x=239, y=0)
- bottom-left corner (x=0, y=319)
bottom-right corner (x=239, y=319)
>echo(0); =undefined 0 0 onDown: 0.14363825945 - 0.09122860557 @ 239187.00858778625 untouched: 0.45956104880 - 0.23576206098 @ 239992.94179389314 --- 1 0 onDown: 0.84319320464 - 0.09904122479 @ 243184.38072519082 untouched: 0.45630579079 - 0.23633173113 @ 243990.34160305344 --- 2 0 onDown: 0.14290582640 - 0.85898120597 @ 246428.01812977099 untouched: 0.28068462144 - 0.32902520281 @ 247233.97805343510 --- 3 0 onDown: 0.85588871086 - 0.85653976246 @ 249302.83683206106 untouched: 0.27962666259 - 0.33260598662 @ 250108.79580152672 --- >
The above data shows the trouble in the untouched stage: untouched values are in the range of touch min-max values. Elaborating on different items - even bringing in the reading of the xy from the old touch2.js code with the 1[ms] timeouts, which worked before for detecting the untouched state - did not help. Just having dropped the continuous polling and the timeouts for a faster and cycle/time-leaner execution, I did not want to go back and increase the timeouts to may-be have success.
The analysis of the data - untouched values are influenced by the previously touched area - and the difference between touch2.js and touch4.js code - unintended output-clashes - made me think that there is not enough time to 'discharge' the previously powered plane sufficiently to be ready for reading.
Adding very brief input with pull-down on the reading plane pin AFTER powering the powered plane provided the solution. Somehow, the lingering capacities between the planes in combination with the very sensitive, input-/sink-frugal ADCs lead to the 'misreadings'. Below the xy() method with the added lines to sink-away lingering capacities, and the new, related output data.
pt.xy = function(callback) { this.t = new Date().getTime(); digitalRead([this.yn,this.yp]); digitalWrite([this.xn,this.xp],2); pinMode(this.yn,"input_pulldown"); // <--- extra lines to sink-away pinMode(this.yn); // <--- ...lingering capacities this.x = (analogRead(this.yn)+analogRead(this.yn)+analogRead(this.yn))/3; digitalRead([this.xn,this.xp]); digitalWrite([this.yn,this.yp],2); pinMode(this.xn,"input_pulldown"); // <--- extra lines to sink-away pinMode(this.xn); // <--- ...lingering capacities this.y = (analogRead(this.xn)+analogRead(this.xn)+analogRead(this.xn))/3; if (callback) { callback.call(this); } };
The new data show now untouched values that are comfortably outside of the range of the touched values.
>echo(0); =undefined 0 0 onDown: 0.15332265201 - 0.09342590473 @ 396399.69179389311 untouched: 0.05224689097 - 0.03605198240 @ 397206.41984732821 --- 1 0 onDown: 0.85312174156 - 0.10058747234 @ 399303.29770992364 untouched: 0.05485109737 - 0.03580783805 @ 400110.02385496185 --- 2 0 onDown: 0.13517458864 - 0.86378271152 @ 402053.27290076337 untouched: 0.05843188118 - 0.03605198240 @ 402860.03339694655 --- 3 0 onDown: 0.84970372065 - 0.84156557564 @ 404042.44847328244 untouched: 0.05875740698 - 0.03637750820 @ 404849.19465648854 --- >
The pin-set sequence can now also be optimized towards the added lines. Looking at in what state the pins are left by the reading of xy(), I reduced listen() to just the pulling hight the second edge of the powered plane and call the xy() before the listen() at connect. But for some reason, this made the watch() to trip on a regular basis without a touch happening (and triggered xy() showed also an 'untouch'...). So I left the listen and optimized only the reading of xy(). Playing around while optimizing, I also noticed that keeping the pull-down had no adverse effect, so I eliminated its removal. (The complete code for the touch initialization and touch onDown event detection is uploaded as touch5.js file.)
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); } };
Next steps are now to bring back all the complete onDown, onTrack - track while touching and possibly dragging - and optional on onUp support.
- detect a touch by hardware event using setWatch() in listen() method- rational: no continuous polling; enter polling mode only while touching for tracking
-
@Gordon, I was not talking about pushing data with http to a server... I was talking pushing data to a client. Clients are by definition pullers.
Agreed, with Espruino, every client can also easily be (made) a server and thus receive data from any other client through that client's push / post - directly or indirectly.
To use this pattern of every node in a network being client AND simultaneously server requires managed IPs for every node, makes every node more vulnerable, and requires all nodes to be server-type hardened.
No matter what pattern is applied, there has to be some designated admin node(s), that knows about the topology (of connected) nodes. An upcoming node registers with this admin node(s), and from then on, talking to any other node goes through (one of) the admin node(s) by logical name to target node for simplification of communication. Admin node(s) also enable easily broadcasting to all or some nodes.
-
...have a hard time to detect when to listen again. Btw, in the listen(), setWatch() has to be on C1 and not on C2, because latter has just been set to high and therefore will never rise... ;).
The issue I have is after 'untouch' to read values different from when touched. With suggested readXY() I get values within the touched range. Interestingly, I did not get such values with my initial code (touch2.js). After 'fixing' the listen(), I used a hybrid of suggested listen() and my initially working readXY() code, but with the same result: for untouched I get values within the range of touched.
So, I have to do a bit backing out....
-
@user49225 - I understood it that way - gprs connects over mobile network to Web where as CC3000 connects over wifi (lan) to Web. So much for 'basic connectivity'. The protocol question is still to be discussed. Since it is connectivity to Web and Web is (mostly) http/https and http/s is a pull and not a push protocol, something additional has to be done to have actually a 'send' in place. for that 'send'-matter I mentioned the NIO / CometD / Bayeux items. I welcome the post from @Gordon which shows that Espruino - HW and SW - is built to support multi-connections, but some other devices have to 'get there' as well... We used iOS and OS X - Safari browsers - as well a Android - Chrome browser - to run the html page with the javascript implementation/binding of Bayeux - and therefore, we know, that the browsers managed the multi connection aspect.
-
-
@user49225, are you thinking about something that would use the push/pull over http protocol, such as the CometD / Bayeux Protocol? See http://en.wikipedia.org/wiki/Comet_(programming) and http://svn.cometd.org/trunk/bayeux/bayeux.html.
That would be a really cool thing!... sending JSON objects around between Espruino nodes.
To apply it with Espruino as an http server, Espruino's http server implementation would need to support NIO - non-blocking IO (and multiple concurrent connections), and as a client, it would need to support multiple concurrent connections. Furthermore, the XMLHTTPRequest object - or Web Sockets - would need to be supported... Most modern Web Application servers support CometD/NIO - and Web Sockets. At that time - about 5+ years ago - I used the XMLHttpRequest long polling as implementation technique. For the server I used jetty:// (see http://www.eclipse.org/jetty/ and for clients any devices with http connecting browsers. On jetty:// server I ran a small java servlet which implemented access control (like a registering process) and and routing (forward publishing) written in Java, and on the browser enabled devices, I used - of course - JavaScript for the application (sometimes running in a 'hijacked' embedded browser for Apple iPhone iOS and Android Phone, and 'XUL' modified/hijacked FireFox on laptop/desktop). Today, for (non-Espruino) server, something like node.js could be used to stay within JavaScript language domain, and Web Sockets for simpler, more direct http implementation.
-
...that's why OneWire bus w/ parasitic power slaves has to be master-slave... master knows what the slave needs (power) to finish its job. In parasitic mode, the chip 'survives' on a (built-in) capacitor (with diode between the feeding resister) while stuff for other slaves goes on on the data line as well as when receiving commands for one self. Duty cycle can matter as well. Some devices then do one thing after another and in a much slower fashion to not too quickly deplete the capacitor and run out of power.
-
There are ancient techniques where - on execution - (simple) executors/interpreters write stuff to the code at intended places, such as markers / return/forward addresses addresses (for returns/if-then-elses) etc. If the addresses for these intended places are off, this stuff mutilates the code. This (ancient) techniques make code though non-reentrant (for same or other threads) - see http://en.wikipedia.org/wiki/RCA_1802. DCP1802 had no stack, so the return address was written at the begin of the subroutine, and the return had to pick up this address to continue just where the call / invocation jumped of. Btw, the DCP1802 had also a BASIC interpreter. (I'm amazed that the data sheet http://www.intersil.com/content/dam/Intersil/documents/cdp1/cdp1802ac-3.pdf is from 2008... my experience with the chip and its programming is from the 70'...)
-
Mine is 1.3 with 1v70 stock software. I noticed it when something when something was going on on the board (serial on data) and other setTimeouts were active, and I just sent new code to the board. That was the trigger for me to have always a disconnect or disable option in place 'to quiet the board' before sending updated software. I this case my experience/context of code corruption is differ from what @tom.gidden experienced.
-
I noticed a similar thing when connected to GPS or LCD or both. It feels like someone is poking around in memory - for sure not my code, because I do not use (yet) those instructions and I'm aware of the risk they pose. Reloading the code helped. Since I was in development I did not pay much attention an attributed it to incorrect / run-away code.
Since I wanted to test-run my GPS connection and line processing for days, I tried to catch any irregularities in try-catch blocks... but somehow I could not get it working. The errors - a GPS sentence field was unexpectedly empty - just let's the thread die and luckily, the next on.data will keep the processing (re-)going.
@tom.gidden, I'm glad you brought this up, so I feel less 'begin nuts...' or 'seeing ghosts...' ;-)
-
just for safety I'd make sure you switch the pins to inputs before you set the other pins to outputs...
I had intended that - ...crucial... that no output conflicts are there... - but obviously missed to code it properly... :(
Blind or continuous polling is not - practically never - sustainable, especially when not the only thing that has to go on - not just in regard of (battery) power consumption, but more so for wasting cycles. Was going for touch begin and end detection in a later state when having figured out the calculation stuff. For now, I just have the counters. I'll definitively try the provided code...
When I thought about the edge-event drivenness, I was not sure if I would get always a clean edge-trigger because of the voltage divider circuitry of the powered plane edges preset to supply and ground voltage. Your code I read the solution: you set both C2 AND C3 to high, C1 to a float (free, 'un-pulled input), and C0 to (pulled-down) input with (one time only) edge trigger (interrupt set to be fire only once). I see no reason why this should not work for a touch begin-detection. After a begin has been detected, the pin settings for polling and polling will take place until end-detection. End-detection is required - because the trigger has to be setup again (you may notice that in my code has only begin-detection).
When timeout can be dropped, then there is no need for callback pattern either. Callback was only introduced to make delayed reading possible. Some testing could show if the code execution creates enough delay for the outputs and inputs to stabilize / settle.
-
But there is also some good news:
You may wonder whether the edge matters where the sensing sheet is connected. It does not (really). Why: the resistance of the coating from the touch point to the edge is (practically) negligible compared to the ADC pin's input impedance (inner resistance) and therefore practically no power (amperes) flows compared to the power that flows in the powered sheet's resistive coating, which is the voltage divider with the division point at the touch point. In other words, it is as if the pin would connect right there where the touch point is. It's all about Ohm's Law.
And last but not least: your soft, fat finger creates anyway a bit a fuzzy touch area with 'a lot of (electrical) noise'. But because it is fat - compared to the location sensitivity of the touch screen (or pad), there have anyway to be multiple measuring and algorithm that find kind of the center of gravity of the touch point. But to that later.
There are chips out there - touch controllers - that handle all the cases and corner cases, create an interrupt, and deliver (more then less) clean numbers through a simple connection interface (see http://www.espruino.com/ADS7843 - ADS7843 TOUCHSCREEN).
But I want to explore how Espruino can do that, I connect Espruino directly to the edges of the sheets. The mentioned color TFT LCD is (or has) a (transparent) resistive touch screen (on top of the display) and the carrier/breakout board makes the 4 edges available (sequence as on the boards bottom connector from left to right, pins counted from 1...):
// touch2X.js [1v70] [1v99] // updated 20180925 // // Pin Touch Connected to: Connected to left/right /top/bottom edge // on LCD Screen Espruino Board of top/bottom sheet... (TBFO) // Carrier Edges ADC Pin (|||| = touch screen connectors at bottom // Board Label var Orig Pico left of TFT LCD display) // 1. 11: +Y pYp C3 B1 '...... sheet' .... edge // 2. 12: +X pXp C1 A6 '...... sheet' .... edge // 3. 13: -Y pYn C2 A7 '.......sheet' .... edge // 4. 14: -X pXn C0 A5 '.......sheet' .... edge // Uncomment line w/ pin assignments to be used: //var pXn=C0, pXp=C1, pYn=C2, pYp=C3; // pin assignments Original var pXn=A6, pXp=B1, pYn=A7, pYp=A5; // pin assignments Pico var enabled = false; // for start and stop var minMaxDisplayed = true; // ...and 1st time reads determination var cnt,cnt0; // for 'new' tap (touch) detection var x ,xMin ,xMax; var y ,yMin ,yMax; var x2,xMin2,xMax2; var y2,yMin2,yMax2; var toggle = function() { enabled = !enabled; }; var logXY = function() { readXY(function(xy) { if (enabled) { if (minMaxDisplayed) { minMaxDisplayed = false; xMin = 99999; xMax = -9999; yMin = 99999; yMax = -9999; xMin2 = 99999; xMax2 = -9999; yMin2 = 99999; yMax2 = -9999; cnt = 10000; cnt0 = cnt; console.log("----- enabled"); console.log("cycle","x ","y "," ","x2 ","y2 "," ","dx dy"); } cnt++; x = Math.round(xy.x * 10000) ; y = Math.round(xy.y * 10000); x2 = Math.round(xy.x2 * 10000) ; y2 = Math.round(xy.y2 * 10000); if ((x > 1000) || (y > 1000) || (x2 > 1000) || (y2 > 1000)) { if (cnt > cnt0 + 4) { // tap gap detection - 5[Hz] - 200[ms] console.log("-----"); } cnt0 = cnt; xMin = (x < xMin ) ? x : xMin ; xMax = (x > xMax ) ? x : xMax ; yMin = (y < yMin ) ? y : yMin ; yMax = (y > yMax ) ? y : yMax ; xMin2 = (x2 < xMin2) ? x2 : xMin2; xMax2 = (x2 > xMax2) ? x2 : xMax2; yMin2 = (y2 < yMin2) ? y2 : yMin2; yMax2 = (y2 > yMax2) ? y2 : yMax2; console.log(cnt,x,y,"-",x2,y2,"d#",(x-x2),(y-y2)); } } else { if (!minMaxDisplayed) { minMaxDisplayed = true; console.log("----- Min/Max values for x, y, and x2, y2:"); console.log("x [",xMin ,"..",xMax," ] - y [",yMin ,"..",yMax ,"]"); console.log("x2[",xMin2,"..",xMax2,"] - y2[",yMin2,"..",yMax2,"]"); console.log("----- disabled"); } } }); setTimeout("logXY();",50); // 20[Hz] sample rate - 50[ms] }; var readXY = function(callback) { var xy = {}; pXn.set(); pXp.reset(); analogRead(pYn); analogRead(pYp); setTimeout(function(){ xy.x = analogRead(pYn); xy.x2 = analogRead(pYp); pYn.set(); pYp.reset(); analogRead(pXn); analogRead(pXp); setTimeout(function(){ xy.y = analogRead(pXn); xy.y2 = analogRead(pXp); callback(xy); },1); },1); }; function onInit() { enabled = true; logXY(); } setTimeout(onInit,1000);
These are the delivered values:
>toggle() =undefined ----- enabled cycle x y x2 y2 dx dy (post run added comment) ----- ...was tap in top left corner 10146 1338 908 - 1345 903 d# -7 5 10147 1340 896 - 1348 906 d# -8 -10 ----- ...was tap in top right corner 10172 8569 999 - 8574 1003 d# -5 -4 10173 8567 1006 - 8562 999 d# 5 7 10174 8557 1003 - 8555 996 d# 2 7 10175 8450 288 - 8323 405 d# 127 -117 ----- ...was top in bottom left corner 10204 1543 8565 - 1538 8587 d# 5 -22 10205 1533 8574 - 1528 8574 d# 5 0 10206 1531 8555 - 1526 8560 d# 5 -5 10207 1526 8567 - 1533 8565 d# -7 2 ----- ...was tab in bottom right corner 10232 437 415 - 569 8633 d# -132 -8218 10233 8518 8655 - 8508 8650 d# 10 5 10234 8486 8650 - 8499 8648 d# -13 2 10235 8499 8648 - 8504 8662 d# -5 -14 10236 8508 8665 - 8511 8655 d# -3 10 10237 8489 8682 - 8486 8672 d# 3 10 ----- ...was tap in (about) the center 10270 4829 4763 - 4829 4746 d# 0 17 10271 4836 4753 - 4854 4761 d# -18 -8 10272 4834 4756 - 4827 4753 d# 7 3 10273 4834 4763 - 4829 4763 d# 5 0 ----- ...horizontal line starting in top left corner 10304 1448 894 - 1448 903 d# 0 -9 10305 1638 974 - 1638 969 d# 0 5 10306 2344 1050 - 2346 1045 d# -2 5 10307 3274 1106 - 3274 1108 d# 0 -2 10308 4622 1089 - 4612 1091 d# 10 -2 10309 5684 1150 - 5686 1157 d# -2 -7 10310 6729 1184 - 6734 1177 d# -5 7 10311 7537 1157 - 7532 1157 d# 5 0 10312 8113 1123 - 8125 1116 d# -12 7 10313 8284 1138 - 8279 1226 d# 5 -88 ----- ...vertical line starting in top left corner 10333 1433 1091 - 1426 1091 d# 7 0 10334 1423 1416 - 1426 1433 d# -3 -17 10335 1377 2512 - 1389 2522 d# -12 -10 10336 1428 3867 - 1436 3877 d# -8 -10 10340 1272 7954 - 1262 7947 d# 10 7 10341 1265 8552 - 1255 8557 d# 10 -5 ----- ...diagonal line starting in top left corner 10370 393 1116 - 520 1111 d# -127 5 10371 1643 1812 - 1633 1819 d# 10 -7 10372 2427 2874 - 2432 2881 d# -5 -7 10373 3276 3867 - 3281 3879 d# -5 -12 10374 4116 4795 - 4124 4788 d# -8 7 10375 5217 5830 - 5234 5830 d# -17 0 10376 5977 6758 - 5982 6751 d# -5 7 10377 6912 7578 - 6914 7571 d# -2 7 10378 7334 7952 - 7341 7947 d# -7 5 10379 7764 8245 - 7766 8255 d# -2 -10 10380 7857 8389 - 7839 8381 d# 18 8 10381 7859 8589 - 7891 8587 d# -32 2 ----- ...diagonal line starting in bottom left corner 10406 1382 8650 - 1382 8667 d# 0 -17 10407 1631 8362 - 1633 8352 d# -2 10 10408 2302 7559 - 2322 7556 d# -20 3 10409 3355 6453 - 3359 6443 d# -4 10 10410 4587 5125 - 4583 5134 d# 4 -9 10411 5689 3997 - 5693 3994 d# -4 3 10412 6697 2986 - 6692 2981 d# 5 5 10413 7422 2200 - 7439 2205 d# -17 -5 10414 7952 1523 - 7944 1523 d# 8 0 10415 8338 1160 - 8347 1152 d# -9 8 >toggle(); =undefined ----- Min/Max values for x, y, and x2, y2: x [ 393 .. 8569 ] - y [ 288 .. 8682 ] x2[ 520 .. 8574 ] - y2[ 405 .. 8672 ] ----- disabled >
After sending to the board, the code immediately starts running. With a frequency of 20Hz - twenty times per second / in 50[ms] intervals - it invokes the self explanatory logXY() function. Since the code is initialized with var enabled = false, the main part of the function body is skipped. At the end of the method, the method sets a timeout - of 50[ms] - for self-invocation.
After enabling with command toggle(); in command pane, the code initializes some control values and various minimum and maximum variables, and prints a header in the console pane for the values to be logged (lines 27..36). Furthermore, the code starts to count in cnt variable - from 10000 upwards for aligned column oriented output - the cycles - 20 per second - as defined by the setTimeout (line 65) and invokes the reading of x and y (voltage) values. Since the reading needs some setup and settling time, the statistics / calculation and logging is passed as a callback to the readXY() function. More about that readXY() function a bit later.
The callback code will detect when a touch happens by the fact that any of the x or y values are beyond a certain threshold: 1000 (line 40). The threshold's value was determined by some code tinkering and is touch screen dependent. The initial value ranging from 0.0000 to 1 is multiplied by 10000 and rounded to an integer (line 38) to trigger the set threshold, and to ease the - optical - tracking of value changes and detecting value and value change patterns. When the threshold is overstepped, the current cnt counter is checked against the past cnt2 counter and if there is a difference of more than 4 (missed cycles - 200[ms], line 41), the touch (tap) is considered a new one. past cnt2 is updated to current cnt as long as the touch keeps going (line 44).
Lines 45 thru 52 do statistics to keep track of the minimum and maximum values.
Finally, line 53 prints the following values:
- Cycle as counted by cnt variable. It is consecutive for each touch or tap including related moving/draggin on the touch screen. A new touch (or tap) related value sequence is separated from the previous one by a line of five (5) dashes (with posthume added comment about the touch/drag action).
- x and y values - as read from one edge of the sensing sheet.
- x2 and y2 values - as read from other edge of the sensing sheet.
- the differences between x and x2 and y and y2.
As you can see, the difference of the values from both edges are very small compared to the read values (with a few exceptions). This proofs, that is sufficient to read just from one edge of the sensing sheet. Codes touch2.js (as shown above) and touch3.js (reading from one edge of the sensing sheet only) are attached as files at the very bottom of this post.
The reading algorithm with its settings of the pins and stabilization times is in lines 68 thru 87 - implemented as readXY() function.
@Gordon, could you please comment on optimal pin setting and reading including timing and provide advice? = From what I understood from other implementations is that it is crucial for clean measuring that no output conflicts are there and powering of the to-power sheet has to stabilize, as well as the sensing ADC pin has to be ready and eventual capacitive energy has been discharged before measurements are taken. Most applications take multiple measurements and increase the accuracy of the (virtual) touch point coordinates.
If the same effects can be achieved with less statements the better. Because when integrated into any other apps, every spared (cpu) cycle will be welcome to not just detect a touch or swipe, but more so to process it and its related biz or tech process.
So much for now. Next steps will be to get some basic algorithm for increasing accuracy of mapping of read value to actual coordinate on screen. For that, some material is there done as part of designing dedicated touch controllers (see http://www.ti.com/lit/an/sbaa036/sbaa036.pdf, http://www.ti.com/lit/an/slyt277/slyt277.pdf, and most helpful http://www.ti.com/lit/an/sbaa155a/sbaa155a.pdf - Reducing Analog Input Noise in Touch Screen Systems). After that a module will be sketched that includes also some basic calibration support - Do you remember when you had to tap with your stylus X-es in the corners and center of the screen?
Codes attached as files touch2X.js:
- Cycle as counted by cnt variable. It is consecutive for each touch or tap including related moving/draggin on the touch screen. A new touch (or tap) related value sequence is separated from the previous one by a line of five (5) dashes (with posthume added comment about the touch/drag action).
-
An other multi part series
This conversation covers some leg work to be done for next steps in * DIY Marine GPS using enhanced GPS Module, u-blox NEO-6M GPS receiver, and ILI9341 Module controlled 2.8" Color TFT LCD* project (http://forum.espruino.com/conversations/255759) and Exploring 2.8" Color TFT Touch LCD by PacMan Game attempt project (http://forum.espruino.com/conversations/127039).
In both projects I intend to use the touch capability of the display.
The touch screen is a resistive touch screen. A good description you can find at https://www.sparkfun.com/datasheets/LCD/HOW%20DOES%20IT%20WORK.pdf.
Basically, a touch screen consists of two stacked 'sheets' with a small gap in between. When touching the (flexible) top sheet, it will touch the (rigid) bottom sheet in the area of the touch point.
Cross cut / side view: Flexible top sheet: -------------------------------------- small gap Rigid bottom sheet: --------------------------------------
When touching the (flexible) top sheet, it will touch the (rigid) bottom sheet in the are of the touch point.
Because the sheets' facing sides are coated with a conductive material with significant resistance versus a plain wire, and one sheet is put under current with one edge all along the edge to ground (0 Volts) and the opposite edge to supply (3.3 Volts), the other sheet senses at the touch point something in between 0 and 3.3 Volts.
Cross cut / side view: Touched area | V Flexible sheet under power: 0 V |--------------------. @ .-------> 3.3 V small gap \_____/ Rigid sheet sensing touch: 2.2 V <-----------------------^^^-----------
The sensing sheet is connected to a pin (for example, C2) with an analog-to-digital converter (ADC), which provides through analogRead(C3); a voltage-related floating point value from roughly 0.000 to 1. Of course, the edges of the sheet under power are also connected to pins of which one is set to Ground (0 Volts) with C0.reset();, and the other one is set to supply (3.3 Volts) using C1.set(); in order to set that sheet under power.
Assuming a screen of 240 horizontal (x) by 320 vertical (y) resolution and below axis configuration with origin {x:0,y:0} in the top left corner of the screen, and the top sheet's left edge to ground (0 V) at x=0 and right edge to supply (3.3 V) at x=239, a touch point sensing (2.2 V) is about 2 thirds in at about x=160.
Top view: 0V, C0 pins C1, 3.3V | | V ---> x-Axis V .------------------. |0 240| | | Touch | | | point |--. V | \ | | y | @ | | - | : | | A | : | | x | : | | i | top : | | s | powered : | | | : | | |320 : | | '------------------' | | bottom | | | sensing | | '---------o--------' | V ADC pin C3, 2.2V --> x value
But this is only the x-axis value... - what about the y-axis value?
Ingeniously, the the bottom sheet has 90 degrees turned edge connectors as well - at the top and the bottom - of which only the bottom is used for the sensing.
But: now roles of the sheets are flipped:
- The bottom sheet is now put under power by connecting the top edge to ground (0 V) through pin C2 and the bottom edge to (3.3 V) through pin C3.
- The top sheet is now the sensing sheet and connected (by either left or right edge) to the pin with the analog-to-digital converter.
Et voila: we get the value y for the y-axis, because the a touch at the top is (0 V) and corresponds to y=0, and a touch at the bottom corresponds to (3.3 V) and corresponds to y=240; and a touch point a quarter way down will provide (0.825 V = 3.3 / 4 V) corresponding to a value of y=80.
Top view: V ---> x-Axis .------------------. |0 240| | | Touch | pin C2 | | point |--.<----0V V | \ | | y | @ ----o---->0.825V - | | | pin C1 A | | | ADC x | | | --> y i | | | value s | | | | | | |320 top sensing | | '------------------' | | | | bottom powered | '------------------'<---3.3V pin C1
I said basically... because looking into the produced values, it is not that a clear cut - at least not for all values.
There is also much more to the building if a touch screen - for example: In order that the sheets to not accidentally touch by sagging or vibration over a too wide area, very small insulating spacers spread in the gap. But because the top is flexible, touching happens between the spacers (S)... --- Ignore the forum's syntax coloring... ;-)
Cross cut / side view: \ / \ Touching Object: / \ 'Soft, Fat' Finger / ------------. '-.___.-----._________.-' .-------- \ _______ / S '-----' S '-----------' S ----------------^^^-------------^^^^^-------------- ^ ^ | | | | Multiple Touch 'Points'
Edit 2018-07-21: Found attached pic on https://www.epectec.com/articles/the-technology-within-touch-panels.html:
- The bottom sheet is now put under power by connecting the top edge to ground (0 V) through pin C2 and the bottom edge to (3.3 V) through pin C3.
-
-
-
Extended the display with the display of the velocity. Velocity is shown in nautical miles. Code is updated.
Next steps are:
- Migrate code to use GPS module version as recommended by @Gordon in particular post http://forum.espruino.com/comments/11859055/ GPS Module, Extensions, and u-blox NEO-6M GPS receiver
- Add battery power supply, stick it into a water proof box / container, and take it on the water.
- Add Wifi module and create a http server to give access to navi data over LAN / WAN.
- Write a first cut of a browser app - of course in JavaScript - that pulls the data with an AJAX request, processes is and displays it text and graphics... and eventually will drive a widget or window with a google map positioned to the received geo location.
- Add touch 'platform' w/ handling APIs - .handleTouch() .
- Add Pause / Resume / Restart(Warm restart) using touch areas.
- Add touch areas for complete clear of background and redraw of individual rows.
Time line is open....
- Migrate code to use GPS module version as recommended by @Gordon in particular post http://forum.espruino.com/comments/11859055/ GPS Module, Extensions, and u-blox NEO-6M GPS receiver
-
Ic. Many options. For now I have dashed the display speed challenge. With more changing data to display, this may change though, and all options will be back on the table. Fixed font for a limited number of characters / symbols in 1-bit foreground/background color mask and may be compressed/deflated will save me the storage. Using a streaming algorithm that just in time inflates two levels - first from compressed to full 1 bit mask and second from 1 to 18 bits by picking 18 bits background or 18 bit foreground depending the filter bit and sent them over a parallel interface, the display may give me the speed I could just dream of . To have performing inflations most likely require 'going underground' to (inline) assembler or using dedicated helper added to the firmware. This approach eliminates then the current drawing of a rectangle in background color before redrawing with current drawString()... ;) - Btw, with limited font options, all digits of a font should be same width, preferably two spaces and two dots (decimal points) wide, and also the -, +, and parenthesis should have this width. These measures provide the means to manageably display changing number values in fixed font and related (unchanging) labels in variable font. Time may come and make me build such a font.
-
@cephdon - you are absolutely right - when there is no time constraint using the practical unlimited space of the SD card is a way out. For the first of my three blocks of data this is a valid approach. For the second and third one, access and process performance are crucial. Therefore they have to live in the memory. If all options fail - space and time - I may resort to inline assembler creating the values from a very compressed, byte based/bit banged memory chunk, and pass them back to the JavaScript context.
-
I'm recalling having read them when I came across Espruino the very first time - even before having had a board in hand. I glanced over it when replacing my first [1v67] with [1v70] with enhanced memory management. I though did not pay as much attention until now, after encountered out of memory.
(Nur) die eigene Erfahrung hat den Vorzug voelliger Gewissheit.
(Only) the very own experience has the advantage of absolute doubtlessness.
Arthur Schopenhauer - 1788-1860
Humans have great difficulty to internalize and to be sure of what they hear or are told - and in turn to adjust their actions - once having experienced something though by themselves, they stick stubbornly with the cerntainty of that personal, individual and often only exemplary experience - and I'm no exception from that. Absolute doubtlessness - absolute certainty - gained by very own experience made in far or near past under then circumstances make oneself a prisoner of that past and blind to accept present and future options and no-options / constraints - not noticing that circumstances most likely have changed. Blind spot is another term for that.
With a fresh look at the implementation / internals / performance, I will elaborate on code variations empirically in the beginning, and over time more theoretically - in an a priori way - the more I (really) understand.
Usage of a very high-level language let's one quickly make things happen and equally quickly forget what is really going on under the hood. Back to the roots is as bloody-red as the red beets themselves... but it is fun.
Regarding temporary memory usage, I was thinking of using the require() and then the un-require() - of which I read about in some posts or tutorials, but can not recall top of my head the actual function call.... will come back and edit the post.
-
I'm not concerned about missing out on lines. I see more the challenge in getting partial / incomplete lines (GPS sentences) on (re-)start/resume. On the other hand, the very rigid tag extract and check would then just make the partial line to be skipped too. The next one though is pickup for sure, which - with (most) receiver's default configuration - shows up right within the next second (I have seen increasing the sentence (set) frequency on u-blox receivers, which of course requires also to increase serial's speed/baud rate in order to send the - also configurable set of - messages within the configured time period.
Thanks for backfilling the term 'root scope'. I like it also for enforcing 'privacy' / enhanced encapsulation... (as 'private' in Java). It is a neat, JS distinctive thing to be able to establish things in the function/method body definition that then can only be seen from within the 'definition-time-scope' and will 'stay for ever' - or at least as the function/method is not garbage collected . The same happens to all things defined in modules when not exported... because it happens all in require()'s scope... (that's why the current GPS module's handleGPSLine() function is not accessible / lacks/suffers from accessibility - lacking or benefiting from absent accessibility is though always dependent on the design intention).
In GPS module I have seen single method export... and in my embedded code, I did emulate the multiple exports because require() returned that kind of object (see line 56 in post http://forum.espruino.com/comments/11857912/ - part 4 of 5). From your code snipped I conclude that you can have a 'collection' of exports... - or, more precisely - an object (instance) with named properties - or plain js object - POJSO (like POJO as in Java). I hoped for and assumed something like that... and now I see how it is done.
Because in the Espruino and a-like realm most challenges come from connecting to things / devices - and module help with that a great deal: hide the nitty-gritty, always the same looking things and (can also) provide additional convenience (methods). I see though the module technique not limited to that only and can see many other application that would have something else than connect as the initial method to get going. I could also see start and stop as a different scope than connect/disconnect, because start, stop, pause, and resume have a different feel to me... almost as we distinguish also boot/cold-start/warm-boot/start,... similar like sleep, deep sleep, and hibernate... none of these are reset or boot. These various types of processes or sequences/sets of life-cycle steps exist all in their own rights....
Oooops: I have - again - to remind my dreamy mind that with Espruino I deal with (very) limited resources... and thus many of these processes have to collapse into dedicated, simplified ones - just as needed. It's almost going back 50 or 60+ years in computing, when computers were built for a distinctive task... Only later systems, such as, for example, IBM System /360 computer announced early 60' were declared as a general purpose machines - not just to do Operations Research (OR), or Accounting, or... you name it. The key logo / badge for this first IBM general purpose computer was a compass rose: you can go any direction with this thing (see http://www.computerhistory.org/revolution/mainframe-computers/7/161).
Today, with 'cheap' hardware available in masses, we can go back to the future and 'back' to dedication... and there is need for a big warehouse, a power plant, and cooling towers for operating such things. I bet that Espruino has multitude of processing power and with wifi connectivity unlimited storage compared to /360 systems with relative little memory - some models with much less and some with more then Espruino - and 7+MB disk storage... and /360s were called a Main Frames... ;-): Everything has it's season.
-
Thanks for your compliments. You did not miss anything... - Parallel driving: Was thinking about it. It for sure performs better. With serial: for complete drawing of time, 1 second is sufficient; drawing latitude and longitude takes a bit longer... What adds pain to the (re)drawing is the absence of a fixed size font (...may be I just have not discovered it yet). Your hint to use a parallel interface makes me rethink my assumption about 'who' runs the drawing: a) Espruino - or b) LCD controller... and I tend now towards assuming a) Espruino. --- Btw, I like to 'fix' hardware using software... - or more accurately - complement and be complemented by hardware. ;).
-
Thanks for sinking your already scarce time resource into this. I'm sure you would like to have satellite brains and body clones working for you and executing all the creative ideas going on in your master brain... ;) - something like this happens in my dreams. Back to - nevertheless - exciting reality:
covered the question of memory usage in the other post...
Gives me enough food for thought to take the next step in adjusting into the architecture and spirit of Espruino as a whole. I'm sure the two links in the addendum post will explain the term root scope. I will resume with the memory conversation when resuming with the related project, which is: http://forum.espruino.com/conversations/127039 - Exploring 2.8" Color TFT Touch LCD by PacMan Game attempt.
What I'm thinking about you suggested 'new' implementation of GPS module - well: I'm going back to school is for sure part of it... other parts are:
I began with list of thoughts below... until paying closer attention to '.start()' method... and got stuck in it.... which toppled almost everything but the first thought to the point of actually being wrong... and to being wrong about code 'annihilates' - or at least - questions most of my (professional) past... therefore: Disregard the list. I will come back, re-think/buke and re-write the list. For now I can say that I 'see' great progress. ;). To have an idea where this all is heading for, take a look at the running application of the GPS module at http://forum.espruino.com/conversations/255759 - DIY Marine GPS using enhanced GPS Module, u-blox NEO-6M GPS receiver, and ILI9341 Module controlled 2.8" Color TFT LCD.
- Comparison with my code / solution patterns highlights the suggested form of writing modules
- Having .start() and .stop() methods and their way of implementation great in many ways - and with it - the whole module passes object-orientation with flying colors. It now allows also to have multiple GPSs... ;) - which I was thinking about in the previous solution, but considered it a rare option... I'd rather have two complete systems connected to a network for 'high'-availability.
- The .stop() 'disconnects' the handlers completely vs. the approach I chose. I was thinking about something like that but had not studied Serial object enough yet. My solution comforted me by the fact that it keeps up with 'complete' lines in the background makes a resume flawless... which I guess is not the case with suggested .start()/.stop()............................ ooooops.................. see comment in italics above this list.
- Comparison with my code / solution patterns highlights the suggested form of writing modules
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:
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/4904059/.
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]