-
@allObjects, this reminds me of Objective-C and Next Computer's graphical IDE. That was a time when this sort of methodology for application development was all the rage ('90s). I seem to recall some SmallTalk IDEs that also tried to get actual code-writing completely out of the picture.
What failed, and still does, is that none of these schemes simplify away the underlying engineering complexity of any real application, in which case the "difficulty" simply shifts from coding to interface definitions and protocols. Having been down this path, one soon finds that any "real world" application of any meaningful functionality and complexity ends up being just as much work -- or more -- to architect, specify, and implement interface and protocol specs, finding that in many cases it's "just easier" to fall back to actual code (C, C++, O-C, Java, whatever) and bang out something concise and efficient.
It's why these methods faded from the scene.
IMO, the real revolution for software engineering will come with AI, not IDEs and various alternative ways to spec program algorithms, which is really what this sort of thing is. Rather, when we have AI that we can simply describe a problem to, perhaps in some formal syntax, better if we can just talk to it, and it spits out the program.
That would free the designer to focus on features, function, behavior, etc.
The other domain that I think is woefully under-invested-in from the standpoint of software development is failure/defect detection and debugging. So little brainpower, relatively speaking, has been spent on improving and enriching this aspect of code development.
-
Those of us old enough to have been around for the development/introduction of java, plug-ins, etc., have seen this dance before. The Chrome Web App dealio was nice, but nothing innovative. It's all been tried before.
And it seems to always end the same way. The reasons are obvious: As long as there are different platforms (which will always be), there will be cross-platform work necessary to support applications across them. This reduces the issue to simply, WHO is going to do that on-going engineering? The app developer or the platform provider?
As another entrant in this space, we have Flash as well. And others. It's an intractable problem.
-
Old thread, pointed here by @allObjects due to some work I'm doing with this same stepper.
Some quick summary precautions to add that are covered here, but buried in all the dialog:
- The 28BYJ-48 can not handle steps faster than about 2ms apart.
- Sufficient power is critical. Running the motor driver (usually a ULN2003 chip) directly from the MCU board is very dicey, and will have lots of problems. You should use a separate 5V power supply for the driver board.
- The 28BYJ-48 can not handle steps faster than about 2ms apart.
-
@allObjects yeah, "duds" are always a risk when ordering cheap from China via ebay. And they've gotcha if one or more is bad, 'cause there's no point in trying to return or get a refund on such small amounts (a dollar or two) from those sources.
That's the trade-off... a risk premium. I've been very luck so far, and everything's been solid that's I've ordered from SLC (Slave Labor China). Some of the fabric my wife has ordered came with Opium residue on it though. Are they ever going to unchain the children from those looms? :-) :-) :-)
-
Yeah, it does "ramp-up" -- that's part of what I'm investigating. The stuttering happens when it isn't given enough time to accelerate to rotational speed before the fastest intervals between step changes. That's what the check in .move() for the first 10 steps is all about. I'm working on that algorithm to get it to be rock-solid and not stutter. Oh, and the stuttering from setting a new "request" while currently working on a current move -- definite bug, but easy to fix!
As far as being generic, yeah, it almost is. I already decided to make the small changes necessary to make it totally general, then populate it with defaults for the 28BYJ48 so it's ready to go "out of the box" for that stepper, since they're so common. The only specific parameter really is the steps/rotation.
@Gordon good ideas for some additional functionality too! The stop() definitely... Some of the other more complex functionality (like with feedback from sensors like a limit switch) I had in mind for application coding, hence the inclusion of the step() method in the prototype rather than as a private function in the module... the step() method keeps track of position, so functionality can be easily extended with step() and zero() (and stop() which I'll add).
-
Inspired by @Gordon writeup to control a stepper motor here, I decided to write a control module for the ubiquitous 28BYJ-48 stepper. These are used everywhere and are manufactured by the millions, so they can be had for very cheap (I just bought 10 with free shipping on eBay for about U$1 apiece). In "4 step" mode there are 2048 steps in a full turn. 8 stepping gets you 4096 discrete steps per 360 degrees.
Note, this is a work in progress, so there are still aspects/concepts evolving in how it works. For now, though, here's what's implemented:
connect(pin1, pin2, pin3, pin4): Used to initialize the driver when loading the module. The pins are the 4 stepper motor coil drivers. Returns an object for controlling the attached stepper motor.
obj.step([ccw[, step8]]): Turns the stepper one step. Optional flags, if true, change direction to counter-clockwise (default is clockwise), and to step with the 8-step schema vs. the 4-step schema (read up on stepper motors, and this will be totally clear).
obj.move(steps[, ccw[, step8[, fnDone]]]): Move the motor shaft 'steps' steps. The true/false flags 'ccw' and 'step8' operate as explained above; the optional parameter 'fnDone' is a callback that gets invoked with the move is completed; this parameter is necessary because the call is non-blocking -- i.e. doesn't wait for the move to complete. Negative 'steps' values will simply reverse the sense of the 'ccw' flag -- i.e. moving -100 steps with ccw 'true' will move cw.
obj.moveAngle(angle[, ccw[, step8[, fnDone]]]): Same as obj.move() except the amount is specified in angular degrees rather than steps.
obj.zero(): Set the current position as location 0 for the following two functions.
obj.moveTo(target[, ccw[, step8[, fnDone]]]): Move to specific step count relative to zero set.
obj.moveToAngle(target[, ccw[, step8[, fnDone]]]): Move to a specific location relative to zero, target in angular degrees.
Properties of the stepper class that can be set separately:
obj.speed: A float value between 0.0 and 1.0, where 1.0 is the maximum speed the shaft can turn, and still maintain accuracy. Setting to 0.5 will cause the shaft to turn half as fast. This parameter affects the delay time between steps, which right now seems to only work 100% reliably if 3ms, but works almost 100% reliably at 2ms so long as the initial steps are a bit slower to allow acceleration of the internal, geared-down motor. I'm still playing with this. Default is 1.0 when the object is created.
Example:
stepper = require("28BYJ48").connect(B3, B4, B5, B6); /* on instantiation, the driver will be zeroed at the stepper's current position */ stepper.moveAngle(45); //turn clockwise 45 degrees stepper.move(256, true); //turn counterclockwise 256 steps, which is 45deg in 4 step mode stepper.move(-1024, false, true); //turn counterclockwise 1024 steps in 8-step mode; ==90deg stepper.moveTo(90, false, false, done); //will turn 180deg/1024 steps clockwise in 4-step mode, then call function 'done()'
-
Since size is always an issue, this should be structured as an extension to the existing driver -- totally agree. Although compared to my GUI library, this thing is nothing more than thin smoke :-)
Maybe even recast it as a 1602A display driver rather than a more generic HD44780 driver, as I think it safe to assume that that hardware always has the R/!W connection exposed. What do you think?
Then, anyone with a different display implementation using the HD44780 can still use the 1602A driver for their display, even if its something else.
It's not finished anyway, and won't be for a while. This, like the GUI project, are the output of my learning and experimenting with Espruino, MCUs in general, and the huge universe of "things" to attach as input sensors and output UI. So, unless there is someone out there dying to have this polished up so they can use it for a real project, it's on the "fiddle with it" shelf right now as my interest wanders around from one thing I'm messing with to another.
Eventually (like, before the end of the calendar year) I plan to take a weekend to polish this, the GUI, a 28BYJ-48 stepper driver I just wrote this weekend (I'll be posting on that later today), and a few other tidbits into formal, submitted modules to the Espruino project on Github.
Until then, I'll keep posting code in the forum for others to check out, looking for feedback.
-
@Wilberforce: 4x faster? I must have something configured wrong. I find that the console is slower and sometimes delays responses to typing etc. over wifi. It can be very annoying to be typing and have a pause for a second (or a few) before the characters your typed print out in the console and "catch up" to your typing.
Doesn't happen with the serial connection. 115200 is very fast.
Something I haven't configured properly for wifi? I hope?
-
@allObjects, thank you for the kind words -- much appreciated!
Of course I'm actually an incredibly arrogant bastard that actually believes he's smarter than everyone else on the planet, but I fake some humility so that all you lesser creatures will continue to be willing to interact with me.
:-) :-) :-)
-
I normally think of myself as a pretty bright person, but for the life of me I seem to be dumb as a lump of granite when it comes to the Module mechanism. What I want to do is conceptually pretty simple: Make a reusable object class. Maybe the module mechanism isn't suited for this? After half an hour looking through source code for a dozen modules or so, I couldn't find anything that looked like what I'm trying to do.
I'd like to be able to do the following... The application would be coded as follows:
require("myClass"); abc = new myClass(); console.log(abc.add(1,2)); console.log(abc.getNextPresident());
And the module, myClass.js, looks like this:
function myClass() { this.nextPresident = "Bozo the clown"; } myClass.prototype.add = function(a,b) { return a+b; }; myClass.prototype.getNextPresident = function() { return this.nextPresident; }; exports myClass;
This, doesn't work. After the require, Espruino seems completely unaware of any constructor function "myClass".
I can see how to work around this by adding an exported interface to create an object instance directly (this is done again and again in modules with the common 'connect' function on an exports declaration), but this is very "kludgy" to me -- isn't there any way to simply include something that acts like a traditional library?
Also, I find that when I do this, it results in a doubling of space usage. The module containing all the method functions gets cached (one copy of everything), then all these functions get created again when constructed in the initial call. To make it clearer, here's what I've done to make this work:
exports myClass.init = function() { myClass = function() { this.nextPresident = "Bozo the clown"; }; myClass.prototype.add = function(a,b) { return a+b; }; myClass.prototype.getNextPresident = function() { return this.nextPresident; }; };
Then, I use the module like this and it works:
require("myClass").init(); abc = new myClass(); console.log(abc.add(1,2)); console.log(abc.getNextPresident());
Problem #1 is it uses 2x the space. I think this is because the call above caches the modules code as part of the 'require' call, and then the init() loads another copy of the class (constructor and prototype functions) again in memory. #2: I don't like it. Awkward.
#1 is the real problem. I can live with #2.
Is there some way to expose the function created when the module is loaded and executed in the root scope, as described in the modules page? This would address both #1 and #2.
-
Thanks very much for the detailed discussion! I'm a geek about this sort of stuff, so the more understanding the better :-)
In the end, the problem can be summed up pretty simply: Scope.
Rereading the primer on making modules I think I found the solution -- the section declaring public members. I didn't do that. Giving that a try in a bit...
Also, ran across this again (I need to get kicked in the head twice sometimes to notice I've been kicked at all :-)):
Can I dynamically load (and unload) modules?
Yes. By default each module that is loaded will be cached (to avoid loading modules >twice). However you can call Modules.removeCached('modulename') which will remove >the module from the cache and free the memory that it uses.
I think this is what's doubling the space usage over just loaded the same code directly from the IDE. IOW, there is a cached copy of the code, and another copy in the working space of the interpreter.
I'll try using Modules.removeCached() in the main demo code to see what happens, but I suspect it will make the loaded code non-functional (as if it wasn't there). @Gordon?
In the end, I may just have to structure this as a set of code files that must be literally appended to the application source in order to keep from wasting the very precious RAM on the F1, if code duplication because of the Module mechanism wastes all that space.
It's ironic, because the Module caching mechanism seems intent on SAVING rather than WASTING space, and for the problem its intending to solve, it does. However, looks like there's an unintended side-effect of wasted space when there isn't the circumstance of loading the same module more than once.
-
Pretty much... just that right now, there's no "awareness" of the second line in any of the code. While you can certainly write something there using the original code from @Gordon, the additions I've made are completely blind to that part of the hardware.
As implemented in the attached code above, the scroll feature is really only usable for a single line up to 40char on the first line. The concept as implemented was intended to be able to start with a clear display, send something to display via the print method, and have it do something sensible if longer than 16 char.
Because shift function of the hardware shifts both lines together over their respective buffers, makes shifting two lines of different lengths a bit awkward, if the shorter one isn't going to simply be sacrificed in "sensible" scrolling for the sake of displaying the entire longer line. A simple implementation would continue to scroll the shorter line off to the left as the rest of the longer line came into the display.
That may not be anything to fret about, in terms of the user experience. Can't say until I see it. Adding the logic to scroll to the end of the longer line (basically a Math.max() call, essentially) should be simple.
Handling the two lines independently would be a nightmare of moving data around in the buffer.
-
Thanks for the feedback, guys.
Ran into problems. I have successfully split the GUI code into 4 separate modules: Widget, Button, CheckBox, and Slider. Widget must always be included (require("Widget")), and must come first.
I clearly didn't understand scoping and namespace particulars, however. Simply cutting up the source and adding exports lines didn't do the trick. The scope the module is loaded (and run) in is not the same scope as the main console prompt. After looking at other modules, it looks like I have to call a function exported and set everything up there.
So, as a first-pass, I just took the entire "class" for one of these objects, and wrapped it in an init() function that's exported. Constructor function, prototype properties and functions, etc. -- literally indented the entire thing and put "exports.init = function() { ... }" around it. Then, I use it all this way in my demo code:
require("Widget").init(); require("Button").init(); require("CheckBox").init(); require("Slider").init(); var w; var sld; function start() { LCD.clear(); new Button({ style: 'flat', area: [58,5,100,50], text: 'LED1 on', color: new Uint8Array([1, 0, 0, 102]), border: 5, textColor: new Uint8Array([0,200,200,200]), onPress: function() { LED1.write(!LED1.read()); this.text = LED1.read() ? "LED1 off" : "LED1 on"; }, }); new Button({ area: [163,5,100,50], text: 'LED2 on', color: new Uint8Array([1, 0, 128, 153]), onPress: function() { LED2.write(!LED2.read()); this.text = LED2.read() ? "LED2 off" : "LED2 on"; }, }); new CheckBox({ area: [70,70,150,30], text: 'Backlight', textColor: new Uint8Array([0,255,255,0]) }); sld = new Slider( { area: [10,189,300,50], min: 0, max: 24, value: 0, range: [0, 1], showSlide: false, onPress: function() { SPI2.send8bit(Uint8Array(this.pixels.buffer, (this.value>>>0)*3, 72), 0b00000011, 0b00011111); }, onHold: function() { SPI2.send8bit(Uint8Array(this.pixels.buffer, (this.value>>>0)*3, 72), 0b00000011, 0b00011111); }, draw: function() { strips = Math.ceil(this.area[2] / 8); for (i = 0; i < strips; i++) { hue = i * (this.range[1] - this.range[0]) / strips + this.range[0]; LCD.setColor2(Uint8Array.prototype.HSBtoRGB([1, hue * 255, 255, 255])); LCD.fillRect( this.area[0] + i * 8, this.area[1], this.area[0] + (i + 1) * 8 - 1, this.area[1] + this.area[3] ); } LCD.setColor2(this.borderColor); LCD.drawRect( this.area[0], this.area[1], this.area[0] + this.area[2], this.area[1] + this.area[3] ); } }); sld.pixels = new Uint8Array(144); for (i=0; i<48; i++) { c = (new Uint8Array([1, (i%24)*255/24, 255, 25])).HSBtoRGB(); sld.pixels[i*3] = c[2]; sld.pixels[i*3+1] = c[1]; sld.pixels[i*3+2] = c[3]; } SPI2.setup({baud:6400000, mosi:B15}); new Slider({ color: new Uint8Array([0,100,100,100]), slideColor: new Uint8Array([0,200,200,200]), area: [60,120,200,25], min: 0, max: 1, value: LCD.brt, onPress: function() { LCD.setBrt(this.value); }, onHold: function() { LCD.setBrt(this.value); } }); }
Not sure if this is the right way to do this (I'm really trying to do what #include does in C). What I found is that it seems to consume twice the memory space just getting the stuff into the system than if the code in those require statements is just literally there rather than being loaded through the module system. This is before even executing the start() function from the demo code, which creates the objects.
I don't get it.
-
Actually, the Button implementation has 3 callbacks -- onPress, onHold, and onRelease. What you're seeing on the action of the buttons is simply because I implemented the action in the onPress callback for those two buttons.
However, you point out unimplemented functionality that I just went and implemented -- a check to see if the touch was still in the button area on release in order to call the onRelease callback... I agree that onRelease shouldn't be called if the finger isn't on the button anymore when lifted from the screen.
I'm leaving onHold alone -- i.e. once the press is detected, the "focus" remains on that control even if the finger leaves the area of the control, and continues to affect it through the onHold callback. This allows seeing where the slider is more easily while moving it if you can still move it back and forth while your finger is above or below the actual control, after it's been "activated" with a press.
Here's how easy it is to set up one of these buttons, if the GUI is available (this is the 3D purplish one):
new Button({ area: [163,5,100,50], text: 'LED2 on', color: new Uint8Array([1, 0, 128, 153]), onPress: function() { LED2.write(!LED2.read()); this.text = LED2.read() ? "LED2 off" : "LED2 on"; }, });
-
Posting up a video of my enhancements to the HD44780 driver reminded me that I never got back here and posted a video of the GUI in action. So... here it is!
Shown here is a demo of the Button, Checkbox, and Slider classes. There's a layout bug in the Checkbox class that I still need to fix. The slider can have the slide hidden so it can be used to manage more interesting "sliding" things, like shown here with the addressible light strip... pretty cool, eh?
Button supports a flat and a 3D style.
I asked a question elsewhere today about modules, which is directly related to this work. The entire GUI code, even minified, is quite big, and the STM32F1 chips used on the Haoyu MiniSTM32 display boards have about half the RAM of the F4's used on the Pico. So I'm going to break it up into individual modules for each widget type (Button, Slider, etc.). Then, only the elements actually being used can be loaded, using only the space needed.
Any and all feedback welcome! This is a "fun" project for me I've been tinkering with as I get to know Espruino and the MCU world. I've ordered about U$50 worth of various sensors and things to play with, so more funny business from me over the coming months.
I just gotta get off my lazy tusch and do one of the REAL projects I've been thinking about. I'm having too much fun experimenting :-) :-)
https://youtu.be/FkOfEuJQW-g
-
Unfortunately, the hardware simply shifts the entire 2-line display over the 40 char "buffers" together -- the two lines can't be shifted separately.
The "scroll" is simply using the shift function of the HD44780 combined with setTimeout() and a little logic to handle the end condition to scroll/marquee the display.
-
I've been playing with a 16 char, 2 line 1602A LCD display using the HD44780 module written by Gordon (3 years ago!). While the module provides basic functionality to write characters to the display, there is a lot of interesting functionality in the HD44780 driver chip that isn't implemented, so I started enhancing the module to add some of this functionality.
Also, found a bug... the HD44780 has a busy condition while its working on an instruction, and the busy flag needs to be checked before committing another operation. You can best see this manifest by writing to the display, then clearing and immediately writing again... the second "print" call will almost always screw up and you'll get junk in the display (at least for the 1602A display I'm playing with). I added code to fix this, requiring the ability to read from the HD44780, something not implemented in the current module.
This is a Work In Progress, so the additional functionality in the attached module is not fully baked; for instance, all of it is implemented only for the 4-bit parallel interface. I haven't addressed the I2C connection option. Still, if you want to play around with it, here it is, attached.
Added functionality:
lcd = require("HD44780").connect(rs,en,d4,d5,d6,d7[,rw]); //this is being pulled locally from my modules folder in the project directory
The params in the connect statement above correspond directly the the pin names on the HD44780 chip. What's new here is the addition of the R/!W pin at the end. In wiring the display up, this needs to be connected to an actual pin on the MCU rather than simply grounded, as read operations are now supported. It's at the end so it can be left out, and the driver will be backwards compatible with code written for the older version (with the bug fix, though).
lcd.print(string[, scroll]);
https://youtu.be/YOoE34pRXbg
While the display is 16 characters wide, the internal buffer in the 44780 is actually 40 chars per line. The display is actually a 16 character "window" on the underlying 40 character buffer. You can send a 'string' parameter up to length 40, and it will be written into the display buffer (called DDRAM), with the first 16 characters displayed. There are 44780 instructions to shift the display window left or right in DDRAM to display different parts of it.The optional 'scroll' parameter above if 'true' will cause the display to scroll left automatically when a string longer than 16 characters is written, until the last character is displayed. It then pauses for a bit, resets back to the beginning of the string, and repeats.
The interval between single character shifts is by default 150ms (looked pretty readable to me), but can be set as desired with the 'sdly' property, like this:
lcd.sdly(75/*ms*/);
The code above takes effect immediately (if scrolling), and would move twice as fast as the default.
lcd.shift(count);
This will shift the display window left or right by 'count' character positions. Direction is specified by the sign of 'count'.
buf = lcd.read(addr,len,cg)
Reads from either DDRAM (display buffer) or CGRAM (character generator RAM), and returns a Uint8Array of length 'len'. 'addr' is the starting address in the selected RAM buffer to read from. For DDRAM, the first line starts at addr 0, second line at 0x40. CGRAM is a completely different animal that I won't address in this post. Example:
lcd.clear(); lcd.print("this is a test of the 2 line display"); buf = lcd.read(8,16,false);
After this code, the display would show "this is a test o", and buf would contain [97, 32, 116, 101, 115, 116, 32, 111, 102, 32, 116, 104, 101, 32, 50, 32] ("a test of the 2 ").
lcd.busyWait();
Waits for the busy flag to clear after an operation is executed. This is really only useful if you are doing low-level things by directly writing to the control register. Used internally in the module, you probably don't ever need this because it's already accounted for in read/write operations (this was the bug fix).
Finally, all the pins are now stored as properties on the instance, with the names shown above in the connect call. So, for example, the Register Select pin can be accessed as obj.rs; the set of 4 data pins can be access as an array with obj.data. This makes it easy to program directly at a low level while still using the high-level functions (like 'print') on an HD44780 instance.
-
Can other modules be used in a module with the require() statement? The writing your own modules page addresses this to some degree, but it wasn't entirely clear to me what would happen if, for instance, the same "core" module is referenced in several different modules.
The scenario: I want to break up the GUI components I've been working on into separate modules so that only the elements being used can be individually referenced, saving space. So, I want to break the code up into a Button module, Slider module, Checkbox, Textbox, etc. All need a "core" set of functionality that would be included in each module.
So, if you were to create an interface that used buttons and sliders, you would include just these components in your code like this:
require("Button"); require("Slider");
Each of those have in them,
require("GUIcommon");
which, of course, is then getting called twice.
Is this handled gracefully, the "right" way so there isn't duplication?
-
Reading through the "PWM how to do it yourself" page, what is described is a software approach.
Is analogWrite(pin, level, {freq:}) the high-level interface to STM32 hardware PWM? I.e., control of frequency via the options parameter, and duty cycle via the level/value parameter?
So, a 1000Hz, 25% duty-cycle waveform is produced, entirely without any code running but simply via the hardware (after Espruino sets it up from the analogWrite call) with analogWrite(pin, 0.25, {freq:1000})? Once done on a board that supports hardware PWM, like the Pico, the MCU is generating that waveform all on its own, the Espruino main loop just idling, right?
-
Hey guys!
I decided to just go with extending Uint8Array by adding my color methods to the prototype. Decided I needed to "get in the MCU thinking mode" -- i.e. small footprint design, rather than my bias toward "elegance".
Been coding Android stuff for years, memory footprint not really an issue. Rather, elegance, simplicity of interfaces, clever OO design, etc. were important.
With such a tiny amout of memory to fit in, this has to be very memory efficient to leave room for the actual application!
Anyway, as I said, moved on... just got the GUI library working with the new, compact Uint8Array(4) type of color "object". Going to shoot a quick video, post and puff up my chest for a bit. It's pretty cool. Watch for the thread over in the General section in an hour or so :-)
-
Thanks for the quick reply, Gordon. I have considered the solution of simply extending the Uint8Array prototype, and in the end of that's the only way, I'll do it. Memory footprint trumps OO elegance for this sort of application.
I've not given up yet, though. Check out this: Extending JavaScript Arrays While Keeping Native Bracket-Notation Functionality
I'm playing with this idea as we speak, and will report back on the memory usage if successful. If I can get it to allocate the same amount of memory per instance as simply creating a 4-element Uint8Array -- solved!
If that doesn't work, I'll take a look at the packing approach you talk about -- a "color" in this scheme is 4 bytes -- one word. A less elegant solution is to simply add member to the Uint8Array prototype called 'color', then bury all the color-related methods in there as properties of the color object, on the prototype.
-
I'm trying to make a "class" called Color that is a 4-element Uint8Array. The point here is compactness -- I'm trying to minimize the memory footprint, which still having my own "object" with lots of goodness in terms of "methods" on an instance of Color (things like accessing the color as an RGB or HSB 8/8/8 bit triple in 3 of the 4 elements -- the 4th (actually first) specifies the format of the three color values).
What I can't figure out is how to call Uint8Array from my Color constructor to return an array as a Color class object that can be indexed and behave like a regular Uint8Array, while responding to my custom "methods" in the prototype. So it can be used like this:
c = new Color([0,100,100,100]); //returns a Uint8Array of [0,100,100,100] that is type Color /* invert color */ c[1] = 255 - c[1]; c[2] = 255 - c[2]; c[3] = 255 - c[3]; /* get HSB version of color from method attached to Color proto */ c_hsb = c.RGBtoHSB();
Here's how this is set up:
function Color(c) { //what do I do here with 'c' to initialize and return a byte array initialized with 'c', that will return 'true' for 'instanceof(Color)'? } function proto(){}; proto.prototype = Uint8Array.prototype; Color.prototype = new proto(); a = new Color([255,255,255]);
Of course, with nothing in the Color constructor bur with the Uint8Array prototype inherited, returns an empty object for the assignment to 'a' on the last line -- not surprising. If I do the following:
function Color(c) { return new Uint8Array(c); }
In the constructor, I get a Uint8Array type object back, not Color type object (which doesn't surprise me). So, none of the "methods" that are a part of the Color prototype are accessible (except through directly calling them as Color.prototype.method()).
Any help?
-
Very interesting (and nice work!).
IS there anything similar, at all, on the other Espruino platforms? Specifically, I'm interested in the HY-STM32F1 board, where I've been working on a GUI. If I could flash the GUI module code to flash memory, and execute it from there, it would free up a TON of RAM for actual application code.