EDIT: Chris has posted a new version of this article that fixes a lot of the issues that we found... specifically with the AVR compiler that ships with the Arduino IDE. Check it out in the new post here.
------------------
Preamble
Chris and I have been pretty busy the past month or so, and the TouchShield Stealth (128 x 128 pixels) and TouchShield Slide (320 x 240 pixels) are now both ready for a major "firmware" upgrade. Thank you to everyone who sent back code optimizations on the graphics routines (especially Sheldon and Omar, although technically it's not fair - you're actually real game programmers). The old TouchShield ran in the low 10-15 frames per second, but with this core now runs closer to 30-40 frames per second! Also, ever since my little project a few weeks back, I've had a lot of encouraging email support from the Processing community, and with a little bit of help, now both the Stealth and Slide both run SubProcessing (a subset of the Processing language). That means that programs can be written on the Arduino, and you can literally hot swap the Stealth and Slide in real time and the program works simultaneously, and even scales the graphics accordingly... (I'll definitely take some videos later this week).
In the meantime, there are a few things that Chris and I am still working on, namely picture uploading. Although the TouchShield Stealth image uploader still works, the upgraded chip in the TouchShield Slide means that I have to rewrite the application. This time, I'm going to write it in Java so the same program works on Mac, Windows, and Linux! I'm hoping to have that wrapped up before next week. Without further ado, here we go! (and if you set a playlist to William Tell's Overture, you'll definitely be done before it completes...)
This is the new TouchShield Core, version 0.9. You can click here, and download it on the "app store." It's all GNU GPL'd.
Act 1: Overture
The first step, is to make sure you're running the latest version of the Arduino IDE application, which as of December 12th, 2008, is version 0012. You can grab the latest version over at the arduino.cc website, here.
Please install version 0012 or greater (because David and team upgraded the AVR compiler, to a more efficient version, so that now it works a lot better!). Once the file is downloaded, unzip it to a new place on your hard-drive, and proceed to step 2...
Act 2: Legato
The next step is to install the "core" files into the new installation of the Arduino IDE. This means copying the touchStealth and touchSlide folders into the following folder:
arduino-0012/hardware/cores/
After this step, (and on my hard drive), the cores folder includes 5 folders:
touchStealth/
touchSlide/
blank/
atmega8/
arduino/
Now that the folders are installed, you just need to make sure that the Arduino IDE program knows about the folders. To do this, open the following file:
arduino-0012/hardware/boards.txt
This file contains a description of all of the Arduino cores and compilers, that the IDE can recognize. At the end of this file, just add the lines below (or, you can copy over the version of the boards.txt file that I've included). Before you edit the boards.txt file, make sure that all versions of the Arduino IDE are closed, and you don't have any running on your computer. If you do, it might not save the changes to the boards.txt file correct. So just close and exit from any versions of the program you might have running, just to be safe!
##############################################################
stealth.name=TouchShield Stealth
stealth.upload.protocol=butterfly
stealth.upload.maximum_size=57342
stealth.upload.speed=57600
stealth.bootloader.low_fuses=0xFF
stealth.bootloader.high_fuses=0x98
stealth.bootloader.extended_fuses=0xFB
stealth.bootloader.path=TouchShield
stealth.bootloader.file=TouchShield_boot.hex
stealth.bootloader.unlock_bits=0xFF
stealth.bootloader.lock_bits=0xFF
stealth.build.mcu=atmega645
stealth.build.f_cpu=16000000L
stealth.build.core=touchStealth
##############################################################
slide.name=TouchShield Slide
slide.upload.protocol=butterfly
slide.upload.maximum_size=258048
slide.upload.speed=57600
slide.bootloader.low_fuses=0xFF
slide.bootloader.high_fuses=0x98
slide.bootloader.extended_fuses=0xFB
slide.bootloader.path=TouchShield
slide.bootloader.file=TouchShield_boot.hex
slide.bootloader.unlock_bits=0xFF
slide.bootloader.lock_bits=0xFF
slide.build.mcu=atmega2560
slide.build.f_cpu=16000000L
slide.build.core=touchSlide
##############################################################
Now, you're ready to move onto step 3!
Act 3: Autumn
The TouchShield Stealth and TouchShield Slide communicate with the Arduino using pins 2 and 3. That means it uses Software Serial, not the built-in hardware serial. In order to get Software Serial working properly, then, we're going to copy over the AFSoftSerial libraries into the appropriate location (thanks Limor!). While we're at it, we're also going to copy over the library Chris and I've written to display large numbers on the screen, in case you want to play around and make big timers or countdown clocks...
Just go to the folder:
arduino-0012/hardware/libraries
Now copy into this folder the two folders, touchLargeNums and AFSoftSerial.
On my computer, the libraries folder now has 12 folders in it:
Stepper/
Sprite/
SoftwareSerial/
Servo/
Matrix/
LiquidCrystal/
Firmata/
Ethernet/
EEPROM/
AFSoftSerial/
touchLargeNums/
Wire/
Voila!
Now, ready to move onto step 4...
Act 4: Allegro Moderato
You open the door. You walk through the door, you roll a die. A dwarf appears. Press 1 to use your magic wand. Press 2 to cast a spell. Press 3 to.... Ok, now it's time to boot everything up!
Open the newly installed and upgraded version of the Arduino IDE. This is the file in the arduino-0012/ folder called "arduino.exe" or "arduino", depending on what operating system you're using.
Place the TouchShield Stealth or TouchShield Slide on top of the Arduino. If this is the first time you're connecting your Arduino to your computer, you'll want to make sure you also install the FTDI drivers. The guys at arduino.cc have great tutorials for installing the drivers properly, over here:
http://arduino.cc/en/Guide/Windows
http://arduino.cc/en/Guide/MacOSX
http://www.arduino.cc/playground/Learning/Linux
Once the drivers are installed, or if you've already installed them before, connect the Arduino to the computer using a USB cable.
The Arduino IDE will take a few seconds, and then it will recognize the Arduino. The next step is to program the TouchShield and the Arduino with the appropriate programs. The TouchShield will run the SubProcessing library, which is a little version of the Processing Graphics library, written just for the TouchShield. From now on, any program written for the TouchShield Stealth will work on the Slide and vice versa, as well as being cross-compatible with any version of Processing you might have installed on your computer. This means I can prototype graphics on my PC, and then flash it down to the Arduino, and it'll look the same!
So the first step is to program the TouchShield. From December 18th, 2008 and onward, every TouchShield that gets mailed out will come pre-loaded with the latest version of the SubProcessing software as of that date, so if this is the first time you're using it, you can skip this step. Otherwise, continue to update the TouchShield's firmware:
Open up the TouchShield.txt file. It contains a small little program that puts the TouchShield into "canvas" mode. This means it sits there, waiting for display commands from the Arduino. That code looks like this:
void setup(void) {
}
void loop(void) {
beginCanvas();
}
Copy and paste this code into the Arduino IDE main window. Then, select the appropriate Serial port from the Tools->Serial Port menu. On my computer, it's serial port 18. Then, select the right board from the Tools->Board menu (either TouchShield Stealth or TouchShield Slide).
Click the compile (or play) button to compile the code. Now, press the reset button on the TouchShield. On the Stealth and the Slide, it's the button right next to the USB connector on the Arduino. This puts the TouchShield into reset mode, waiting for a program from the Arduino IDE.
Now press the program button, or "upload to I/O board". The LEDs will blink as the program is downloaded to the board, and then it'll finish. Done!
The final step is to load a program onto the Arduino.
Open the Arduino.txt file, and copy and paste this into a new program in the Arduino IDE window. Now, select "Arduino" from the Tools->Boards menu. Press play to compile, and then press the "upload to IO board" button to send the program to the Arduino. Done!
In about a second or two, the Arduino will reset, and will start sending commands to the TouchShield. The program is pretty simple, it just displays a little red square that you can drag around the screen. If you happen to have a Slide and a Stealth, you can hot-swap the two shields one after the other, and they'll both start displaying whatever the Arduino sends to them. In some cases, it might help to cycle the power on the Arduino and TouchShield, by reseting or re-plugging in the USB or Lithium Backpack.
If you have any questions, or want any help writing some code, or if anything at all doesn't work, or if you're just looking for someone to bounce ideas or talk to, just drop me an email!
Matt and Chris
(and Limor and Sheldon and Omar - thanks!)
Thursday, December 18, 2008
Wednesday, December 17, 2008
A silly little Twilight Game
There are some days I go to sleep after a long, hard day, and I think to myself, today... I really accomplished something, and that makes me happy and I fall asleep content.
Then there are days like today, where I'm just confused... but I suppose it was for a good cause. Brian, a friend of mine who got one of the first GamePacks ever, emailed me asking how hard would it be for me to build the shell of a game for his kids. He wanted the theme of the game to be the movie Twilight. (Un?)fortunately I haven't gotten a chance to see that movie in theatres yet...
So, while this is not my proudest accomplishment ever, if it makes his kids happy, I suppose I can justify the effort (and at worst, it refreshed my memory about how hard it is to do object collision detection for games, even if it is just Edward's head vs. rotating pictures of bad vampires. Ugh. I can't believe I just wrote that. I think a little piece of me deep down inside just died a little bit...). But I digress:


Here's the game, written for the GamePack and the InputShield. I've uploaded the source code for it all over at the "app store" (which is really becoming more and more just a place to throw source code so I can at least stay a little organized). The Arduino runs a continuous polling algorithm on the InputShield to read the dual potentiometers (which are set to mode A), and then sends the bytes up to the TouchShield. The TouchShield, in turn, interprets the commands, and moves a little picture (sprite) of Bella's head around the screen. Meanwhile, Edward's head moves around too, and tries to avoid the bad vampire heads.
Although technicaaaaaallly...
If my quick scan of the character summary over at Rotten Tomatoes serves me correctly, Edward doesn't shy away from confronting these bad guys in the movie. Oh well.
In my version, he randomly selects an opposing direction, and flees in either the inverse X, inverse Y, or some combination of those directions. On a collision with the vampire head, the vampire then iteratively selects whether to flee in the inverse x or y direction... or do nothing and continue charging ahead (dun dun dun). The suspense is already killing me :)
Here's a picture of it sitting on my computer. You can see the paper on the left side, which actually has the math and logic for the sprite collision checking algorithm. There must be a more optimized way to do it besides 8 ands, 16 compares, and 8 additions?

