středa 30. listopadu 2016

Forth syntax colorizer in VS Code

FlashForth is a wonderful Forth implementation for selected MCU types, namely PIC18, PIC24, PIC30 and dsPIC33, and also AVR ATMega.

I have quit playing with PIC processors many years ago, at the time when the most exciting PIC was the good old PIC16F84, but AVR processors drew my attention thanks to various Arduino variants but especially because of the omnipresent Arduino Nano clones from China, cheap and easily available in quantities.

I have never been very much excited by the Arduino IDE, and programming in C or C++ doesn't make me happy either.

That is why Forth implementations for AVR/Arduino have always attracted me.

The only problem seems to be lack of reasonable code editor or IDE supporting Forth (because it is a weird language for most people in the world). On the one hand Forth is a language in which you are supposed to develop your program interactively on the target system, at the same time doing the debugging, and incrementally build the final solution. On the other hand, the usual bunch of tools available for embedded Forth fans – serial port monitors and terminal programs – do not provide many syntax highlighting features or other amenities.

So where to go for some more comfortable source editing?

First of all I tried my long-time favorite editor, Notepad++.  Unfortunately, I had to give up. FlashForth supports three different numerical notations (#decimal, $hex and %binary), one too many for NPP's User defined language template. Additionally, NPP was unable to highlight any of the two features properly - neither numerical constants, nor comments.

Then I realized that in fact the most comfortable and powerful code editor I have been using recently was ... Visual Studio Code! Microsoft bashing aside, VS Code is a really pleasant tool and, compared with any bloated IDE I had been using before, it is as light as air. And it is apparently less quirky and more flexible than Chrome developer tools.

It took me several hours to learn how to write language grammar file (the JSON version, the XML option is just too horrible...) but in the end I do have a language grammar file that works.  For sake of readability and thanks to the easy configuration of the language grammar file I added a few (key)words that are distinct among the forth dictionary entries - words allowed in compile mode only, words modifying word's behavior (immediate and inlined) and defining words create, constant, variable.

I think the highlighted code looks quite good:

I will try to post the (Flash)Forth language extension to VS market as soon as I learn how to do that.  In the meantime, if you are interested, you can ask me for the language file by e-mail. (this will be later replaced by a link to github or to VS market.)  Any takers wishing to test and post the Forth extension on my behalf will be more than welcome...

středa 1. července 2015

Color conversion from Hue to RGB without ifs

The conversion of Hue value to RGB components usually involves a set of conditions because there are six different intervals of hue values where always two of the RGB components reach maximum value or zero while the third one is the only one changing between zero and the maximum.  One of many examples can be seen here.
Although such approach is technically correct and, of course, returns correct value, the number of necessary if statements gives the algorithm untidy and kind of "unsystematic" look and feel.
Considering the circular essence of Hue, one can intuitively feel that it should be enough to have one function converting Hue to the respective Red, Green or Blue value, using a "rotation" parameter.
Let us remember that maximum Red value is occurs at Hue = 0° or 360°, and maximum Green and Blue occur at 120° and 240°, respectively.  Additionally, the red maximum 100% occurs in the intervals from 0° to 60° and between 300° and 360°.  If we translate these values from 0°...360° range to -180°...+ 180°, we can see that the interval -60° to 60° is 100% Red and the adjacent 60 degree segments represent red fade-out zone.
Obviously, the Red maximum is at Hue = 0°.  Thus, the Red component will depend on the Hue distance from zero.  
R' = | Hue mod 360 - 180 | 
The next task is to ensure that Red will become zero at the distance of 120° from Hue = 0° and that it will be constant and maximal between -60° and +60°.  In the interval of interest value of R' is within the range <60,180>. To adjust the value to zero we just subtract 60:
R'' = | Hue mod 360 - 180 | - 60
Now our R'' value is between 0 and 120 in the interval of interest.  However, we want to make Red constant within ±60° around Hue = 0°.  Easy to do, we will cap the value not to exceed R'' for Hue = 60°, i.e. 60.  In most programming languages we can use minimum function to achieve the capping:
R''' = MIN( | Hue mod 360 - 180 | - 60, 60 )
Our Hue to Red conversion is almost perfect. Within 60° off Hue = 0 we have the maximum Red and within 120° around zero the Red gradually fades out.  However, for Hue < -120 or Hue > 120 our Red value (R''') is negative.  To keep Red within the range of non-negative numbers we will use the same trick that we used for cap, now setting the floor to be zero:
Red = MAX ( MIN( | Hue mod 360 - 180 | - 60, 60 ), 0 )
So, we are done with the Red.  How about Green and Blue, though?  RGB colors in HSL scheme are placed around a circle, do you remember? Therefore we can use the same algorithm for Green and Blue, we just need to "rotate" the input Hue value to obtain the correct Green and Blue maxima.  The Green maximum occurs at Hue = 120, i.e. shifted by +120° from the Red maximum.  We have to subtract 120° from Hue to obtain Green value.  And because the circle has 360°, subtracting 120° is the same as adding 240°:
Green = MAX ( MIN( | (Hue+240) mod 360 - 180 | - 60, 60 ), 0 )
And the Blue value will be obtained using the same pattern, only this time the shift will be 120°:
Blue = MAX ( MIN( | (Hue+120) mod 360 - 180 | - 60, 60 ), 0 )
Go, try this in your favorite programming language.  Can you implement this in your Arduino driving red, green and blue LEDs?