-
Ic... (OTG). I was less thinking about price, but more of change of connectivity/connectivity
and pin reuse at the same time: not to have the USB (board) plug and chip pins sitting idling there while not plugged in (as USB slave) and not being able to use the 'pins' (chip and board)... reusing space and pins in pico context means a lot. -
I ventured into the ILI9341 datasheet and - of course - some coding. First I did an analysis of the existing module... I hope I got the comments right.. I added also getPixel(), getRect()angle, setRect() - for saving and restoring on overlay, and a helper method to convert from 3 byte 6 bit <<2 pixel data from reading a pixel w/ getPixel() to writing using setPixel()*. Code - ready to be loaded into the editor, a shot and a clip are attached to the post.
The attached clip shows you the behavior:
- LCD initializes, a border 1px border is drawn, and Hello Espruino! is printed.
- Top left a green, 20x20 px rectangular is drawn (filled).
- A 20x20 px 'save' is taken from the area between Hellow and Espruino
- A red , 20x20 px rectangular is drawn, just overriding the saved area
- Task and time is printed (save: 495 [ms])
- Red rectangular overridden area is restored
Task and time is printed (restore: 1 [ms])
Attached is the inline file that can be loaded right into the editor. // ILI9341E_DOCD_inline.js /* Copyright (c) 2013 Juergen Marsch and Gordon Williams, Pur3 Ltd. See the file LICENSE for copying permission. */ /* Module Enhanced for the ILI9341 LCD controller Just: SPI1.setup({sck:B3, miso:B4, mosi:B5, baud: 1000000}); var g = require("ILI9341").connect(SPI1, B6, B8, B7, function() { g.clear(); g.drawString("Hello",0,0); g.setFontVector(20); g.setColor(0,0.5,1); g.drawString("Espruino",0,10); // --- "Enhacements" g.getPixel(x,y) -> [R,G,B] each 6 bits << 2 (white = 252,252,252) g.pxToInt([R,G,B] (from getPixel()) -> int color for setPixel(x,y,color) g.getRect(x1,y1,x2,y2); --> Uint16Array of [colors,...] g.setRect(x1,y1,x2,y2,rect); // rect from getRect() }); */ var LCD_WIDTH = 240; var LCD_HEIGHT = 320; var ILI9341 = {connect: function(spi, dc, ce, rst, callback) { // inline for next line // exports.connect = function(spi, dc, ce, rst, callback) { // about SPI (see http://www.espruino.com/Reference#SPI): // d is data1, p is data1 or pin, w/ data1 is int|string|array|{data:e, count:#} and // e is data2, w/ data2 is int|string|array // - spi.write(d,...,p); // sends LSBytes of all d, and if last arg is pin, pin held 0 // - spi.send(e,p); // sends LSBytes of e or all in e, if p present, pin p held 0 function writeCMD(c){ // --- write command (cmd) only ce.write(0); // chip enable spi.write(c,dc); // spi write cmd w/ dc data/cmd pin held cmd mode (0) } function writeCD(c,d){ // --- write command w/ data/parms ce.write(0); // chip enable spi.write(c,dc); // spi write cmd w/ dc data/cmd pin held cmd mode (0) spi.send(d); // spi send data/parms ce.write(1); // chip disable } var LCD = Graphics.createCallback(LCD_WIDTH, LCD_HEIGHT, 16, { // set pixel is like fill rectangle w/ [x1/y1=x,y inclusive and x2/y2=x+1,y+1) exclusive setPixel:function(x,y,c){ // x, y, c(olor)/image data for 1px ce.reset(); // chip enable spi.write(0x2A,dc); // cmd 0x2A - x/col addr - w/ dc for cmd (0) spi.write(x>>8,x,x>>8,x); // x [Start Point MSByte, LSByte, then End Point) spi.write(0x2B,dc); // cmd 0x2B - y/row/page addr - w/ dc for cmd (0) spi.write(y>>8,y,y>>8,y); // x [Start Point MSByte, LSByte, then End Point) spi.write(0x2C,dc); // cmd 0x2C - memory write - w/ dc for cmd (0) spi.write(c>>8,c); // 65K 2 bytes color (LSByte 1st, MSB 2nd) ce.set(); }, fillRect:function(x1,y1,x2,y2,c){ // x1,y1,y1,y2, c(olor)/image data for 1px ce.reset(); // chip enable spi.write(0x2A,dc); // cmd 0x2A - x/col addr - w/ dc for cmd (0) spi.write(x1>>8,x1,x2>>8,x2); // x [Start Point MSByte, LSByte, then End Point) spi.write(0x2B,dc); // cmd 0x2B - y/row/page addr - w/ dc for cmd (0) spi.write(y1>>8,y1,y2>>8,y2); // y [Start Point MSByte, LSByte, then End Point) spi.write(0x2C,dc); // md 0x2C - memory write - w/ dc for cmd (0) spi.write({data:String.fromCharCode(c>>8)+String.fromCharCode(c), count:(x2-x1+1)*(y2-y1+1)}); ce.set(); // chip disable } }); ce.write(1); // chip disable dc.write(1); // data mode rst.write(0); // reset setTimeout(function(){ // time reset pin low 1[ms] using timeout rst.write(1); // end reset setTimeout(function(){ // time after reset pin back to high 5[ms] writeCMD(0x01); // cmd 01 software Reset setTimeout(function(){ // time for software Reset 5[ms] writeCMD(0x28); // cmd 28 Display OFF ce.write(1); // chip disable writeCD(0xCF,[0x00,0x83,0x30]); // CF Power control B writeCD(0xED,[0x64,0x03,0x12,0x81]); // ED Power on sequence control writeCD(0xE8,[0x85,0x01,0x79]); // E8 Driver timing control A writeCD(0xCB,[0x39,0x2C,0x00,0x34,0x02]); // CB Power control B writeCD(0xF7,0x20); // F7 Pump ratio control writeCD(0xEA,[0x00,0x00]); // EA Driver timing control B writeCD(0xC0,0x26); // C0 Power Control 1 writeCD(0xC1,0x11); // C1 Power Control 2 writeCD(0xC5,[0x35,0x3E]); // C5 VCOM Control 1 writeCD(0xC7,0xBE); // C7 VCOM Control 2 writeCD(0x36,0x48); // 36 Memory Access Control: row col exch, BGR order writeCD(0x3A,0x55); // 3A COLMOD: Pixel Format Set 65K 16bit R(5) G(6) B(5) writeCD(0xB1,[0x00,0x1B]); // B1 Frame Rate Control (in Normal Mode/Full Colors) writeCD(0xF2,0x08); // F2 Enable 3G writeCD(0x26,0x01); // 26 Gamma Set // E0 Positive Gamma Correction // E1 Negative... writeCD(0xE0,[0x1F,0x1A,0x18,0x0A,0x0F,0x06,0x45,0x87,0x32,0x0A,0x07,0x02,0x07,0x05,0x00]); writeCD(0xE1,[0x00,0x25,0x27,0x05,0x10,0x09,0x3A,0x78,0x4D,0x05,0x18,0x0D,0x38,0x3A,0x1F]); writeCD(0xB7,0x07); // B7 Entry Mode Set writeCD(0xB6,[0x0A,0x82,0x27,0x00]); // B6 Display Function Control writeCMD(0x11); // 11 Sleep Out ce.write(1); // chip disable setTimeout(function(){ // time for Sleep Out 100[ms] writeCMD(0x29);ce.write(1); // 29 Display ON setTimeout(function(){ // time for DISPLAY ON 100[ms] if (callback!==undefined) callback(); // application callback },100); // 100[ms] for switching DISPLAY ON },100); // 100[ms] for Sleep Out },5); // 5[ms] for Software Reset },5); // 5[ms] time after reset pin back to high },1); LCD.getPixel = function(x,y) { ce.reset(); // chip enable spi.write(0x2A,dc); // cmd 0x2A - x/col addr - w/ dc for cmd (0) spi.write(x>>8,x,x>>8,x); // x [Start Point MSByte, LSByte, then End Point) spi.write(0x2B,dc); // cmd 0x2B - y/row/page addr - w/ dc for cmd (0) spi.write(y>>8,y,y>>8,y); // x [Start Point MSByte, LSByte, then End Point) spi.write(0x2E,dc); // cmd 0x2E - memory red - w/ dc for cmd (0) spi.write(0x00,0x00,0x00); var p = spi.send([0x00,0x00,0x00]); ce.set(); return p; }; LCD.pxToInt = function(p) { return ((p[0]>>3)<<3)+(p[1]>>5)*256+(p[1]<<3)%256+(p[2]>>3); }; LCD.getRect = function(x1,y1,x2,y2) { var m = 0, n = (x2-x1+1)*(y2-y1+1)*2, r = new Uint8Array(n); var xfr = function(p) { r[m++] = ((p[0]>>3)<<3)+(p[1]>>5); r[m++] = (p[1]<<3)%256+(p[2]>>3); }; ce.reset(); // chip enable spi.write(0x2A,dc); // cmd 0x2A - x/col addr - w/ dc for cmd (0) spi.write(x1>>8,x1,x2>>8,x2); // x [Start/Ent Pts MSByte, LSByte) spi.write(0x2B,dc); // cmd 0x2B - y/row/page addr - w/ dc for cmd (0) spi.write(y1>>8,y1,y2>>8,y2); // x [Start/End PTs MSByte, LSByte) spi.write(0x2E,dc); // cmd 0x2E - memory read - w/ dc for cmd (0) spi.write(0x00,0x00,0x00); // dmy reads while (m < n) { xfr(spi.send([0x00,0x00,0x00])); } // a px at a time incl conv to Uint16 ce.set(); return r; }; LCD.setRect = function(x1,y1,x2,y2,r) { ce.reset(); // chip enable spi.write(0x2A,dc); // cmd 0x2A - x/col addr - w/ dc for cmd (0) spi.write(x1>>8,x1,x2>>8,x2); // x [Start Point MSByte, LSByte, then End Point) spi.write(0x2B,dc); // cmd 0x2B - y/row/page addr - w/ dc for cmd (0) spi.write(y1>>8,y1,y2>>8,y2); // x [Start Point MSByte, LSByte, then End Point) spi.write(0x2C,dc); // cmd 0x2C - memory write - w/ dc for cmd (0) spi.write(r); ce.set(); }; return LCD; } // inline }; SPI1.setup({sck:B3, miso:B4, mosi:B5, baud: 1000000}); var lcd = ILI9341.connect(SPI1, B6, B8, B7, function() { // inline for next line // var lcd = require("ILI9341").connect(SPI1, B6, B8, B7, function() { B2.set(); lcd.clear(); lcd.setColor(0.0,1.0,1.0); lcd.drawRect(0,0,lcd.getWidth()-1,lcd.getHeight()-1); lcd.setColor(1.0,1.0,1.0); lcd.setFontVector(20); lcd.drawString("Hello Espruino!",35,5); lcd.setFontVector(15); var r,t; lcd.setColor(0.0,1.0,0.0); lcd.fillRect(1,1,20,20); t = getTime(); r = lcd.getRect( 85, 0,104, 19); // get/save rectangle for later restor console.log(t = getTime() - t,"[s] bytes:",r.length," memory",process.memory().usage); lcd.setColor(1.0,1.0,1.0); lcd.drawString("save 20x20 rectangle:",5,35); lcd.setColor(1.0,1.0,0.0); lcd.drawString(Math.round(t*1000) + " [ms] 1200-->800 bytes",5,55); setTimeout(function(){ lcd.setColor(1.0,0.0,0.0); lcd.fillRect( 85, 0,104, 19); // override saved rectangle area setTimeout(function(){ t = getTime(); lcd.setRect( 85, 0,104, 19,r); // restore rectangle area console.log(t = getTime() - t,"[s] bytes:",r.length," memory",process.memory().usage); lcd.setColor(1.0,1.0,1.0); lcd.drawString("restore 20x20 rectangle:",5,75); lcd.setColor(1.0,1.0,0.0); lcd.drawString(Math.round(t*1000) + " [ms] <--800 bytes",5,95); },1000); },1000); });
Most difficult part in getRect() and setRect() for save and restore (or copy) of an area was the different pixel format: it is read with 3 6bit bytes and a left shift of <<2 (White is 252,252,252). Writing back requires two Uint8 that cover 5 bits read, 6 bits green (straddling the bytes), and 5 bits blue. After a while I got the hang of it.
You can use the color values to set the color and then call setPixel with no color argument... but that's super strolly...
var px = lcd.getPixel(x,y); // --> array [R,G,B], 6 bit each with left shift of <<2 lcd.setColor(px[0]/252,px[1]/252,px[2]/252); lcd.setPixel(x,y);
The method .pixToInt(px) in line 126 helps to get this a bit easier (and is borrowed from getRect() method (line 133) - a slow version of ILICalc in assembler from @JumJum ;), figured that out in hindsight.
Initially I just read all the bytes in one swoosh by creating and sending a 0x00 initialized Uint8Array --- and wasted lots of memory... 4 or more bytes per pixel... and could read only 10x10 before running out of memory. Also, I kept the read format until restoring and did above mentioned conversion from 3 to 2 bytes when restoring: Another tie up of additional 50% memory. So I came up with the one px at a time (which works quite well - form me - but could be optimized by some bulking algorithm), and do the conversion right when reading.. Now, only the bare minimum on memory is used. This seems to work for my purposes. But I'm looking int adding some serial RAM (flash is an option too, but sucks in power... on the other hand it's on the board...) I was also thinking of using the controller's 'porches' outside of the visual area - if there is memory left; but I did not go into detail thoughts yet).
The approach of reading just a pixel and do the conversion turned out not much slower than reading and keeping all data memory efficiently, but the write is now a very quick one:
- time 566 [ms] is the read time for 20x20 area... 1200 Bytes packed into 800 to be keept until restore.
time of 14 [ms] is the restore / write time.
1v70 Copyright 2014 G.Williams >echo(0); =undefined 0.56678676605 [s] bytes: 800 memory 1315 0.01441287994 [s] bytes: 800 memory 1312 >
I hoped to get more out of it when making it a module and using minification: Speed was insignificant faster... 12% (last but not least removed the inline/infunction comments), but memory looks great:
1v70 Copyright 2014 G.Williams >echo(0); =undefined 0.49496555328 [s] bytes: 800 memory 678 0.01411247253 [s] bytes: 800 memory 682 >
I had also some difficulties with reading from the controller via SPI, because for each byte to read, a byte has to be sent (?) with SPI.send(). Unfortunately, SPI.send() is not supporting the object {data:data, count#} parameter as the write does... and the SPI.write - which supports it - does not return anything... So my suggestion is that the send() should support the object parameter option... the count would have made it really easy: repeatedly sending 0x00 (send is always a 0x00)
Small changes to the existing module are possible: when defining the rectangle (column and page address), the rectangle can have an extend of 0: no need to add 1. And as said, the spi.send could use the object parameter option... (and a native map.reduce function...).
@JumJum, I did not venture into assembler yet...
- LCD initializes, a border 1px border is drawn, and Hello Espruino! is printed.
-
Hot swap is a tricky thing... ensuring consistency after any edit is practically impossible, especially when going very optimized/minified. It is not impossible, but the limited amount of memory makes it even more difficult. Yes, the Laptop / Web IDE could be aware of all what is on the board... it it should not be memory strapped...
-
-
@Gordon, np, well understood... I'm excited about he Pico! Congrats: 2 days and 50%, trippled+ since I noticed yesterday! (of course, I'm 8 hrs time zone late...).
Issue will not get forgotten... I will have to go back to that particular code anyway. In the meantime I did some work on ILI9341 module...
-
@user7114, when iteratively developing a module as module or with its code 'inline' within a (limited) testbed, no minification can work. But for runtime, where the module should - hopefully - be a 'small' part compared to the application, additional JSVARS are a death sentence.
Developing with no minification in a (limited) testbed though has the advantage of not eating up the budget of the not really free google closure compiler service. At the same time, the testbed is best practice for unit/regression test and documented example.
-
@JumJum, parsed through your posts - which not necessarily expose ILI9341 relationship in title... nice 'Goldgrube'. The examples - and the provided extension - give me the opportunity to stand on giant's shoulders. Especially intriguing is the windowing aspect... last but not least to make sure a 'display' does not get messed up (...and did you have scrolling in mind?).
-
Yes, two different 'errors' - may be actually 3:
The if-issue - covering a double issue - is now clear (I guess): it is the combination of minification and Espruino's interpreter and the 'common' JavaScript syntax and Espruino's interpreter.
Latter could be fixed by adding curly braces, when then get removed by minification, because minification detects that there is only one statement in the block(s) and removes the curly braces, which get syntax and interpreter at odds again.
The second one is the try-catch thing... it is somehow not working the way I'm used to... I expected it would catch this error: for loop can only iterate over .... and object's properties -and not over undefined object C. (try { var C = undefined; for (var v in C).... } catch(x) {.... }).
I looked at the try catch test cases in github as examples... but somehow it does not work in this case. -
Module file is 5335 bytes, including comments - all what you see in post http://forum.espruino.com/comments/11899589/, lines 5..139 with a few more comment lines (frugal doc of methods...).
-
exactly what I expected, but the ILI9341 controller chip has the memory and the ability to return information from it.
When inspecting the return object from var lcd = require("ILI9341").connect() (just typing lcd in command pane), I see iSetPixel and iFillRect functions listed... and yes, I would have seen also something like iGetPixel (and/or what I would like even more: iGetRect). I though wonder where all the other methods are that I can use with lcd object... looked at the modules code, and see the Graphics.createCallback(...). So I inspect global Graphics (Singleton) object, and get single function with [native code] back... so I conclude that there is something hybrid/tricky in the interpreter which is invisible/uninspectable from the outside..., which then let's the lcd object (as the returned object from Graphics.createCallback()) understand all the Graphics methods... last but not least also the getWidth() and getHeight(), which return just the LCD_WIDTH and LCD_HEIGHT constants passed to Graphics.createCallback() method in the first place. I guess that the literally passed 16 in that very same method tells the chip to use 16 bit color input mode... (glancing over http://www.newhavendisplay.com/app_notes/ILI9341.pdf).
Regarding creating my own version (or an extension) is the way to go for reading whole blocks.
Regarding what I'm trying to do is save and restore the areas overridden by the (about) 20x20 px calibration marks after using them in the calibration module - one at the time, or some (simple) drop down menu.
For (re)calibration I need save-and-restore only when I have drawn the screen already. If I (re)calibrate before the app draws the screen, I do not need it. Also, I think, I may not need re-calibration after all, because the touch detection accuracy is sufficient for what I want to do in the application: +-15..20 px when using the finger tip, +-5..10px with stylo, or in terms of drawn button sizes: 30..40 px minimal and 10..20 px, respective.
For a simple drop down menu, I need of course to save and restore a larger area.
The idea of an memory rendered element is not flying, because the area to backup and restore is changing along the application and a redrawing becomes practically impossible... and if made possible, the extra memory (to keep states) and hold the code to support that would become a problem as well - and with that the speed would not be faster either, because drawing just a section - a display section unrelated to the application section - is impossible, and therefore, the whole display would have to be redrawn (think of a PacMan game board state after some time after the start of the game...).
No matter what, save and restore would have to stream to a processor-external storage - SD card or (serial) RAM chip (does not need persistence), (default) Espruino's (48K) memory is just too small after all...
'We' really need the option of a board with a chip with larger/largest memory... because I feel the cpu power of the chip and amount of memory are not balanced: memory is not at par with what amount of JavaScript application code can be crunched - a VM w/ garbage collection needs by definition just way more memory than a native straight forward programming with C-like language as Arduino and most of the other micro controllers (may be you have some good news there) - yes, price is an item... but any other additional chip to alleviate the issue adds cost AND hassle beyond what the larger chip costs, especially when you want to do some serious projects with it, an not just educational pet/bricollage/t(h)inkering projects (no insult here). Look at the bare BASIC Stamp... and its price... I would rather make learners use JavaScript than BASIC (or C) - Web technologies are omnipresent, after all (would like to say: 'before' all). Btw, what is the lot size you (have to) order from a manufacturer? I know that 'socketing' pulls it right away 'out of the socks' price-wise - if even possible, and hand-soldering for an average dude like me is not really an option... (the times where I needed only my bare eyes to actually see and do things the size the processor legs are have passed a while ago...). I messed around with various Arduino's, but when I came across Espruino, the 5-times price was not a question at all, because of JavaScript and the processing power (and of course, what you made out of the idea of combining a powerful micro controller and JavaScript... you see the 'softy' in me...). Also: Espruino - not any Arduino - got me really going again with my micro controller t(h)inkering projects after my initial playing around with ubicom.com / Parallax 's SX a while ago.
@JumJum, thank you for the code snippet. It will get me going... ;-) ...btw, what is setRect() function looing like and doing?
-
I tried to use the .getPixel(x,y) to save areas of the display to later restore...
Reading from any location I always get 0 - even for locations I just set, and can actually see the just set pixel.
I know that the boards are connected properly (Espruino outputs and inputs to breakout board inputs and outputs). I also know that the boards communicate properly because can write and read from the board (for example, .setColor() and .getColor() work). I use the breakout board from http://www.adafruit.com/products/1770
Why do I get just 0 back with .getPixel()?
PS: 'looked around' and found some low level reading... about Highly optimized ILI9341 (320x240 TFT color display) at http://forum.pjrc.com/threads/26305 I'm sure this would all hide behind the Graphics.readPixel(x,y) JavaScript implementation. Since a single pixel is usually not of real use, the read of a rectangle and related (re-)write into and from, for example, a uInt16 like buffer (streaming in to and out of an SD card for larger areas), is the desired function. To make it w/ 16 bits, two colors have to be expanded/collapsed by a bit to make that happen, and from what I can read from the controller's datasheet, it may even be supported by the controller...). I'm not ready yet to take on such hardware close calls... but it could happen sooner with some help from any Mr or Mrs Geek G. Shoehorn.... ;-)
-
Really weird things happen when throwing minification and Espruino together - see http://forum.espruino.com/conversations/256957/ - where all of a sudden the if does not work anymore... nor the try-catch... and only the addition of some application-useless but minification-tricking (noise) code get's the things back to work again.
-
The if (C) {...}-thing still gives me annoying grieve,... I thought the added curly braces would have solved the issue for good...
1v70 Copyright 2014 G.Williams >echo(0); Uncaught Error: FOR loop can only iterate over Arrays, Strings or Objects, not undefined at line 1 col 288 ...or(var v in C)this.C[v]=C[v]} ^
Related to this code (line 10 in constructor), coming from the (again) working space-only-minified sandbox modules folder. (Had to re-enable some minification option after getting unexplicable out of memory error - see http://forum.espruino.com/comments/11900960/).
// ACD pins for X-, X+, Y-, Y+, optional - but one - callbacks, optional C(onfig) function TOUCHR(xn,xp,yn,yp,onDownCB,onTrackCB,onUpCB,onEscCB,C) { this.xn = xn; this.xp = xp; this.yn = yn; this.yp = yp; this.cbs = [[onDownCB,onTrackCB,onUpCB,onEscCB]]; this.w = null; this.te = 0; this.upCnt = 0; this.up = true; this.xr = this.xrr = this.yr = this.yrr = -1; this.x = this.x0 = this.x1 = -1; this.y = this.y0 = this.y1 = -1; this.t = this.t0 = this.t1 = 0; if (C) { for (var v in C) { this.C[v] = C[v]; } } }
The constructor is invoked with undefined for C.
The minification messes with the code to the point where the execution and block nesting becomes broken... Why would I say so: Adding/removing some code further down in the module made the error flip-flop...
Interestingly, when I put a console.log() in the if-(then) block, it 'tricks' the minification and - miraculously (for me) - works:
if (C) { console.log("C:",C); for (var v in C) { this.C[v] = C[v]; } }
@Gordon, since you know your code like your own pockets, I'm sure you have a nice explanation - and may be - even a remedy top of your head... ;-)
The stuff seems to be related to what @DaveNI experienced in Minified Code Producing Error - Solved at http://forum.espruino.com/conversations/257029/
-
Clarification: just the Web IDE setting got cleared! Gladly! Otherwise: @#Y@%QWEG%Y... I'm not there yet, but could eventually close in on it... ;-) ...your
Man, I just can't...
related to ...433mhz... is still ringing in my ears... (at http://forum.espruino.com/comments/11897222/)
-
Having re-entered the Sandbox directory in Communication (to what it was before), the module is found, but now I get another 'nasty' comment / surprise:
>echo(0); ERROR: Out of Memory! WARNING: Unable to create string as not enough memory WARNING: Out of memory while appending to array Execution Interrupted. at line 2 col 60 ...(g-a+1)*(f-d+1)});c.set()}});c.write(1);e.write(1);h.write(0... >
I just wonder why... because it is the very same (in total) amount of 'unmodularized' code when sending from edit pane (...with no module but module code imbedded). It is the code shown in post at http://forum.espruino.com/comments/11899589/, except the first part as module in the /sandbox/modules directory - which worked before (with Module Minification set to Web IDE's default).
I assume the out of memory occurs because the module is not streamed but read as a whole and then sent... could that be? - I tested successfully the module (core code) embedded, so it cannot be some syntax issue.
-
although changing the minifier setting should work too
I did that... and may have had this side effect:
In Project, I selected No Minification for Module Minification (for Minification it was already set to No Minification), and it did reset / clear the Sandbox directory setting in Communication of the WEB IDE... (added clarification that the Files were not cleared, just the setting in Web IDE).
Is that possible?
Sending code to the board with a reset / cleard / empty Sandbox directory and modules to be expected to found in /sandbox/modules (too), the console shows:
>echo(0); ERROR: Unable to mount SD card : NOT_READY WARNING: Module "XYZMODULE" not found Uncaught Error: Field or method does not already exist, and can't create it on undefined at line 1 col 30 var v = require("XYZMODULE").connect(.....
-
You can, just make sure the you respect the 3.3V inputs. To be on a save side with measuring floating lines, you need to have Espruino's power supply galvanically separated - DC-DC isolated power converter, for example, something like http://www.ebay.com/itm/140702578979?_trksid=p2055119.m1438.l2649&ssPageName=STRK%3AMEBIDX%3AIT and data transmission wireless.
The connected charge controller may though interfere with your measurements - assuming you have one in place.
Something what you can for sure measure is what's going on at your battery... but even there, if the charge controller is on / charging, you do not get the actual voltage/charge condition. Since (cheap) charge controllers can not be influence from the outside, it will be a nice challenge. More expensive charge controllers have interfaces and they provide access to the measurements which they actually do for themselves to run proper charging cycles.
-
Here the first cut of LCD and TOUCHR(esistive) screen combined with calibration module connected.
// touchrCalib.js [0v03] [1v70] 20141022 (c) muet.com // temp beg ---------------- // TOUCHR.js [0v04] [1v70] 20141022 (c) muet.com // suggested pins for connect: C0(xn=X-),C1(xp=X+),C2(yn=Y-),C3(yp=Y+) // CallBacks and Config optional on connect function TOUCHR(xn,xp,yn,yp,onDownCB,onTrackCB,onUpCB,onEscCB,C) { this.xn = xn; this.xp = xp; this.yn = yn; this.yp = yp; this.cbs = [[onDownCB,onTrackCB,onUpCB,onEscCB]]; this.te = 0; this.upCnt = 0; this.up = true; this.xr = this.xrr = this.yr = this.yrr = -1; this.x = this.x0 = this.x1 = -1; this.y = this.y0 = this.y1 = -1; this.t = this.t0 = this.t1 = 0; if (C) { for (var v in C) { console.log("v: ",C[v]); this.C[v] = C[v]; } } } var pt = TOUCHR.prototype; // tracking Interval in [ms], upThresholds, required up counts // escape time [ms], LCD and screen config parms pt.C = { trkIv: 100 , upThX: 0.08 , upThY: 0.05 , upCnt: 2 , escTme: 10000, sameThd: 12 , xmx:239, xo: 0.11210664669 ,xd: 0.00318978292 , ymx:319, yo: 0.07025931859 ,yd: 0.00251604316 }; 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.xyr(_this._onDown); }, this.xp, {edge:rising, repeat:false} ); }; pt._onDown = function() { this._xyc(this.C,true); this.x0 = this.x1 = this.x; this.y0 = this.y1 = this.y; this.te = 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() { var q = this.cbs.length - 1, C = this.C; if ((this.xrr > C.upThX) || (this.yrr > C.upThdY)) { this._xyc(C,true); this.x1 = this.x; this.y1 = this.y; this.t1 = this.t; this.upCnt = 0; if (this.t1 - this.te > this.C.escTme) { if ( (Math.abs(this.x0 - this.x1) < C.sameThd) && (Math.abs(this.y0 - this.y1) < C.sameThd) && this.cbs[q][3] && (this.cbs[q][3](this)) ) { return; } else { this.te = this.t; } } if (this.cbs[q][1]) { this.cbs[q][1](this, this.x, this.y, this.t); } this.track(); } else { if (this.upCnt++ < 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.onTrack = function(onTrackCB,onUpCB) { var q = this.cbs.length - 1; this.cbs[q][1] = onTrackCB; this.cbs[q][2] = onUpCB; }; pt.onEsc = function(onEscCB) { var q = this.cbs.length - 1; this.cbs[q][3] = onEscCB; }; pt.track = function() { var _this = this; setTimeout(function(){ _this.xyr(_this._onTrack); },this.C.trkIv); }; pt._xyc = function(C,c) { if (c) { var x = Math.round(((this.xr = this.xrr) - C.xo) / C.xd); var y = Math.round(((this.yr = this.yrr) - C.yo) / C.yd); this.x = (x < 0) ? 0 : (x <= C.xmx) ? x : C.xmx; this.y = (y < 0) ? 0 : (y <= C.ymx) ? y : C.ymx; } else { this.x = undefined; this.y = undefined; } }; pt.xy = function(callback) { this.xyr(); this._xyc(this.C,(this.xrr > C.upThX) || (this.yrr > C.upThdY)); if (callback) { callback.call(this); } }; pt.xyr = function(callback) { this.t = new Date().getTime(); pinMode(this.yn,"input_pulldown"); digitalRead(this.yp); digitalWrite([this.xn,this.xp],2); this.xrr = (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.yrr = (analogRead(this.xn)+analogRead(this.xn)+analogRead(this.xn))/3; digitalRead([this.yn,this.yp]); if (callback) { callback.call(this); } }; // exports.connect = function(xn,xp,yn,yp,onDown,onTrack,onUp,onEsc,C) { var touchrModule = { connect: function(xn,xp,yn,yp,onDown,onTrack,onUp,onEsc,C) { var touch = new TOUCHR(xn,xp,yn,yp,onDown,onTrack,onUp,onEsc,C); touch.listen(); return touch; } }; // temp end ---------------- // function xy(xr,yr,C) { // var x = Math.round((xr - C.xo) / C.xd), y = Math.round((yr - C.yo) / C.yd); // x = (x < 0) ? 0 : (x < C.xmx) ? x : C.xmx; y = (y < 0) ? 0 : (y < C.ymx) ? y : C.ymx; // console.log("----->",x,"-",y); // } var cnt = -1, cnt2; // var touch = require("TOUCHR").connect(C0,C1,C2,C3, // suggested default ADC pins var touch = touchrModule.connect(C0,C1,C2,C3, // suggested default ADC pins function(touch,x,y,t){ // --- onDown callback function cnt2 = 0; console.log(++cnt,cnt2,"onDown-r:",touch.xr,"-",touch.yr,"@",t); console.log(++cnt,cnt2,"onDown: ",x,"-",y,"@",t); touch.onTrack( function(touch,x,y,t){ // --- onTrack callback function cnt2++; console.log(cnt,cnt2,"onTrack: ",x,"-",y,"@",t); },function(touch,x,y,t){ // --- onUp callback function cnt2++; // 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(cnt,cnt2,"up-r: ",touch.xr, "-",touch.yr ); console.log(cnt,cnt2,"up--rr: ",touch.xrr,"-",touch.yrr); console.log("...in ",touch.t1 - touch.t0,"[ms]"); }); // touch.onEsc( // function() { // --- empty 'not-available' onEscape callback function // cnt2++; // console.log(cnt,cnt2,"onEscape - but 'not-available', hence returning false"); // return false; // }); }); function TOUCHRCALIB(touch,lcd,noteCB,exitCB) { this.touch = touch; this.lcd = lcd; this.noteCB = noteCB; this.exitCB = exitCB; this.step = -1; this.rdy = false; this.ps = null; this.vs = null; this.exitTmr = null; var _this = this; touch.onEsc(function(){ return _this.enter(); }); } var pt = TOUCHRCALIB.prototype; pt.C = { exitTme: 30000 , noteTme: 2000 , markDly: 500 , markSze: 20 }; pt.enter = function() { if (this.step == -1) { var tme = this._note(true); console.log("tme =",tme," - exit =",tme + this.C.exitTme); var _this = this; this.vs = []; this.exitTmr = setTimeout(function(){ _this._exit(); },tme + this.C.exitTme); setTimeout(function(){ _this.step = 0; _this.rdy = true; _this.touch.track(); },tme); this.touch.cbs.push([null,null,function(touch,x,y,t){ _this._next(x,y,t); },null]); return true; } else { return false; } }; pt._next = function(x,y,t) { var s = this.step; if (this.rdy) { this.rdy = false; if (s > 0) { this.vs.push(this.touch.xr); this.vs.push(this.touch.yr); this._unmark(this.lcd,this.ps[s*2-2],this.ps[s*2-1],this.C.markSze); } if (s < 5) { this.step++; this._mark(s); this.rdy = true; } else { clearTimeout(this.exitTmr); this.step = 6; this._calib(); this._exit(); } } }; pt._exit = function() { console.log("calib _exit():"); var tme = this._note(false); this.ps = null; this.vs = null; var _this = this; setTimeout(function(){ _this.touch.cbs.pop(); _this.step = -1; _this.rdy = false; if (_this.exitCB) { _this.exitCB(); } },tme); }; pt._mark = function(s) { var m = this.C.markSze, m2 = Math.floor(m / 2 - 0.5) + 1; if (s === 0) { var x = this.lcd.getWidth(), y = this.lcd.getHeight(); this.touch.C.xmx = x - 1; this.touch.C.ymx = y - 1; this.ps = [0,0, x-m-1,0, x-m-1,y-m-1, 0,y-m-1, x/2-m2-1, y/2-m2-1]; console.log("ps:",this.ps); } this._mark0(this.lcd,this.ps[s*2],this.ps[s*2+1],m,m2); }; pt._mark0 = function(l,x,y,m,m2) { l.setColor(1.0,1.0,1.0); l.fillRect(x,y,x+m,y+m); l.setColor(0.0,0.0,0.0); l.drawRect(x+1,y+1,x+m-1,y+m-1); l.drawLine(x,y,x+m,y+m); l.drawLine(x+m,y,x,y+m); l.fillRect(x+m2-2,y+m2-2,x+m2+2,y+m2+2); }; pt._unmark = function(l,x,y,m) { l.setColor(0.0,0.0,0.0); l.fillRect(x,y,x+m,y+m); }; pt._calib = function() { var m = this.C.markSze, m2 = Math.floor(m / 2 - 0.5) + 1; var vs = this.vs; var xl = (vs[0] + vs[6]) / 2, xu = (vs[2] + vs[4]) / 2; var yl = (vs[1] + vs[3]) / 2, yu = (vs[5] + vs[7]) / 2; var xd = (xu - xl) / (this.lcd.getWidth() - m); var yd = (yu - yl) / (this.lcd.getHeight() - m); xl = xl - xd * m2; xu = xu + xd * m2; yl = yl - yd * m2; yu = yu + yd * m2; var xc = (xl + xu) / 2, yc = (yl + yu) / 2; var C = this.touch.C; if (console && console.log) { console.log("calib _calib():"); var i = -1; while (i < 4) { i++; console.log("i:",i," ",vs[i*2],"-",vs[i*2+1]); } console.log("xd:",xd," yd:",yd," - ds:",xd - C.xd," ",yd - C.yd); console.log("x-:",xl," x+:",xu," - d: ",xl - C.xo); console.log("y-:",yl," y+:",yu," - d: ",yl - C.yo); console.log("xc:",xc," yc:",yc); } C.xmx = this.lcd.getWidth() - 1; C.xo = xl; C.xd = xd; C.ymx = this.lcd.getHeight() - 1; C.yo = yl; C.yd = yd; }; pt._note = function(evt) { console.log("calib _note(): evt =",((evt) ? "beg" : "end")); var tme = (this.noteCB) ? this.noteCB(evt) : this.C.noteTme; return (!isNaN(tme) && (tme >= this.C.noteTme)) ? tme : this.C.noteTme; }; var touchrcalibModule = { connect:function(touch,lcd,noteCB,exitCB){ var calib = new TOUCHRCALIB(touch,lcd,noteCB,exitCB); return calib; } }; B2.set(); SPI1.setup({sck:B3, miso:B4, mosi:B5, baud: 1000000}); var lcd = require("ILI9341"); lcd = lcd.connect(SPI1, B6, B8, B7, function() { lcd.clear(); lcd.setFontVector(20); lcd.drawString("Hello Espruino!",35,0); lcd.setColor(0.0,1.0,1.0); lcd.drawRect(0,0,lcd.getWidth()-1,lcd.getHeight()-1); touchrcalibModule.connect(touch,lcd,function(beg){ console.log("noteCB w/ noteTme = 2500"); var noteTme = 2500; B2.reset(); setTimeout("B2.set()",noteTme); return noteTme; }); });
The code is still pretty fat and needs to go for some diet. On the other hand it shows that not for no reason touch controller chips are available to offload an application controller from that tedious work... Some fat is intended to be burned - saved - when going for a simple UI w/ buttons and sliders.
Below some output, including the re-calibration.
>echo(0); =undefined 0 0 onDown-r: 0.16691335418 - 0.09798326593 @ 5888100.53244274854 1 0 onDown: 17 - 11 @ 5888100.53244274854 1 1 onUp: 17 - 11 X 17 - 11 1 1 up-r: 0.16691335418 - 0.09798326593 1 1 up--rr: 0.04085348795 - 0 ...in 0 [ms] 2 0 onDown-r: 0.82789349202 - 0.12483914447 @ 5890403.95133587811 ..... 5 0 onDown: 17 - 305 @ 5896185.48854961805 ..... 6 0 onDown: 227 - 307 @ 5897569.74809160269 6 1 onTrack: 228 - 308 @ 5897683.27194656524 6 2 onTrack: 229 - 307 @ 5897792.12309160269 6 3 onUp: 227 - 307 X 229 - 307 ...in 222.375 [ms] 7 0 onDown: 115 - 159 @ 5899129.74427480902 7 1 onTrack: 116 - 160 @ 5899243.35782442707 7 2 onUp: 115 - 159 X 116 - 160 8 0 onDown: 116 - 275 @ 5909195.74141221400 8 1 onTrack: 116 - 275 @ 5909309.24713740497 8 2 onTrack: 116 - 273 @ 5909418.09828244242 8 3 onTrack: 116 - 273 @ 5909526.95801526680 ..... ..... ..... 8 89 onTrack: 114 - 272 @ 5918888.63454198464 8 90 onTrack: 115 - 271 @ 5918997.46374045778 8 91 onTrack: 114 - 271 @ 5919106.32442748080 calib _note(): evt = beg ..... calib _calib(): i: 0 0.14144096030 - 0.09773912158 i: 1 0.84278629739 - 0.09871569899 i: 2 0.85735357696 - 0.85027339080 i: 3 0.15844968337 - 0.86101574222 i: 4 0.48812593779 - 0.48470791688 xd: 0.00318238461 yd: 0.00252472385 - ds: -0.00000739830 0.00000868069 x-: 0.11812147568 x+: 0.88189378333 - d: 0.00601482899 y-: 0.07298017174 y+: 0.88089180505 - d: 0.00272085315 xc: 0.50000762951 yc: 0.47693598840 calib _exit(): ..... 9 0 onDown: 20 - 11 @ 5947261.60019083973 9 1 onUp: 20 - 11 X 20 - 11 ...in 0 [ms] .....
As you may notice, most touches / taps with a resistive and thus spongy feel are longer than the set track interval of 100 [ms] - 10 cycles or reads/second when while touching... and two for safely detecting - and 'debouncing' an 'untouch'. Therefore you see onTrack: output lines - such as 14, 15, and 19, even though I intended only a (short) touch / tap.
With output line 8 a very long tap starts... After the defined esc(ape)Time of 10 [sec] the connected recalibrate callback will kick in - at line 31 - after 91 track (way) points (of 100 theoretical possible ones). This is a great testimony Espruino's amazing performance.
Lines 34..42 show calibration values. First - lines 34..38 - show the read raw ADC values of top-left, top-right, bottom-right, and bottom-left corners (@ 10 px from the border) and center. (In the attached shot I commented the removal of the markers to tap to show all locations at once. The marker size is 20x20 px).
Surprising to me was the quite accurate reproducibility of the values between calibration. The last two numbers in line 39 show the ADC value difference for 1 px in x and y axis, and the last number on line 40 and 41 show the offset difference. Touch detection accuracy is a fraction of the display accuracy of +-1 pixel. The shape of the touching object and the pressure add quite some variation - especially a finger tip - which is reflected in unexpected high value of 12 px for sameThd (...Threshold) to detect still same touch location. For a pointy pen 3 px worked (line 29 in the code).
With the experience made, I do not (anymore) believe that calibration has to be available at runtme. It is good enough to verify with a particular new Touch LCD device - and if the device is within the tolerance, no value adjustments are needed. If there are - because of different types - then the connect (and constructor) allows to pass a C(onfig) object with the parameters that need to be different from what the module code has coded.
More about the code and some application samples in a different post.
Attached touchrCalib.js file (with touch and calibration 'module').
-
I'm only aware of minifiers/shrinkwrappers written in Java or C/C++. There are reasons for it. (But: ...could a signed Java Applet solve the issue? ...of course a bit an overkill for the term 'Applet') .
In order to continue I pulled the module into the code. Since at development time for components the time (and space) is not as much on the line as at runtime, it worked for me. Having still modules - just not minified - is though already a leap towards a final solution with minification. Adding the cache for now is a very good tactical solution. I assume, the cache stays alive for the duration of a Web IDE session. Btw, for file name and path retention I was thinking about HTML5 storage. And for the cache beyond session I was thinking about a second, parallel modules directory - such as modulesm - that could store the minified version. Because of security I'm sure it would require a pop-up for the save-confirmation from the user, does it? - no pressure what so ever... ;-)
-
-
Duplicate of: New-Bee error message: Too many compiles - try back later ? see http://forum.espruino.com/conversations/254197
Doing incremental development using the Web IDE, all of a sudden I get this in the console:
1v70 Copyright 2014 G.Williams >echo(0); Uncaught Error: Field or method does not already exist, and can't create it on undefined at line 1 col 36 oo many compiles performed recently. Try again l ^ Uncaught Error: Function "connect" not found!
...and nothing goe anymore. A bit very frustrated - because it is on an unchanged module in the local sandbox - I leave the stuff alone.
Googling 'oo many compiles...' leads me to this Google Closure Compiler Service API Reference page: https://developers.google.com/closure/compiler/docs/api-ref
Under the Errors I find:
- 22
- Too many compiles performed recently. Try again later.
- You have submitted too many compiles from your machine. After an hour, you should be able to perform compiles again.
On the Getting Started with the API at https://developers.google.com/closure/compiler/docs/gettingstarted_api
puts me in the category of an abuser...It was several hours later when I came back and tried again to no avail - and while stuck - ventured into googling and creating this conversation.
@Gordon, am I wasting my time here?
Is this what I'm thinking it is: Web IDE (with local Sandbox modules) is using a 'free' but limited free Google service?
So my primary question here is: What is the way around this limitation?
And a quite corollary question is: Did I miss that in the documentation of the Web IDE?
- 22
-
-
In handling of optional parameter in constructor I got a bit lost... and still am... ?-(
This is the original code, and I do not know what is wrong with it...
// goal: pass an optional C(onfig) object to update the C(onfig) in prototype function Clazz(C) { if (C) for (var v in C) this.C[v] = C[v]; } Clazz.prototype.C = { c: 100 }; var aClazz = new Clazz(); console.log("aClazz.C.C =",aClazz.C.C);
Running this code I get following console output:
1v70 Copyright 2014 G.Williams >echo(0); aClazz.C.C = 100 =undefined Uncaught Error: FOR loop can only iterate over Arrays, Strings or Objects, not undefined at line 2 col 43 if (C) for (var v in C) this.C[v] = C[v]; ^ >
I had expected that by design the if would have taken care of an undefined parameter variable C and skip the for-loop. The for-loop should only execute when is C defined.
Invoking constructor with empty object works:
var aClazz = new Clazz({});
logs:
1v70 Copyright 2014 G.Williams >echo(0); aClazz.C.C = 100 =undefined >
Invoking constructor with changing object works:
var aClazz = new Clazz({ C:50 });
logs:
1v70 Copyright 2014 G.Williams >echo(0); aClazz.C.C = 50 =undefined >
Next step I tried was for loop with curly braces - to no avail:
if (C) for (var v in C) { this.C[v] = C[v]; }
Next step I tried if with curly braces - but not the for loop - and it worked... (update: ...hold your horses, this was not the last snag... keep on reading!)
if (C) { for (var v in C) this.C[v] = C[v]; }
Sure, I always recommend to use curly braces. Before I though added them, I tried the avenue of try-catch to find out what is going on. It seemed to me odd that the reporting of the error was actually after execution of all the code and the error did not stop the code from executing... (as it would have done in a browser).
function Clazz(C) { if (C) for (var v in C) this.C[v] = C[v]; } Clazz.prototype.C = { C: 100 }; try { var aClazz = new Clazz(); console.log("Clazz() constructor passed"); } catch(x) { console.log("exception in Clazz() constructor:",x); } console.log("aClazz.C.C =",aClazz.C.C);
logs:
1v70 Copyright 2014 G.Williams >echo(0); Clazz() constructor passed aClazz.C.C = 100 =undefined Uncaught Error: FOR loop can only iterate over Arrays, Strings or Objects, not undefined at line 2 col 45 if (C) for (var v in C) this.C[v] = C[v]; ^ >
Surprisingly, the try-catch does not catch the error... it lets the faulty expression to pass... so I wrapped the actually expression in the constructor into a try-catch block...
function Clazz(C) { // -------------------------- try { if (C) for (var v in C) this.C[v] = C[v]; console.log("Clazz() constructor passed"); } catch(x) { console.log("exception in Clazz() constructor:",x); } } Clazz.prototype.C = { C: 100 }; var aClazz = new Clazz(); console.log("aClazz.C.C =",aClazz.C.C);
with the same puzzling result...
So I'm asking:
- What is going on here?
- Why is the if not catching when not provided with curly braces?
- Why it the try-catch not catching the error
- Why is the error reported at the end of all reporting... (console output)
I had tried to use try-catch block in a different project,... and it did not work there either. Because int that project it was precaution and the anticipated possible error did not show (yet), so I ignored 'to go to the bottom of it'.
- What is going on here?
-
...ouch, Web IDE (v0.47.2) file path/name handling on load and save still somehow messed up... could not yet find the pattern to recreate what I noticed: sometimes the suggested directory on save and load are the same and sometimes they are different. I have also no pattern to explain which code is shown when opening IDE - I know it is for sure NOT always the last one loaded or saved, and the suggested directory for save and load are different from where the shown code comes from... and as said, sometimes different for save and load (not the same when loading from a different dir but not saving and then close and reopen IDE...)...
It would be 'cool' if:
a) there is just one directory default kept... the same for load and save, set on performed load and save
b) not only the directory is kept, but the file names as well...
c) a) and b) would allow to load and show the last loaded/saved code if unchanged. If changed, keep last loaded/saved directory and blank the file name if default (code.js) filename already exists, otherwise blank to avoid saving with a predefined name.
d) if save/load was not the last action - in other words changes were done after load or save - changed code is shown (with directory of last save/load kept), but file name blanked... (the IDE somehow keeps code... independent of last activities, directory, and file name. Why can it not keep last edited and not saved content.I do not know whether the IDE / editor knows that the content is changed, and if not, how difficult it is to have it detected...
Experience the very same issue with reading values from resistive touch screen. The internal pull-up/down resistors are about 30..40K which may need to be considered when measuring - because they can pose 'significant load' on the measured 'object' - depending on circuitry. In my case, I could not detect the 'OFF' state reliably... continuous reading/sampling without pull-up/down even triggered subsequent setWatch() on the open pin - something did not expect. The solution is to pull down - and if the the 30..40K are a significant factor - switch to open input before reading (see http://forum.espruino.com/comments/11892295/). It is anyway a good thing to have the input as much open as possible to not waste any power. On the other hand to avoid floating, you may consider to pull down externally with a resistor of much higher value - 470K...1M and keep it... (value all depends on your circuitry). In my case it did not really matter 30..40K vs 300..400 Ohms, and left it pulled down.