Probably the hardest part to code was the Edward vs. vampires collision detection and randomized scatter function:
All of the source code is released under the GNU GPL over in a zip file, with the images and everything, over here.
Enjoy!
Then there are days like today, where I'm just confused... but I suppose it was for a good cause. Brian, a friend of mine who got one of the first GamePacks ever, emailed me asking how hard would it be for me to build the shell of a game for his kids. He wanted the theme of the game to be the movie Twilight. (Un?)fortunately I haven't gotten a chance to see that movie in theatres yet...
So, while this is not my proudest accomplishment ever, if it makes his kids happy, I suppose I can justify the effort (and at worst, it refreshed my memory about how hard it is to do object collision detection for games, even if it is just Edward's head vs. rotating pictures of bad vampires. Ugh. I can't believe I just wrote that. I think a little piece of me deep down inside just died a little bit...). But I digress:


Here's the game, written for the GamePack and the InputShield. I've uploaded the source code for it all over at the "app store" (which is really becoming more and more just a place to throw source code so I can at least stay a little organized). The Arduino runs a continuous polling algorithm on the InputShield to read the dual potentiometers (which are set to mode A), and then sends the bytes up to the TouchShield. The TouchShield, in turn, interprets the commands, and moves a little picture (sprite) of Bella's head around the screen. Meanwhile, Edward's head moves around too, and tries to avoid the bad vampire heads.
Although technicaaaaaallly...
If my quick scan of the character summary over at Rotten Tomatoes serves me correctly, Edward doesn't shy away from confronting these bad guys in the movie. Oh well.
In my version, he randomly selects an opposing direction, and flees in either the inverse X, inverse Y, or some combination of those directions. On a collision with the vampire head, the vampire then iteratively selects whether to flee in the inverse x or y direction... or do nothing and continue charging ahead (dun dun dun). The suspense is already killing me :)
Here's a picture of it sitting on my computer. You can see the paper on the left side, which actually has the math and logic for the sprite collision checking algorithm. There must be a more optimized way to do it besides 8 ands, 16 compares, and 8 additions?

Probably the hardest part to code was the Edward vs. vampires collision detection and randomized scatter function:
if ( ((xPos > xmet && xPos<xmet+i) && (yPos>ymet && yPos<ymet+i)) ||
((xPos+i>xmet && xPos+i<xmet+i) && (yPos>ymet && yPos<ymet+i)) ||
(
(xPos>xmet && xPos<xmet+i) && (yPos+i>ymet && yPos+i<ymet+i)) ||
((xPos+i>xmet && xPos+i<xmet+i) && (yPos+i>ymet && yPos+i<ymet+i)))
{
dirx2*=-1;diry2*=-1;
if (choicedir) {
dirx1*=-1;
} else {
diry1*=-1;
}
if (choicedir++ > 4) {
choicedir = 0;
}
xme += 2 * dirx2;
yme += 2 * diry2;
}
All of the source code is released under the GNU GPL over in a zip file, with the images and everything, over here.
Enjoy!
Labels:
Liquidware
Tuesday, December 16, 2008
How would you change the Arduino?
Talk about Merry Christmas!
I just got back from meeting up with a former professor of mine here in New York City (the one who taught me signals and systems back in undergrad - ugh), and he told me that he's been using the Arduino in his class now for about a year. But, his students keep running out of I/O and memory for their projects, and assignments. Sooo... (drum roll) he was wondering if I'd be willing to make a few modifications for him (like finding a way to fit in more IO pins, for starters). But here's the best part yet... he's going to use part of his grant to help fund it all... Thanks!
Anyway, it's only fair to give back to the open source hardware community, so in the next few weeks, over my Christmas vacation, I'm going to be laying out a whole new board, hopefully in time for the first week or two of 2009, to usher in the new year with a new board. Chris, Justin, Mike, and I learned a lot about about the little details with AVR back when we first built the TouchShield, so hopefully that will all come in handy this time around.
Here's the catch. The whole thing, literally everything down to parts lists and schematics and you name it, is going to be Open Source. As in GNU and Creative Commons and Free Software Foundation Open Source. As in real, true, 100% USDA prime "open source hardware". In fact, everything I build and code will go straight to David Mellis from the Arduino team, and maybe it'll even make its way into future Arduino releases (fingers crossed).
Anyway, if you have any special requests, just let me know, and I'll try my best to include it in the design! :)
I just got back from meeting up with a former professor of mine here in New York City (the one who taught me signals and systems back in undergrad - ugh), and he told me that he's been using the Arduino in his class now for about a year. But, his students keep running out of I/O and memory for their projects, and assignments. Sooo... (drum roll) he was wondering if I'd be willing to make a few modifications for him (like finding a way to fit in more IO pins, for starters). But here's the best part yet... he's going to use part of his grant to help fund it all... Thanks!
Anyway, it's only fair to give back to the open source hardware community, so in the next few weeks, over my Christmas vacation, I'm going to be laying out a whole new board, hopefully in time for the first week or two of 2009, to usher in the new year with a new board. Chris, Justin, Mike, and I learned a lot about about the little details with AVR back when we first built the TouchShield, so hopefully that will all come in handy this time around.
Here's the catch. The whole thing, literally everything down to parts lists and schematics and you name it, is going to be Open Source. As in GNU and Creative Commons and Free Software Foundation Open Source. As in real, true, 100% USDA prime "open source hardware". In fact, everything I build and code will go straight to David Mellis from the Arduino team, and maybe it'll even make its way into future Arduino releases (fingers crossed).
Anyway, if you have any special requests, just let me know, and I'll try my best to include it in the design! :)
Labels:
Liquidware
Thursday, December 11, 2008
Riding a bike is cool... but riding a unicycle is really cool
I was checking out the Arduino forums to get some ideas for my next project... and that's when it hit me. An RGB LED (Red, Green, Blue Light Emitting Diode)... in my last project I used a TouchShield to change colors depending on my mood
RED = Angry
Blue = Hungry
Magenta = Tired
Black = Sleeping
White = Excited
Orange = Happy
Yellow = Worried
etc.
The TouchShield is an OLED (Organic LED) screen with a total of 49,152 LEDs.
16,384 Red LEDs
16,384 Green LEDs
16,384 Blue LEDs
I thought I was soooo cool with my LED Matrix... but as it turns out, people are having just as much fun with one LED as I was with forty-nine thousand of them.
How?
RGB Lamp Test from Mike Mc on Vimeo.
I rest my case.
RED = Angry
Blue = Hungry
Magenta = Tired
Black = Sleeping
White = Excited
Orange = Happy
Yellow = Worried
etc.
The TouchShield is an OLED (Organic LED) screen with a total of 49,152 LEDs.
16,384 Red LEDs
16,384 Green LEDs
16,384 Blue LEDs
I thought I was soooo cool with my LED Matrix... but as it turns out, people are having just as much fun with one LED as I was with forty-nine thousand of them.
How?
RGB Lamp Test from Mike Mc on Vimeo.
I rest my case.
Labels:
Liquidware
Monday, December 8, 2008
Processing, meet Tom Duff
My girlfriend has turned me on to Taste Spotting, so I gave it whirl with chicken parmesan. The pictures are so enticing that I immediately started rifeling through the fridge, pushing leftover containers aside desperately searching for the ingredients. I knew they were in there somewhere, but it occurred to me that if there was a way to get rid of all those leftover containers faster, then I could get to my tasty meal that much sooner.
This reminded me of the pin register trick I wrote about in a previous post, but this trick starts to become really interesting when used with the concept of loop unrolling for hard-core code optimization.

Thanks to Tom Duff and his cleverly named "Duff Device", we can show this optimization technique in C and not assembler.
This code listing takes a variable length loop action and unrolls it into batches of 8 sequential actions. What a clever exploit of the switch statement!
Thanks Tom, and now it's possible to enhance many of the low-level drawing routines of Matt's Sub-Processing library on the TouchShield to support screen painting at 60 frames per second. Not too shabby for an 8-bit device.
Chris
This reminded me of the pin register trick I wrote about in a previous post, but this trick starts to become really interesting when used with the concept of loop unrolling for hard-core code optimization.
Thanks to Tom Duff and his cleverly named "Duff Device", we can show this optimization technique in C and not assembler.
/* A Duff Device
antipastohw.blogspot.com */
#define DUFF_DEVICE_8(aCount, aAction) \
do { \ int count_ = (aCount); \
int times_ = (count_ + 7) >> 3; \
switch (count_ & 7){\
case 0: do { aAction; \
case 7: aAction; \
case 6: aAction; \
case 5: aAction; \
case 4: aAction; \
case 3: aAction; \
case 2: aAction; \
case 1: aAction; \
} while (--times_ > 0); \ } \ } while (0)
Thanks Tom, and now it's possible to enhance many of the low-level drawing routines of Matt's Sub-Processing library on the TouchShield to support screen painting at 60 frames per second. Not too shabby for an 8-bit device.
Chris
Labels:
Liquidware
Ruby on Rails vs. Arduino Processing
Firstly, I'll just put it out there: yes, these two languages are meant to do two entirely, completely different things, and therefore cannot be directly compared with each other. But analogy and comparison are powerful (and fun) tools, so I'm going to use them today :)
I've gotten several emails over the past few weeks, asking if I could post the source code to the programs I've written in a zip file format, since blogspot tends to mess up the ampersands, greater, and less than signs in my Arduino sketches when I just copy and paste. Despite my attempts to try to fix each snippet I post, some inevitably mess up, so I decided to take a whirl at learning Ruby on Rails and made an open source "app store" (sort of like Apple, but 100% not really). All the app source code snippets I've posted ever are GNU licensed open source, and are now zipped into little packages over here. I'll try to do this from now on, too! Anyway, doing this made me learn a lot about the language underpinnings of Rails.
It was an odd juxtaposition: I had a chance to write Ruby code for the website, and in between functions I'd make some more progress on my Processing on Arduino app. Flipping back and forth between Rails and Arduino Processing was actually harder than I thought...
What is Ruby on Rails?
Arduino Processing
So, onto the list of similarities:
5) Isolation - Both languages and environments operate on the principle of isolation. That is, complexity in other parts of the environment are obscured when you're coding. In Rails, when you're writing a database model for one feature, you don't really care about or see the code for other database models. You just build the functionality you want there on the spot. In Arduino, you don't have to wrestle the complexity of the Atmega CPU, you just focus on the C functionality and hit compile.
4) Portability - Sketches written in Arduino Processing are typically just a single file, and only the most complex ones will be several files. That means that sharing code is as simple as a little copy and paste (though not onto a blog on blogspot, apparently). There's almost no configuration or customization necessary to go from one platform or computer to the next (only what serial port are you using). On Rails, pretty much the only thing you have to configure when porting an app from one computer to the next is the database.yml file (the one that stores your local database username and password). After that, it pretty much runs as configured, which is amazing considering all those sad, long nights in PHP world that I'll never get back :(
3) Universality - A few simple functions work everywhere, on anything. Arduino's print functions almost mirror the simplicity of the to_s() and related typecasters in Ruby. That way, you don't have to spend all your time worrying about data types and formats (yeck)
2) Code compression - On the Arduino, a 5 line program will get you up and running, blinking an LED, and that's it. On Rails, a 5 line edit to a data model could mean adding validations to every form on your entire website. So both languages are made to compress a lot of meaning into short syntax.
1) "Lite" programming - Previous languages and development environments seemed focused on exposing all the bells and whistles to the programmer. That meant huge learning curves too, as every developer was forced to learn huge lists of functions before writing useful code. This is a lot like my experience with old school Code Warrior from Metrowerks on the Mac (and some Programming the Macintosh Pascal books). Both Ruby/Rails and Arduino operate on a completely different principle, almost like "light" programming. You're given a few constructs first, into which you can make small tweaks that have significant affects on the behavior of the program, and only later - as you learn more - are you encouraged to learn more complex functions.
And now the differences:
5) Object orientation - This one's obvious, so I'll start out with it. Arduino Processing is based on Java, so it could use the object oriented methods like ::, embedded functions, objects, etc. But in general, those are confusing to learn for programming beginners, so it doesn't force them on you. Instead, it's based primarily on a linear functional programming style with functions calling other functions directly, not through objects. Ruby and Rails, on the other hand, is completely object oriented. So much so that at times it feels like it's getting a little carried away (maybe that's because I still miss the goto function from my BASIC days - ha).
4) Longevity - Ruby on Rails programs are forever (don't sue me, please, diamond company that rhymes with "endears"). Rails programs always run, and are meant to sit on servers somewhere churning away like workhorses. Arduino programs are more fleeting. Even the name, "sketch" implies a quickly written thingy that runs lightly, does one thing, for a period of time, and then gets replaced with another sketch. Arduino sketches are a bit like constantly evolving, dynamic modules.
3) Learning curves - On the Arduino, the learning curve is tightly managed by the Arduino founders. David Mellis and Tom Igoe frequently debate on the mailing lists and forums whether certain functions are worthy additions to the Arduino core language. The argument typically says (and I agree) that you leave the core language simple, strong, and generalizable. Then as guys master the base language, they can expand as they grow. So the first activity you do when you get an Arduino is download code and make LEDs blink. By comparison, on Rails, the API and programming metaphor *is* the language, and so you have to learn it first. Otherwise, you don't know where files are, where functions are supposed to go (is the function a data manipulation, data extraction, or visual presentation function?), or where to find things. While learning Rails, I spent 75% of my time just opening and closing files, saying to myself, "nope that function isn't in there, is in there, nope, oh there it is." So the first activity you do when you get Rails running is reading... books ... full of functions and block charts ... to understand where things are.
2) Programming path - The tech guys would call this "tool chain" but I always tend to think power tools, and that can be intimidating so I avoid anything that's named a tool chain (and instead opt for something like a beginners package). Arduino has a simple programming path; write code, click verify (compile or spit out errors), click download, done, led blinks, yey. By comparison, Ruby on Rails feels like a zoo. Gems, plugins, and migrations sometimes seem to fight with each other for metaphorical dominance during programming. Which ones are right? Which ones are primary? Script server to run but script generate to build? It's all very close together and tightly knit, so it can get a bit confusing.
1) Hardware / software stack - Rails is purely a web construct. It's 100% software that runs on other software, that sits in generic computer boxes. It's born as information, and remains information based for the rest of its useful life. By comparison, Arduino starts out as software, but then makes a jump to hardware. This allows physical computing to happen, because source code bits can now change real life physical stuff. To me, that's what makes Arduino so much more fulfilling, line-for-line, than Ruby on Rails.
So there you have it, my little reflection on 3 weeks of intense Ruby on Rails and Arduino Processing coding!
I've gotten several emails over the past few weeks, asking if I could post the source code to the programs I've written in a zip file format, since blogspot tends to mess up the ampersands, greater, and less than signs in my Arduino sketches when I just copy and paste. Despite my attempts to try to fix each snippet I post, some inevitably mess up, so I decided to take a whirl at learning Ruby on Rails and made an open source "app store" (sort of like Apple, but 100% not really). All the app source code snippets I've posted ever are GNU licensed open source, and are now zipped into little packages over here. I'll try to do this from now on, too! Anyway, doing this made me learn a lot about the language underpinnings of Rails.
It was an odd juxtaposition: I had a chance to write Ruby code for the website, and in between functions I'd make some more progress on my Processing on Arduino app. Flipping back and forth between Rails and Arduino Processing was actually harder than I thought...
What is Ruby on Rails?
- A script-based, runtime compiled, object oriented language called Ruby extended with a development framework called Rails
- It's used for a lot of websites these days because of how easy it is to manage prototype, deploy, manage backend changes, etc.
- It's lead users are all those spritely web coders running all over the place these days (and since everyone kept making such a big deal about it, I figured I'd try to learn it)
Arduino Processing
- A narrow subset of Java (close to C and C++) called Processing compiled to bytecode to run on an embedded machine, within a development framework called "Arduino"
- It's used for teaching electronics, creating art, making open gadgets and electronics
- It's lead users are all those guys that post furiously over at arduino.cc (and a bunch of fellow Italian guys!)
So, onto the list of similarities:
5) Isolation - Both languages and environments operate on the principle of isolation. That is, complexity in other parts of the environment are obscured when you're coding. In Rails, when you're writing a database model for one feature, you don't really care about or see the code for other database models. You just build the functionality you want there on the spot. In Arduino, you don't have to wrestle the complexity of the Atmega CPU, you just focus on the C functionality and hit compile.
4) Portability - Sketches written in Arduino Processing are typically just a single file, and only the most complex ones will be several files. That means that sharing code is as simple as a little copy and paste (though not onto a blog on blogspot, apparently). There's almost no configuration or customization necessary to go from one platform or computer to the next (only what serial port are you using). On Rails, pretty much the only thing you have to configure when porting an app from one computer to the next is the database.yml file (the one that stores your local database username and password). After that, it pretty much runs as configured, which is amazing considering all those sad, long nights in PHP world that I'll never get back :(
3) Universality - A few simple functions work everywhere, on anything. Arduino's print functions almost mirror the simplicity of the to_s() and related typecasters in Ruby. That way, you don't have to spend all your time worrying about data types and formats (yeck)
2) Code compression - On the Arduino, a 5 line program will get you up and running, blinking an LED, and that's it. On Rails, a 5 line edit to a data model could mean adding validations to every form on your entire website. So both languages are made to compress a lot of meaning into short syntax.
1) "Lite" programming - Previous languages and development environments seemed focused on exposing all the bells and whistles to the programmer. That meant huge learning curves too, as every developer was forced to learn huge lists of functions before writing useful code. This is a lot like my experience with old school Code Warrior from Metrowerks on the Mac (and some Programming the Macintosh Pascal books). Both Ruby/Rails and Arduino operate on a completely different principle, almost like "light" programming. You're given a few constructs first, into which you can make small tweaks that have significant affects on the behavior of the program, and only later - as you learn more - are you encouraged to learn more complex functions.
And now the differences:
5) Object orientation - This one's obvious, so I'll start out with it. Arduino Processing is based on Java, so it could use the object oriented methods like ::, embedded functions, objects, etc. But in general, those are confusing to learn for programming beginners, so it doesn't force them on you. Instead, it's based primarily on a linear functional programming style with functions calling other functions directly, not through objects. Ruby and Rails, on the other hand, is completely object oriented. So much so that at times it feels like it's getting a little carried away (maybe that's because I still miss the goto function from my BASIC days - ha).
4) Longevity - Ruby on Rails programs are forever (don't sue me, please, diamond company that rhymes with "endears"). Rails programs always run, and are meant to sit on servers somewhere churning away like workhorses. Arduino programs are more fleeting. Even the name, "sketch" implies a quickly written thingy that runs lightly, does one thing, for a period of time, and then gets replaced with another sketch. Arduino sketches are a bit like constantly evolving, dynamic modules.
3) Learning curves - On the Arduino, the learning curve is tightly managed by the Arduino founders. David Mellis and Tom Igoe frequently debate on the mailing lists and forums whether certain functions are worthy additions to the Arduino core language. The argument typically says (and I agree) that you leave the core language simple, strong, and generalizable. Then as guys master the base language, they can expand as they grow. So the first activity you do when you get an Arduino is download code and make LEDs blink. By comparison, on Rails, the API and programming metaphor *is* the language, and so you have to learn it first. Otherwise, you don't know where files are, where functions are supposed to go (is the function a data manipulation, data extraction, or visual presentation function?), or where to find things. While learning Rails, I spent 75% of my time just opening and closing files, saying to myself, "nope that function isn't in there, is in there, nope, oh there it is." So the first activity you do when you get Rails running is reading... books ... full of functions and block charts ... to understand where things are.
2) Programming path - The tech guys would call this "tool chain" but I always tend to think power tools, and that can be intimidating so I avoid anything that's named a tool chain (and instead opt for something like a beginners package). Arduino has a simple programming path; write code, click verify (compile or spit out errors), click download, done, led blinks, yey. By comparison, Ruby on Rails feels like a zoo. Gems, plugins, and migrations sometimes seem to fight with each other for metaphorical dominance during programming. Which ones are right? Which ones are primary? Script server to run but script generate to build? It's all very close together and tightly knit, so it can get a bit confusing.
1) Hardware / software stack - Rails is purely a web construct. It's 100% software that runs on other software, that sits in generic computer boxes. It's born as information, and remains information based for the rest of its useful life. By comparison, Arduino starts out as software, but then makes a jump to hardware. This allows physical computing to happen, because source code bits can now change real life physical stuff. To me, that's what makes Arduino so much more fulfilling, line-for-line, than Ruby on Rails.
So there you have it, my little reflection on 3 weeks of intense Ruby on Rails and Arduino Processing coding!
Labels:
Liquidware
Friday, December 5, 2008
Atmel's Clever Pin Register
When browsing through the datasheets of the ATmega processors, most of the time my eyes just glaze over this diagram. I never really put much thought into it.

But zooming in, you'll notice a special feature of the Atmel's Pin register...
First, you start by finding the PORT flip-flop which is the PORTxn symbol directly above the RESET signal in the diagram above. Notice that it's output is on the left and it's flipped and fed back into itself on the right?
That's not really that exciting, right?
Wrong! Because if you write a 1 to the Pin register WPx (input to the AND gate), you'll be able to toggle the output state of the port!
So why is this interesting? It's interesting because you can now toggle the I/O pins at blazing fast, single instruction speeds :-)
The code to toggle PORTB 7 might look something like this:
DDRB = 0b10000000;
PINB = (1 << 7);
Chris

But zooming in, you'll notice a special feature of the Atmel's Pin register...

First, you start by finding the PORT flip-flop which is the PORTxn symbol directly above the RESET signal in the diagram above. Notice that it's output is on the left and it's flipped and fed back into itself on the right?
That's not really that exciting, right?
Wrong! Because if you write a 1 to the Pin register WPx (input to the AND gate), you'll be able to toggle the output state of the port!
So why is this interesting? It's interesting because you can now toggle the I/O pins at blazing fast, single instruction speeds :-)
The code to toggle PORTB 7 might look something like this:
DDRB = 0b10000000;
PINB = (1 << 7);
Chris
Labels:
Liquidware
Thursday, December 4, 2008
Passing large values between the Arduino to the TouchShield
(I've gotten a couple of questions about this, especially since I posted the Processing on a TouchShield post, so here's a little tutorial on how to pass large values, like integers between the Arduino and TouchShield ... it's a slightly modified version of what I posted on the arduino.cc forum.)
Communicating from the Arduino to the TouchShield is a bit of a manual process, largely because there are so many different ways someone might want to communicate that it's tough to plan for all of them ahead of time. It's easy to pass unsigned chars one at a time, because the serial.read() function grabs one char at a time, which is one byte. The catch is that integers (ints) are 2 bytes long, so if you try to just use serial.print() and serial.read(), it only sends one byte, or 8 bits, and then you lose the other part of your number!
So in order to send a full int from the arduino, you have to send each byte of the 2-byte integer separately, and then reconstruct it back into the full two-byte value. Chris figured out how to get this working in the Pin Visualizer project, and I've adapted it for the Processing graphics library code too.
On the TouchShield, I use this code:
int getValue = Serial.read();
getValue = (getValue < < 8) + Serial.read();
This first calls Serial.read() to get the high bit. The " < < 8" means bit shift the byte up (to the left) 8 bits. Then, it calls Serial.read() again to get the low byte. And finally it adds both together. It kind of looks like this:
First get byte 1, the high byte:
0000000010101010
Shift it left 8 bits
1010101000000000
Then get byte 2, the low byte:
11111111
Add that to the left-shifted byte:
1010101011111111
And on the Arduino, I'll use this code:
unsigned char lowByte, highByte;
unsigned int val;
//set val to something
lowByte = (unsigned char)val;
highByte = (unsigned char)(val > > 8);
mySerial.print(highByte);
delay(1);
mySerial.print(lowByte);
delay(1);
That kind of does the inverse behavior. First it take val, and sets lowByte to only the lower or rightmost 8 bits. Then, it sets highByte to the upper or leftmost 8 bits (by bitshifting it down 8 bits first). Then, it prints the high byte, followed by the low byte. I throw a delay(1) in between just to give the Arduino and TouchShield time to separate the two sends from each other.
So if val looks like:
1010101011111111
It sets lowByte to:
11111111
It then shifts val to the right by 8 bits to get:
0000000010101010
Which it then grabs only the lower 8 bits of:
10101010
Which get stored as highByte
Because I send highByte first, and the send lowByte, that means the TouchShield has to know that the first thing it gets will be the highByte. So that's why the first byte the TouchShield gets is shifted left by 8 bits... the "circle of life" is now complete :-)
Phew. That was really long... On the plus side, this also happens to be a convenient way to pass large values between two Arduinos over a two-wire Rx/Tx serial connection, or between the Arduino and a custom program on the PC. I know they tend not to be used in too many apps or sketches, but bit shifts really do come in handy sometimes. And if you still want some more help, just send me some code to look at, and I'll try my best!
Communicating from the Arduino to the TouchShield is a bit of a manual process, largely because there are so many different ways someone might want to communicate that it's tough to plan for all of them ahead of time. It's easy to pass unsigned chars one at a time, because the serial.read() function grabs one char at a time, which is one byte. The catch is that integers (ints) are 2 bytes long, so if you try to just use serial.print() and serial.read(), it only sends one byte, or 8 bits, and then you lose the other part of your number!
So in order to send a full int from the arduino, you have to send each byte of the 2-byte integer separately, and then reconstruct it back into the full two-byte value. Chris figured out how to get this working in the Pin Visualizer project, and I've adapted it for the Processing graphics library code too.
On the TouchShield, I use this code:
int getValue = Serial.read();
getValue = (getValue < < 8) + Serial.read();
This first calls Serial.read() to get the high bit. The " < < 8" means bit shift the byte up (to the left) 8 bits. Then, it calls Serial.read() again to get the low byte. And finally it adds both together. It kind of looks like this:
First get byte 1, the high byte:
0000000010101010
Shift it left 8 bits
1010101000000000
Then get byte 2, the low byte:
11111111
Add that to the left-shifted byte:
1010101011111111
And on the Arduino, I'll use this code:
unsigned char lowByte, highByte;
unsigned int val;
//set val to something
lowByte = (unsigned char)val;
highByte = (unsigned char)(val > > 8);
mySerial.print(highByte);
delay(1);
mySerial.print(lowByte);
delay(1);
That kind of does the inverse behavior. First it take val, and sets lowByte to only the lower or rightmost 8 bits. Then, it sets highByte to the upper or leftmost 8 bits (by bitshifting it down 8 bits first). Then, it prints the high byte, followed by the low byte. I throw a delay(1) in between just to give the Arduino and TouchShield time to separate the two sends from each other.
So if val looks like:
1010101011111111
It sets lowByte to:
11111111
It then shifts val to the right by 8 bits to get:
0000000010101010
Which it then grabs only the lower 8 bits of:
10101010
Which get stored as highByte
Because I send highByte first, and the send lowByte, that means the TouchShield has to know that the first thing it gets will be the highByte. So that's why the first byte the TouchShield gets is shifted left by 8 bits... the "circle of life" is now complete :-)
Phew. That was really long... On the plus side, this also happens to be a convenient way to pass large values between two Arduinos over a two-wire Rx/Tx serial connection, or between the Arduino and a custom program on the PC. I know they tend not to be used in too many apps or sketches, but bit shifts really do come in handy sometimes. And if you still want some more help, just send me some code to look at, and I'll try my best!
Labels:
Liquidware
Wednesday, December 3, 2008
What is Open Source Hardware, really? Part 2 and the CoreBoard
Somehow it didn't feel right to spend all that time thinking about Open Source over the last few days, only to make another file using Microsoft's very, very proprietary Powerpoint file and format :(
Anyway, thanks Limor (p.s. can I come over and use your laser etcher?!) and especially Phil for the ideas and comments (they've definitely thought long and hard about this). So I spent some time last night and today reading up on the huge threads over at OpenCollector, Slashdot and Opencores.org, where there are some really interesting ideas too. I tried to summarize everything I read, and some of my thoughts as well into "What is Open Source Hardware - Part 2".
Incidentally, it's funny that folks don't feel comfortable writing comments on a blog, and prefer to send emails instead, but whatever works :) I think I'm the same way on other blogs too...
Also, since I thought it was a good example of the licensing issues, I figured I might as well talk about my CoreBoard project. It was originally something I just built for myself, and I was kind of embarassed to release it because it technically doesn't work with the Arduino IDE (instead, you have to use either something from here, or from here on Linux).



It's a little Basic STAMP carrier board that converts all of my old STAMPS that I had lying around from the pre-Arduino days. It's shaped just like an Arduino, but colored black, and it has a little ZIF socket in the middle that's perfectly shaped for all kinds of 24-pin STAMP varieties floating around out there (like ARM, Java, or PIC-based ones). I also pinned out all of the Basic Stamp's I/O to the Arduino female pin header rows, so writing code for it wouldn't be too hard. I wanted to be able to use the shields like the TouchShield or wave shield with them.

Here's some open source code to make the CoreBoard blink LED 15 - I'm releasing this code snippet under the GNU GPL license :-)
' {$STAMP BS2e}
' {$PBASIC 2.5}
' {$PORT COM21}
LED PIN 15
IsOn CON 0
IsOff CON 1
Setup:
OUTPUT LED
Main:
DO
LED = IsOn
PAUSE 500
LED = IsOff
PAUSE 500
LOOP
I've release all the schematics, diagrams, bill-of-materials, parts list, and gerbers under the Creative Commons license so have fun ... And now that I've written a blog article about it, I've also thrown it over at liquidware.com. If you buy one, I'll assemble and solder it for you!
Anyway, thanks Limor (p.s. can I come over and use your laser etcher?!) and especially Phil for the ideas and comments (they've definitely thought long and hard about this). So I spent some time last night and today reading up on the huge threads over at OpenCollector, Slashdot and Opencores.org, where there are some really interesting ideas too. I tried to summarize everything I read, and some of my thoughts as well into "What is Open Source Hardware - Part 2".
Incidentally, it's funny that folks don't feel comfortable writing comments on a blog, and prefer to send emails instead, but whatever works :) I think I'm the same way on other blogs too...
Also, since I thought it was a good example of the licensing issues, I figured I might as well talk about my CoreBoard project. It was originally something I just built for myself, and I was kind of embarassed to release it because it technically doesn't work with the Arduino IDE (instead, you have to use either something from here, or from here on Linux).



It's a little Basic STAMP carrier board that converts all of my old STAMPS that I had lying around from the pre-Arduino days. It's shaped just like an Arduino, but colored black, and it has a little ZIF socket in the middle that's perfectly shaped for all kinds of 24-pin STAMP varieties floating around out there (like ARM, Java, or PIC-based ones). I also pinned out all of the Basic Stamp's I/O to the Arduino female pin header rows, so writing code for it wouldn't be too hard. I wanted to be able to use the shields like the TouchShield or wave shield with them.

Here's some open source code to make the CoreBoard blink LED 15 - I'm releasing this code snippet under the GNU GPL license :-)
' {$STAMP BS2e}
' {$PBASIC 2.5}
' {$PORT COM21}
LED PIN 15
IsOn CON 0
IsOff CON 1
Setup:
OUTPUT LED
Main:
DO
LED = IsOn
PAUSE 500
LED = IsOff
PAUSE 500
LOOP
I've release all the schematics, diagrams, bill-of-materials, parts list, and gerbers under the Creative Commons license so have fun ... And now that I've written a blog article about it, I've also thrown it over at liquidware.com. If you buy one, I'll assemble and solder it for you!
Labels:
Liquidware
Monday, December 1, 2008
Processing ported to an Arduino + TouchShield ported from Processing
This is a little project I just finished working on over the past few weeks, called project "P-A-P-A", which stands for: "Processing-Ported to-Arduino-Running Processing on an-Arduino". It's something of a recursive project, since the Arduino was originally based on a subset of the Processing Graphics language, and can now display a subset of Processing functions through sketches that interact with through a TouchShield. It's not the most heavily optimized code I've ever written, but that's only because I was focused more on just getting it to work, figuring I could go back later and optimize it.

Since I've only ported a subset of the language, I'm calling this the informal "Subprocessing" port of Processing. I'll set up a small website soon to document all of the updates and changes, but for now, my mini-port implements the following functions:
fill()
quad()
ellipse()
rect()
dist()
stroke()
triangle()
line()
point()
mouseX and mouseY
width and height
...as well as some temporary functions that are waiting for full porting to Processing, including:
setbrightness()
gettouch()
clearscreen()
setbcolor()
setfcolor()
This means that you can run almost all of the basic shapes examples in the book, Processing by Casey Reas and Ben Fry (with a little bit of work to make sure the shapes are drawn within the correct screen bounds, since the TouchShield isn't good at handling overflow). As an aside, I've read most of the book now, and I highly recommend it if you're new to Processing, or just curious!
This is a video showing my port of Processing to the TouchShield, so it can be used on an Arduino to run processing graphics programs. I think the coolest part is having different sketches running on different Arduino's, so all I had to do was plug in the TouchShield from one to the next, and the programs automatically updated:
And here's a closeup video of the TouchShield + Arduino + Lithium Backpack running the same sketch as John Resig made over at his website. It was definitely inspirational reading through some of his code to see all the hoops he jumped through to get it working!
Finally, I uploaded some other pictures I took to Flickr.



Anyway, enjoy the recursion! As always, here's the Open Source software and API for the Arduino:
//Set up the serial communications channel between the Arduino and the TouchShield - thanks LadyAda!
#include
#define RXPIN 3
#define TXPIN 2
AFSoftSerial mySerial = AFSoftSerial(RXPIN, TXPIN);
//This is the beginnings of the "Sub-Processing" for TouchShield library
//Version 0.1
//by inthebitz @ antipastohw.blogspot.com & liquidware.com
//updated on nov 30, 2008
#define SCREENX 128
#define SCREENY 128
#define WAIT 10
void sendString( char *buf) {
int i, size; size = strlen(buf);
for (i = 0;i < i =" 0;i" mousex =" SCREENX" mousey =" SCREENY" width =" SCREENX;" height =" SCREENY;" len =" strlen(command);">> 8); command[4]=0;
command[5]=0;command[6]=0;command[7]=0;command[8]=0;
command[9]='~';command[10]=0;
sendStringL(command,11);
delay(200+time*10); //wait for the touchshield to fade
}
void fadein( int time) {
command[0]='|'; command[1]=6;
command[2]=(unsigned char)time; command[3]=(unsigned char)(time >> 8); command[4]=0;
command[5]=0;command[6]=0;command[7]=0;command[8]=0;
command[9]='~';command[10]=0;
sendStringL(command,11);
delay(200+time*10); //wait for the touchshield to fade
}
void point( int x, int y) {
command[0]='|'; command[1]=7;
command[2]=(unsigned char)x; command[3]=(unsigned char)(x >> 8); command[4]=(unsigned char)y;
command[5]=(unsigned char)(y >> 8);command[6]=0;command[7]=0;command[8]=0;
command[9]='~';command[10]=0;
sendStringL(command,11);
delay(WAIT);
}
void drawcircle( int x, int y, int r) {
command[0]='|'; command[1]=8;
command[2]=(unsigned char)x; command[3]=(unsigned char)(x >> 8); command[4]=(unsigned char)y;
command[5]=(unsigned char)(y >> 8);command[6]=(unsigned char)r;command[7]=(unsigned char)(r >> 8);command[8]=0;
command[9]='~';command[10]=0;
sendStringL(command,11);
delay(WAIT);
}
void drawrect( int x1, int y1, int x2, int y2) {
command[0]='|'; command[1]=9;
command[2]=(unsigned char)x1; command[3]=(unsigned char)(x1 >> 8); command[4]=(unsigned char)y1;
command[5]=(unsigned char)(y1 >> 8);command[6]=(unsigned char)x2;command[7]=(unsigned char)(x2 >> 8);
command[8]=(unsigned char)y2;command[9]=(unsigned char)(y2 >> 8);
command[10]='~';command[11]=0;
sendStringL(command,12);
delay(WAIT);
}
void line( int x1, int y1, int x2, int y2) {
command[0]='|'; command[1]=10;
command[2]=(unsigned char)x1; command[3]=(unsigned char)(x1 >> 8); command[4]=(unsigned char)y1;
command[5]=(unsigned char)(y1 >> 8);command[6]=(unsigned char)x2;command[7]=(unsigned char)(x2 >> 8);
command[8]=(unsigned char)y2;command[9]=(unsigned char)(y2 >> 8);
command[10]='~';command[11]=0;
sendStringL(command,12);
delay(WAIT);
}
void drawchar( int x, int y, char text) {
command[0]='|'; command[1]=11;
command[2]=(unsigned char)x; command[3]=(unsigned char)(x >> 8); command[4]=(unsigned char)y;
command[5]=(unsigned char)(y >> 8);command[6]=text;command[7]=0;command[8]=0;
command[9]='~';command[10]=0;
sendStringL(command,11);
delay(WAIT);
}
void drawstring( int x, int y, char *text) {
int len;
command[0]='|'; command[1]=12;
command[2]=(unsigned char)x; command[3]=(unsigned char)(x >> 8); command[4]=(unsigned char)y;
command[5]=(unsigned char)(y >> 8);command[6]=0;command[7]=0;command[8]=0;
strcpy ( &command[9], text);
len = strlen(text);
sendStringL(command,9+len);//10 is where the zero is
delay(WAIT+len*15);
}
void triangle( int x1, int y1, int x2, int y2, int x3, int y3) {
command[0]='|'; command[1]=15;
command[2]=(unsigned char)x1; command[3]=(unsigned char)(x1 >> 8); command[4]=(unsigned char)y1;
command[5]=(unsigned char)(y1 >> 8);command[6]=(unsigned char)x2;command[7]=(unsigned char)(x2 >> 8);
command[8]=(unsigned char)y2;command[9]=(unsigned char)(y2 >> 8);
command[10]='~';command[11]=0;
sendStringL(command,12);
delay(WAIT+100);
command[0]='|'; command[1]=16;
command[2]=(unsigned char)x3; command[3]=(unsigned char)(x3 >> 8); command[4]=(unsigned char)y3;
command[5]=(unsigned char)(y3 >> 8);command[6]=0;command[7]=0;
command[8]=0;command[9]=0;
command[10]='~';command[11]=0;
sendStringL(command,12);
delay(WAIT+300);
}
void clearscreen( void) {
setbcolor( 0, 0, 0);fillback();
}
void background( int b) {
setbcolor( b, b, b);fillback();
}
void stroke( int s) {
setfcolor( s, s, s);
}
void stroke( int r, int g, int b) {
setfcolor( r, g, b);
}
void gettouch( void) {
command[0]='|'; command[1]=13;
command[2]=0; command[3]=0; command[4]=0;
command[5]=0;command[6]=0;command[7]=0;command[8]=0;
command[9]='~';command[10]=0;
sendStringL(command,11);
delay(WAIT);
delay(10);
mySerial.read();
mouseX = mySerial.read();
mouseY = mySerial.read();
if (mouseX < mousex =" 1;"> SCREENX) mouseX = SCREENX;
if (mouseY < mousey =" 1;"> SCREENY) mouseY = SCREENY;
}
float dist(float x1, float y1, float x2, float y2) {
return sqrt(sq(x2-x1)+sq(y2-y1));
}
void rect (int x, int y, int width, int height) {
drawrect(x, y, x+width, y+height);
}
void quad( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) {
triangle(x1, y1, x2, y2, x3, y3);
delay(1000);
triangle(x2, y2, x3, y3, x4, y4);
delay(1000);
triangle(x1, y1, x3, y3, x4, y4);
delay(1000);
}
void fill( int f) {
setfcolor(f,f,f);
setbcolor(f,f,f);
}
void ellipse( int x, int y, int radx, int rady) {
if (radx == rady) {
drawcircle( x, y, radx);
} else {
command[0]='|'; command[1]=14;
command[2]=(unsigned char)x; command[3]=(unsigned char)(x >> 8); command[4]=(unsigned char)y;
command[5]=(unsigned char)(y >> 8);command[6]=(unsigned char)radx;command[7]=(unsigned char)(radx >> 8);
command[8]=(unsigned char)rady;command[9]=(unsigned char)(rady >> 8);
command[10]='~';command[11]=0;
sendStringL(command,12);
delay(WAIT+100);
}
}
void setup() {
mySerial.begin(9600);
Serial.begin(9600);
//delay(2000);
}
//http://ejohn.org/apps/processing.js/examples/basic/distance2d.html
float max_distance;
int oldx, oldy;
void loopo () {
int a = 0;
setbcolor( 128, 255, 57);
delay(a);
fillback();
delay(a);
setbcolor( 0, 0, 0);
delay(a);
fillback();
delay(a);
//setbcolor( 255, 255, 255);
drawchar(50,50,'X');
drawstring(50,70,"asdf hello");
delay(a);
setbcolor( 0, 0, 255);
fillback();
delay(a);
}
void loop () {
gettouch();
oldx = mouseX;
oldy = mouseY;
max_distance = dist(0, 0, width, height);
setbrightness( 10);
setbcolor( 0, 0, 0);fillback();
draw();
while (1) {
gettouch();
if ((mouseX != oldx) || (mouseY != oldy)) {
oldx = mouseX;
oldy = mouseY;
clearscreen();
setbcolor( 255, 255, 255);
setfcolor( 255, 255, 255);
draw();
}
}
}
void draw( void) {
float size;
//background(51);
for(int i = 0; i <= width; i += 20) { for(int j = 0; j <= width; j += 20) { float size = dist(mouseX, mouseY, i, j); size = size/max_distance * 33; ellipse(i, j, size, size); } } }
And here's the source code for the TouchShield:
#include
COLOR fcolor = { 0, 0, 0 };
COLOR bcolor = { 0, 0, 0 };
COLOR green = { 0, 255, 0 };
COLOR blue = {0,0,255};
COLOR yellow = {255,255,0};
COLOR grey = {0x77,0x77,0x77};
COLOR red = {255,0,0};
COLOR black = {0,0,0};
COLOR white = {255,255,255};
char buf[32];
char tmp[32];
int brightness=5;
POINT my_point;
int trix1, triy1, trix2, triy2, trix3, triy3;
void setup() {
Serial.begin(9600);
lcd_setBrightness(brightness);
lcd_clearScreen(white);
}
void GetString(char *buf, int bufsize)
{
int i;
for (i=0; i9) break;}; // is it the terminator byte?
}
buf[i] = 0; // 0 string terminator just in case
}
void loop() {
int cptr, x1, y1, x2, y2, r, r2, timer;
GetString(buf, sizeof(buf));
delay(10);
if (touch_get_cursor(&my_point)) {
}
if (buf[0] == '|') {
cptr = 1;
switch (buf[cptr]) {
case 1:
fcolor.red = buf[cptr+1];
fcolor.green = buf[cptr+2];
fcolor.blue = buf[cptr+3];
break;
case 2:
bcolor.red = buf[cptr+1];
bcolor.green = buf[cptr+2];
bcolor.blue = buf[cptr+3];
break;
case 3:
lcd_clearScreen(bcolor);
break;
case 4:
lcd_setBrightness(buf[cptr+1]);
brightness = buf[cptr+1];
break;
case 5:
timer = (buf[cptr+2] << i =" brightness;">0; i--) {
lcd_setBrightness(i);
delay(timer);
}
CLRBIT(PORTE, PE3);
break;
case 6:
timer = (buf[cptr+2] << i =" 0;" x1 =" (buf[cptr+2]" y1 =" (buf[cptr+4]" x1 =" (buf[cptr+2]" y1 =" (buf[cptr+4]" r =" (buf[cptr+6]" x1 =" (buf[cptr+2]" y1 =" (buf[cptr+4]" x2 =" (buf[cptr+6]" y2 =" (buf[cptr+8]" x1 =" (buf[cptr+2]" y1 =" (buf[cptr+4]" x2 =" (buf[cptr+6]" y2 =" (buf[cptr+8]" x1 =" (buf[cptr+2]" y1 =" (buf[cptr+4]" x1 =" (buf[cptr+2]" y1 =" (buf[cptr+4]" x1 =" (buf[cptr+2]" y1 =" (buf[cptr+4]" r =" (buf[cptr+6]" r2 =" (buf[cptr+8]" trix1 =" (buf[cptr+2]" triy1 =" (buf[cptr+4]" trix2 =" (buf[cptr+6]" triy2 =" (buf[cptr+8]" trix3 =" (buf[cptr+2]" triy3 =" (buf[cptr+4]" mycolor =" {255," red =" fill.red;mycolor.green" blue =" fill.blue;" red =" outline.red;mycolor.green" blue =" outline.blue;" x =" 0," y =" b;" a2 =" (long)a*a," b2 =" (long)b*b;" crit1 =" -(a2/4" crit2 =" -(b2/4" crit3 =" -(b2/4" t =" -a2*y;" dxt =" 2*b2*x," dyt =" -2*a2*y;" d2xt =" 2*b2," d2yt =" 2*a2;">=0 && x<=a) { lcd_pixel(xc+x, yc+y, mycolor); if (x!=0 || y!=0) lcd_pixel(xc-x, yc-y, mycolor); if (x!=0 && y!=0) { lcd_pixel(xc+x, yc-y, mycolor); lcd_pixel(xc-x, yc+y, mycolor); } if (t + b2*x <= crit1 || /* e(x+1,y-1/2) <= 0 */ t + a2*y <= crit3) /* e(x+1/2,y) <= 0 */ incx(); else if (t - a2*y > crit2) /* e(x+1/2,y-1) > 0 */
incy();
else {
incx();
incy();
}
}
}
void dispFillEllipse(int xc, int yc, int a, int b)
{ /* e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 */
int x = 0, y = b;
unsigned int width = 1;
long a2 = (long)a*a, b2 = (long)b*b;
long crit1 = -(a2/4 + a%2 + b2);
long crit2 = -(b2/4 + b%2 + a2);
long crit3 = -(b2/4 + b%2);
long t = -a2*y; /* e(x+1/2,y-1/2) - (a^2+b^2)/4 */
long dxt = 2*b2*x, dyt = -2*a2*y;
long d2xt = 2*b2, d2yt = 2*a2;
while (y>=0 && x<=a) { if (t + b2*x <= crit1 || /* e(x+1,y-1/2) <= 0 */ t + a2*y <= crit3) { /* e(x+1/2,y) <= 0 */ incx(); width += 2; } else if (t - a2*y > crit2) { /* e(x+1/2,y-1) > 0 */
//dispRectangle(xc-x, yc-y, width,1);
lcd_rectangle(xc-x, yc-y, xc-x+width, yc-y+1, mycolor, mycolor);
if (y!=0)
//dispRectangle(xc-x, yc+y, width,1);
lcd_rectangle(xc-x, yc+y, xc-x+width, yc+y+1, mycolor, mycolor);
incy();
}
else {
//dispRectangle(xc-x, yc-y, width,1);
lcd_rectangle(xc-x, yc-y, xc-x+width, yc-y+1, mycolor, mycolor);
if (y!=0)
//dispRectangle(xc-x, yc+y, width,1);
lcd_rectangle(xc-x, yc+y, xc-x+width, yc+y+1, mycolor, mycolor);
incx();
incy();
width += 2;
}
}
if (b == 0)
//dispRectangle(xc-a, yc, 2*a+1,1);
lcd_rectangle(xc-a, yc, xc-a+2*a+1, yc+1, mycolor, mycolor);
}
//There's definitely an easier way to do this, but for now I'll use some help from:
//http://www.codeproject.com/KB/GDI/antialias.aspx#dwuln
//Edited by inthebitz
void DrawWuLine ( short X0, short Y0, short X1, short Y1, COLOR linecolor )
{
unsigned short IntensityShift, ErrorAdj, ErrorAcc;
unsigned short ErrorAccTemp, Weighting, WeightingComplementMask;
short DeltaX, DeltaY, Temp, XDir;
short BaseColor = 0;
short NumLevels = 2;
unsigned short IntensityBits = 2;
/* Make sure the line runs top to bottom */
if (Y0 > Y1) {
Temp = Y0; Y0 = Y1; Y1 = Temp;
Temp = X0; X0 = X1; X1 = Temp;
}
/* Draw the initial pixel, which is always exactly intersected by
the line and so needs no weighting */
lcd_pixel(X0, Y0, linecolor);
if ((DeltaX = X1 - X0) >= 0) {
XDir = 1;
} else {
XDir = -1;
DeltaX = -DeltaX; /* make DeltaX positive */
}
/* Special-case horizontal, vertical, and diagonal lines, which
require no weighting because they go right through the center of
every pixel */
if ((DeltaY = Y1 - Y0) == 0) {
/* Horizontal line */
while (DeltaX-- != 0) {
X0 += XDir;
lcd_pixel(X0, Y0, linecolor);
}
return;
}
if (DeltaX == 0) {
/* Vertical line */
do {
Y0++;
lcd_pixel(X0, Y0, linecolor);
} while (--DeltaY != 0);
return;
}
if (DeltaX == DeltaY) {
/* Diagonal line */
do {
X0 += XDir;
Y0++;
lcd_pixel(X0, Y0, linecolor);
} while (--DeltaY != 0);
return;
}
/* Line is not horizontal, diagonal, or vertical */
ErrorAcc = 0; /* initialize the line error accumulator to 0 */
/* # of bits by which to shift ErrorAcc to get intensity level */
IntensityShift = 16 - IntensityBits;
/* Mask used to flip all bits in an intensity weighting, producing the
result (1 - intensity weighting) */
WeightingComplementMask = NumLevels - 1;
/* Is this an X-major or Y-major line? */
if (DeltaY > DeltaX) {
/* Y-major line; calculate 16-bit fixed-point fractional part of a
pixel that X advances each time Y advances 1 pixel, truncating the
result so that we won't overrun the endpoint along the X axis */
ErrorAdj = ((unsigned long) DeltaX << erroracctemp =" ErrorAcc;" weighting =" ErrorAcc">> IntensityShift;
//////////////////////////////////////////////////////
lcd_pixel(X0, Y0, linecolor);
//lcd_pixel(X0 + XDir, Y0, mycolora);
//lcd_pixel(X0, Y0, BaseColor + Weighting);
//lcd_pixel(X0 + XDir, Y0,
// BaseColor + (Weighting ^ WeightingComplementMask));
}
/* Draw the final pixel, which is
always exactly intersected by the line
and so needs no weighting */
lcd_pixel(X1, Y1, linecolor);
return;
}
/* It's an X-major line; calculate 16-bit fixed-point fractional part of a
pixel that Y advances each time X advances 1 pixel, truncating the
result to avoid overrunning the endpoint along the X axis */
ErrorAdj = ((unsigned long) DeltaY << erroracctemp =" ErrorAcc;" weighting =" ErrorAcc">> IntensityShift;
///////////////////////////////////////////////////
lcd_pixel(X0, Y0, linecolor);
//lcd_pixel(X0, Y0 + 1, linecolor);
//lcd_pixel(X0, Y0, BaseColor + Weighting);
//lcd_pixel(X0, Y0 + 1,
// BaseColor + (Weighting ^ WeightingComplementMask));
}
/* Draw the final pixel, which is always exactly intersected by the line
and so needs no weighting */
lcd_pixel(X1, Y1, linecolor);
}
//http://www.swissdelphicenter.ch/en/showcode.php?id=2400
//http://tog.acm.org/GraphicsGems/gemsiii/triangleCube.c
//I'm sure there's a more elegant and cleaner way, but with help from the links above I was able to cludge
//this together, so that it at least works!
#define MIN3(a,b,c) ((((a)<(b))&&((a)<(c))) ? (a) : (((b)<(c)) ? (b) : (c))) #define MAX3(a,b,c) ((((a)>(b))&&((a)>(c))) ? (a) : (((b)>(c)) ? (b) : (c)))
void triangle ( int x1, int y1, int x2, int y2, int x3, int y3, COLOR tcolor, COLOR ocolor) {
for (int x=MIN3(x1, x2, x3); x 0) {
return 1;
} else if (orin <>

Since I've only ported a subset of the language, I'm calling this the informal "Subprocessing" port of Processing. I'll set up a small website soon to document all of the updates and changes, but for now, my mini-port implements the following functions:
fill()
quad()
ellipse()
rect()
dist()
stroke()
triangle()
line()
point()
mouseX and mouseY
width and height
...as well as some temporary functions that are waiting for full porting to Processing, including:
setbrightness()
gettouch()
clearscreen()
setbcolor()
setfcolor()
This means that you can run almost all of the basic shapes examples in the book, Processing by Casey Reas and Ben Fry (with a little bit of work to make sure the shapes are drawn within the correct screen bounds, since the TouchShield isn't good at handling overflow). As an aside, I've read most of the book now, and I highly recommend it if you're new to Processing, or just curious!
This is a video showing my port of Processing to the TouchShield, so it can be used on an Arduino to run processing graphics programs. I think the coolest part is having different sketches running on different Arduino's, so all I had to do was plug in the TouchShield from one to the next, and the programs automatically updated:
And here's a closeup video of the TouchShield + Arduino + Lithium Backpack running the same sketch as John Resig made over at his website. It was definitely inspirational reading through some of his code to see all the hoops he jumped through to get it working!
Finally, I uploaded some other pictures I took to Flickr.



Anyway, enjoy the recursion! As always, here's the Open Source software and API for the Arduino:
//Set up the serial communications channel between the Arduino and the TouchShield - thanks LadyAda!
#include
#define RXPIN 3
#define TXPIN 2
AFSoftSerial mySerial = AFSoftSerial(RXPIN, TXPIN);
//This is the beginnings of the "Sub-Processing" for TouchShield library
//Version 0.1
//by inthebitz @ antipastohw.blogspot.com & liquidware.com
//updated on nov 30, 2008
#define SCREENX 128
#define SCREENY 128
#define WAIT 10
void sendString( char *buf) {
int i, size; size = strlen(buf);
for (i = 0;i < i =" 0;i" mousex =" SCREENX" mousey =" SCREENY" width =" SCREENX;" height =" SCREENY;" len =" strlen(command);">> 8); command[4]=0;
command[5]=0;command[6]=0;command[7]=0;command[8]=0;
command[9]='~';command[10]=0;
sendStringL(command,11);
delay(200+time*10); //wait for the touchshield to fade
}
void fadein( int time) {
command[0]='|'; command[1]=6;
command[2]=(unsigned char)time; command[3]=(unsigned char)(time >> 8); command[4]=0;
command[5]=0;command[6]=0;command[7]=0;command[8]=0;
command[9]='~';command[10]=0;
sendStringL(command,11);
delay(200+time*10); //wait for the touchshield to fade
}
void point( int x, int y) {
command[0]='|'; command[1]=7;
command[2]=(unsigned char)x; command[3]=(unsigned char)(x >> 8); command[4]=(unsigned char)y;
command[5]=(unsigned char)(y >> 8);command[6]=0;command[7]=0;command[8]=0;
command[9]='~';command[10]=0;
sendStringL(command,11);
delay(WAIT);
}
void drawcircle( int x, int y, int r) {
command[0]='|'; command[1]=8;
command[2]=(unsigned char)x; command[3]=(unsigned char)(x >> 8); command[4]=(unsigned char)y;
command[5]=(unsigned char)(y >> 8);command[6]=(unsigned char)r;command[7]=(unsigned char)(r >> 8);command[8]=0;
command[9]='~';command[10]=0;
sendStringL(command,11);
delay(WAIT);
}
void drawrect( int x1, int y1, int x2, int y2) {
command[0]='|'; command[1]=9;
command[2]=(unsigned char)x1; command[3]=(unsigned char)(x1 >> 8); command[4]=(unsigned char)y1;
command[5]=(unsigned char)(y1 >> 8);command[6]=(unsigned char)x2;command[7]=(unsigned char)(x2 >> 8);
command[8]=(unsigned char)y2;command[9]=(unsigned char)(y2 >> 8);
command[10]='~';command[11]=0;
sendStringL(command,12);
delay(WAIT);
}
void line( int x1, int y1, int x2, int y2) {
command[0]='|'; command[1]=10;
command[2]=(unsigned char)x1; command[3]=(unsigned char)(x1 >> 8); command[4]=(unsigned char)y1;
command[5]=(unsigned char)(y1 >> 8);command[6]=(unsigned char)x2;command[7]=(unsigned char)(x2 >> 8);
command[8]=(unsigned char)y2;command[9]=(unsigned char)(y2 >> 8);
command[10]='~';command[11]=0;
sendStringL(command,12);
delay(WAIT);
}
void drawchar( int x, int y, char text) {
command[0]='|'; command[1]=11;
command[2]=(unsigned char)x; command[3]=(unsigned char)(x >> 8); command[4]=(unsigned char)y;
command[5]=(unsigned char)(y >> 8);command[6]=text;command[7]=0;command[8]=0;
command[9]='~';command[10]=0;
sendStringL(command,11);
delay(WAIT);
}
void drawstring( int x, int y, char *text) {
int len;
command[0]='|'; command[1]=12;
command[2]=(unsigned char)x; command[3]=(unsigned char)(x >> 8); command[4]=(unsigned char)y;
command[5]=(unsigned char)(y >> 8);command[6]=0;command[7]=0;command[8]=0;
strcpy ( &command[9], text);
len = strlen(text);
sendStringL(command,9+len);//10 is where the zero is
delay(WAIT+len*15);
}
void triangle( int x1, int y1, int x2, int y2, int x3, int y3) {
command[0]='|'; command[1]=15;
command[2]=(unsigned char)x1; command[3]=(unsigned char)(x1 >> 8); command[4]=(unsigned char)y1;
command[5]=(unsigned char)(y1 >> 8);command[6]=(unsigned char)x2;command[7]=(unsigned char)(x2 >> 8);
command[8]=(unsigned char)y2;command[9]=(unsigned char)(y2 >> 8);
command[10]='~';command[11]=0;
sendStringL(command,12);
delay(WAIT+100);
command[0]='|'; command[1]=16;
command[2]=(unsigned char)x3; command[3]=(unsigned char)(x3 >> 8); command[4]=(unsigned char)y3;
command[5]=(unsigned char)(y3 >> 8);command[6]=0;command[7]=0;
command[8]=0;command[9]=0;
command[10]='~';command[11]=0;
sendStringL(command,12);
delay(WAIT+300);
}
void clearscreen( void) {
setbcolor( 0, 0, 0);fillback();
}
void background( int b) {
setbcolor( b, b, b);fillback();
}
void stroke( int s) {
setfcolor( s, s, s);
}
void stroke( int r, int g, int b) {
setfcolor( r, g, b);
}
void gettouch( void) {
command[0]='|'; command[1]=13;
command[2]=0; command[3]=0; command[4]=0;
command[5]=0;command[6]=0;command[7]=0;command[8]=0;
command[9]='~';command[10]=0;
sendStringL(command,11);
delay(WAIT);
delay(10);
mySerial.read();
mouseX = mySerial.read();
mouseY = mySerial.read();
if (mouseX < mousex =" 1;"> SCREENX) mouseX = SCREENX;
if (mouseY < mousey =" 1;"> SCREENY) mouseY = SCREENY;
}
float dist(float x1, float y1, float x2, float y2) {
return sqrt(sq(x2-x1)+sq(y2-y1));
}
void rect (int x, int y, int width, int height) {
drawrect(x, y, x+width, y+height);
}
void quad( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) {
triangle(x1, y1, x2, y2, x3, y3);
delay(1000);
triangle(x2, y2, x3, y3, x4, y4);
delay(1000);
triangle(x1, y1, x3, y3, x4, y4);
delay(1000);
}
void fill( int f) {
setfcolor(f,f,f);
setbcolor(f,f,f);
}
void ellipse( int x, int y, int radx, int rady) {
if (radx == rady) {
drawcircle( x, y, radx);
} else {
command[0]='|'; command[1]=14;
command[2]=(unsigned char)x; command[3]=(unsigned char)(x >> 8); command[4]=(unsigned char)y;
command[5]=(unsigned char)(y >> 8);command[6]=(unsigned char)radx;command[7]=(unsigned char)(radx >> 8);
command[8]=(unsigned char)rady;command[9]=(unsigned char)(rady >> 8);
command[10]='~';command[11]=0;
sendStringL(command,12);
delay(WAIT+100);
}
}
void setup() {
mySerial.begin(9600);
Serial.begin(9600);
//delay(2000);
}
//http://ejohn.org/apps/processing.js/examples/basic/distance2d.html
float max_distance;
int oldx, oldy;
void loopo () {
int a = 0;
setbcolor( 128, 255, 57);
delay(a);
fillback();
delay(a);
setbcolor( 0, 0, 0);
delay(a);
fillback();
delay(a);
//setbcolor( 255, 255, 255);
drawchar(50,50,'X');
drawstring(50,70,"asdf hello");
delay(a);
setbcolor( 0, 0, 255);
fillback();
delay(a);
}
void loop () {
gettouch();
oldx = mouseX;
oldy = mouseY;
max_distance = dist(0, 0, width, height);
setbrightness( 10);
setbcolor( 0, 0, 0);fillback();
draw();
while (1) {
gettouch();
if ((mouseX != oldx) || (mouseY != oldy)) {
oldx = mouseX;
oldy = mouseY;
clearscreen();
setbcolor( 255, 255, 255);
setfcolor( 255, 255, 255);
draw();
}
}
}
void draw( void) {
float size;
//background(51);
for(int i = 0; i <= width; i += 20) { for(int j = 0; j <= width; j += 20) { float size = dist(mouseX, mouseY, i, j); size = size/max_distance * 33; ellipse(i, j, size, size); } } }
And here's the source code for the TouchShield:
#include
COLOR fcolor = { 0, 0, 0 };
COLOR bcolor = { 0, 0, 0 };
COLOR green = { 0, 255, 0 };
COLOR blue = {0,0,255};
COLOR yellow = {255,255,0};
COLOR grey = {0x77,0x77,0x77};
COLOR red = {255,0,0};
COLOR black = {0,0,0};
COLOR white = {255,255,255};
char buf[32];
char tmp[32];
int brightness=5;
POINT my_point;
int trix1, triy1, trix2, triy2, trix3, triy3;
void setup() {
Serial.begin(9600);
lcd_setBrightness(brightness);
lcd_clearScreen(white);
}
void GetString(char *buf, int bufsize)
{
int i;
for (i=0; i
}
buf[i] = 0; // 0 string terminator just in case
}
void loop() {
int cptr, x1, y1, x2, y2, r, r2, timer;
GetString(buf, sizeof(buf));
delay(10);
if (touch_get_cursor(&my_point)) {
}
if (buf[0] == '|') {
cptr = 1;
switch (buf[cptr]) {
case 1:
fcolor.red = buf[cptr+1];
fcolor.green = buf[cptr+2];
fcolor.blue = buf[cptr+3];
break;
case 2:
bcolor.red = buf[cptr+1];
bcolor.green = buf[cptr+2];
bcolor.blue = buf[cptr+3];
break;
case 3:
lcd_clearScreen(bcolor);
break;
case 4:
lcd_setBrightness(buf[cptr+1]);
brightness = buf[cptr+1];
break;
case 5:
timer = (buf[cptr+2] << i =" brightness;">0; i--) {
lcd_setBrightness(i);
delay(timer);
}
CLRBIT(PORTE, PE3);
break;
case 6:
timer = (buf[cptr+2] << i =" 0;" x1 =" (buf[cptr+2]" y1 =" (buf[cptr+4]" x1 =" (buf[cptr+2]" y1 =" (buf[cptr+4]" r =" (buf[cptr+6]" x1 =" (buf[cptr+2]" y1 =" (buf[cptr+4]" x2 =" (buf[cptr+6]" y2 =" (buf[cptr+8]" x1 =" (buf[cptr+2]" y1 =" (buf[cptr+4]" x2 =" (buf[cptr+6]" y2 =" (buf[cptr+8]" x1 =" (buf[cptr+2]" y1 =" (buf[cptr+4]" x1 =" (buf[cptr+2]" y1 =" (buf[cptr+4]" x1 =" (buf[cptr+2]" y1 =" (buf[cptr+4]" r =" (buf[cptr+6]" r2 =" (buf[cptr+8]" trix1 =" (buf[cptr+2]" triy1 =" (buf[cptr+4]" trix2 =" (buf[cptr+6]" triy2 =" (buf[cptr+8]" trix3 =" (buf[cptr+2]" triy3 =" (buf[cptr+4]" mycolor =" {255," red =" fill.red;mycolor.green" blue =" fill.blue;" red =" outline.red;mycolor.green" blue =" outline.blue;" x =" 0," y =" b;" a2 =" (long)a*a," b2 =" (long)b*b;" crit1 =" -(a2/4" crit2 =" -(b2/4" crit3 =" -(b2/4" t =" -a2*y;" dxt =" 2*b2*x," dyt =" -2*a2*y;" d2xt =" 2*b2," d2yt =" 2*a2;">=0 && x<=a) { lcd_pixel(xc+x, yc+y, mycolor); if (x!=0 || y!=0) lcd_pixel(xc-x, yc-y, mycolor); if (x!=0 && y!=0) { lcd_pixel(xc+x, yc-y, mycolor); lcd_pixel(xc-x, yc+y, mycolor); } if (t + b2*x <= crit1 || /* e(x+1,y-1/2) <= 0 */ t + a2*y <= crit3) /* e(x+1/2,y) <= 0 */ incx(); else if (t - a2*y > crit2) /* e(x+1/2,y-1) > 0 */
incy();
else {
incx();
incy();
}
}
}
void dispFillEllipse(int xc, int yc, int a, int b)
{ /* e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 */
int x = 0, y = b;
unsigned int width = 1;
long a2 = (long)a*a, b2 = (long)b*b;
long crit1 = -(a2/4 + a%2 + b2);
long crit2 = -(b2/4 + b%2 + a2);
long crit3 = -(b2/4 + b%2);
long t = -a2*y; /* e(x+1/2,y-1/2) - (a^2+b^2)/4 */
long dxt = 2*b2*x, dyt = -2*a2*y;
long d2xt = 2*b2, d2yt = 2*a2;
while (y>=0 && x<=a) { if (t + b2*x <= crit1 || /* e(x+1,y-1/2) <= 0 */ t + a2*y <= crit3) { /* e(x+1/2,y) <= 0 */ incx(); width += 2; } else if (t - a2*y > crit2) { /* e(x+1/2,y-1) > 0 */
//dispRectangle(xc-x, yc-y, width,1);
lcd_rectangle(xc-x, yc-y, xc-x+width, yc-y+1, mycolor, mycolor);
if (y!=0)
//dispRectangle(xc-x, yc+y, width,1);
lcd_rectangle(xc-x, yc+y, xc-x+width, yc+y+1, mycolor, mycolor);
incy();
}
else {
//dispRectangle(xc-x, yc-y, width,1);
lcd_rectangle(xc-x, yc-y, xc-x+width, yc-y+1, mycolor, mycolor);
if (y!=0)
//dispRectangle(xc-x, yc+y, width,1);
lcd_rectangle(xc-x, yc+y, xc-x+width, yc+y+1, mycolor, mycolor);
incx();
incy();
width += 2;
}
}
if (b == 0)
//dispRectangle(xc-a, yc, 2*a+1,1);
lcd_rectangle(xc-a, yc, xc-a+2*a+1, yc+1, mycolor, mycolor);
}
//There's definitely an easier way to do this, but for now I'll use some help from:
//http://www.codeproject.com/KB/GDI/antialias.aspx#dwuln
//Edited by inthebitz
void DrawWuLine ( short X0, short Y0, short X1, short Y1, COLOR linecolor )
{
unsigned short IntensityShift, ErrorAdj, ErrorAcc;
unsigned short ErrorAccTemp, Weighting, WeightingComplementMask;
short DeltaX, DeltaY, Temp, XDir;
short BaseColor = 0;
short NumLevels = 2;
unsigned short IntensityBits = 2;
/* Make sure the line runs top to bottom */
if (Y0 > Y1) {
Temp = Y0; Y0 = Y1; Y1 = Temp;
Temp = X0; X0 = X1; X1 = Temp;
}
/* Draw the initial pixel, which is always exactly intersected by
the line and so needs no weighting */
lcd_pixel(X0, Y0, linecolor);
if ((DeltaX = X1 - X0) >= 0) {
XDir = 1;
} else {
XDir = -1;
DeltaX = -DeltaX; /* make DeltaX positive */
}
/* Special-case horizontal, vertical, and diagonal lines, which
require no weighting because they go right through the center of
every pixel */
if ((DeltaY = Y1 - Y0) == 0) {
/* Horizontal line */
while (DeltaX-- != 0) {
X0 += XDir;
lcd_pixel(X0, Y0, linecolor);
}
return;
}
if (DeltaX == 0) {
/* Vertical line */
do {
Y0++;
lcd_pixel(X0, Y0, linecolor);
} while (--DeltaY != 0);
return;
}
if (DeltaX == DeltaY) {
/* Diagonal line */
do {
X0 += XDir;
Y0++;
lcd_pixel(X0, Y0, linecolor);
} while (--DeltaY != 0);
return;
}
/* Line is not horizontal, diagonal, or vertical */
ErrorAcc = 0; /* initialize the line error accumulator to 0 */
/* # of bits by which to shift ErrorAcc to get intensity level */
IntensityShift = 16 - IntensityBits;
/* Mask used to flip all bits in an intensity weighting, producing the
result (1 - intensity weighting) */
WeightingComplementMask = NumLevels - 1;
/* Is this an X-major or Y-major line? */
if (DeltaY > DeltaX) {
/* Y-major line; calculate 16-bit fixed-point fractional part of a
pixel that X advances each time Y advances 1 pixel, truncating the
result so that we won't overrun the endpoint along the X axis */
ErrorAdj = ((unsigned long) DeltaX << erroracctemp =" ErrorAcc;" weighting =" ErrorAcc">> IntensityShift;
//////////////////////////////////////////////////////
lcd_pixel(X0, Y0, linecolor);
//lcd_pixel(X0 + XDir, Y0, mycolora);
//lcd_pixel(X0, Y0, BaseColor + Weighting);
//lcd_pixel(X0 + XDir, Y0,
// BaseColor + (Weighting ^ WeightingComplementMask));
}
/* Draw the final pixel, which is
always exactly intersected by the line
and so needs no weighting */
lcd_pixel(X1, Y1, linecolor);
return;
}
/* It's an X-major line; calculate 16-bit fixed-point fractional part of a
pixel that Y advances each time X advances 1 pixel, truncating the
result to avoid overrunning the endpoint along the X axis */
ErrorAdj = ((unsigned long) DeltaY << erroracctemp =" ErrorAcc;" weighting =" ErrorAcc">> IntensityShift;
///////////////////////////////////////////////////
lcd_pixel(X0, Y0, linecolor);
//lcd_pixel(X0, Y0 + 1, linecolor);
//lcd_pixel(X0, Y0, BaseColor + Weighting);
//lcd_pixel(X0, Y0 + 1,
// BaseColor + (Weighting ^ WeightingComplementMask));
}
/* Draw the final pixel, which is always exactly intersected by the line
and so needs no weighting */
lcd_pixel(X1, Y1, linecolor);
}
//http://www.swissdelphicenter.ch/en/showcode.php?id=2400
//http://tog.acm.org/GraphicsGems/gemsiii/triangleCube.c
//I'm sure there's a more elegant and cleaner way, but with help from the links above I was able to cludge
//this together, so that it at least works!
#define MIN3(a,b,c) ((((a)<(b))&&((a)<(c))) ? (a) : (((b)<(c)) ? (b) : (c))) #define MAX3(a,b,c) ((((a)>(b))&&((a)>(c))) ? (a) : (((b)>(c)) ? (b) : (c)))
void triangle ( int x1, int y1, int x2, int y2, int x3, int y3, COLOR tcolor, COLOR ocolor) {
for (int x=MIN3(x1, x2, x3); x
return 1;
} else if (orin <>
Labels:
Liquidware
Happy (Cyber) Monday!
No, it's not just any other Monday. I've heard about Black Friday for years, but it's the first time I've heard of "Cyber Monday", the online retailer equivalent. Maybe I've had my head in the sand, but it's one more thing to get me going today, as we're 5 days away from another weekend!
So in honor of Cyber Monday, I've rearranged some of the prices, and made some updates to the kits that a couple folks had suggested. Actually, I've been meaning to do this for a while, so this is just an excuse for me to finally get to it :-)
There's the option to swap in a HiCap in some of the kits now, as well as a variety of other updates I'll be making throughout the day, so be sure to take a look!
So in honor of Cyber Monday, I've rearranged some of the prices, and made some updates to the kits that a couple folks had suggested. Actually, I've been meaning to do this for a while, so this is just an excuse for me to finally get to it :-)
There's the option to swap in a HiCap in some of the kits now, as well as a variety of other updates I'll be making throughout the day, so be sure to take a look!
Labels:
Liquidware
Subscribe to:
Posts (Atom)