Sunday, December 12, 2010


/* it's very easy to do a forthlike system in JS. here it is */

var words = [];
var stack = [];
var state = "interp";
var cword = "";

words["+"] = function(stack) {
stack.push(stack.shift() + stack.shift());
}

function run_compile1(stack, word)
{
if (word == ";") {
state = "interp";
}

cword = word;
words[cword] = new Object();
words[cword].type = "func";
words[cword].cmds = [];
state = "compile2";
}

function run_compile2(stack, word)
{
if (word == ";") {
state = "interp";
return;
}
words[cword].cmds.push(word);
}

function run_interp(stack, word)
{
// if (typeof(words[word]) == "undefined") return; // todo: throw

if (word == ":") {
state = "compile1";
return;
}

if (typeof(words[word]) == "object") {
for (i in words[word].cmds) {
// print(words[word].cmds[i]);
run_interp(stack, words[word].cmds[i]);
}
} else if (typeof(words[word]) == "function") {
words[word](stack);
} else {
var v = parseFloat(word);
if (v != NaN) {
stack.push(v);
} else {
stack.push(word);
}
}
}

function run(stack, word)
{
eval("run_" + state + "(stack, word)");
}

run(stack, ":");
run(stack, "test");
run(stack, "3");
run(stack, "4");
run(stack, "+");
run(stack, ";");
//print(stack);
run(stack, "test");
run(stack, "2");
print(stack);
run(stack, "+");
print(stack);

Tuesday, July 06, 2010

Seagate Dockstar notes...

(or: Chad writes a practical post for once!)

The Seagate Dockstar's a variation of the Pogoplug, in turn Sheevaplug. woot.com recently had them for $20+5/ea ($65 for 3!) and buy.com has them for $25+0.

The Dockstar has reduced specs (128mb ram, 256mb flash, no RTC) from the original Sheevaplug, but multiple USB ports. Combined with a Gigabit Ethernet port it's a far more powerful version of the once-famous Linksys NSLU2 (aka Slug)

The first challenge is getting the conventional firmware out of the way so we can do truly useful things with it. It turns out that the default firmware only uses 32MB flash, leaving a nice 224MB jffs2 partition for a better Linux distro! there's a build of Debian Lenny here

My steps (largely cribbed from http://ahsoftware.de/dockstar/)

- Log in via ssh (root pw: sgxadmin)

- mount / -o remount,rw

- disable hbmgr in /etc/init.d/rcS. edit: this is very important, the dockstar firmware may auto-update and cut off ssh!

- mkdir /tmp/mnt

- mount /dev/mtdblock3 /tmp/mnt

Now I can extract the Lenny tarball - I put it on another machine and used netcat (nc -l -p5000 | tar -xvjf -) to put it into /tmp/mnt

After this there are two paths:

- run debian in a chroot with a ssh server on an alternate port. This means keeping the init from the original system running, but it's not too bad.

- Put a pivot_root/exec debian's /sbin/init and have the Debian system totally take over.

Debian Lenny notes:

- /var/cache/apt[/archives][/partial] must be a tmpfs since jffs2 is not mmap-able.

- debian/usr/sbin/chroot is static, so you don't need a chroot binary in the main system.

- By changing the sshd port to 2222 in /etc/ssh/sshd_config, you can ssh directly into debian

- you need these mounts:

tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=620)
none on /proc type proc (rw)
none on /sys type sysfs (rw)
none on /tmp type tmpfs (rw)
none on /dev/shm type tmpfs (rw)
none on /dev/pts type devpts (rw)
none on /lib/init/rw type tmpfs (rw)
none on /var/cache/apt type tmpfs (rw)

- run "export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"" if chrooting in.

- After removing /var/cache/apt there's still 40MB (+ compression gain) in the large filesystem. Not bad.

update: here's an autostart script that gets the debian chroot+sshd up and running (assuming you change the ssh server port)


#!/bin/sh
mount /dev/mtdblock3 /debian
mount none -t proc /debian/proc
mount none -t tmpfs /debian/tmp
mount none -t tmpfs /debian/dev/shm
mount none -t tmpfs /debian/var/cache/apt
mkdir /debian/var/cache/apt/archives
mkdir /debian/var/cache/apt/archives/partial
mount none -t sysfs /debian/sys
mount /dev /debian/dev -o bind
mount none -t devpts /debian/dev/pts
/debian/usr/sbin/chroot /debian /usr/sbin/sshd


The Debian chroot will start sometime after the stock distro's sshd, since mounting the jffs2 partition takes a while. There's plenty of free memory afterwards:

Pogoplug:~# free
total used free shared buffers cached
Mem: 126064 27040 99024 0 0 10792
-/+ buffers/cache: 16248 109816
Swap: 0 0 0

Enjoy!

Saturday, July 03, 2010

A poor/slow man's FPGA? It might be closer than you think.

Got a paperback copy of "Designing Logic Systems Using State Machines" today off Amazon... the bit about ROM-based logic (a precursor to CPLD's?) got me thinking that one could translate a logic circuit design into assembly code for a microcontroller. It could use a mixture of ROM and direct assembly operations, tuning it according to the target CPU in question.

Such a program would be slow by logic standards (at least if you wanted more than the simplest functions!) but with non-pin-related interrupts off and non-branching code, the timing could be completely predictable.

Friday, July 02, 2010

Another idea...

(yes, I'm very ADD this week!)

A CUPS-based virtual print server for rooted nook wi-fi. Turn it on, print *anything* to it (hopefully even via Windows...?) and take it with you. That should be pretty awesome for printing out web pages, eh?

(or alternatively, netcat listening on port 9100 wired up to ghostscript in a PDF conversion mode... that might only work with Linux tho.)

MSP430 Launchpad first impressions

Just plugged in my MSP430 Launchpad. Not able to actually do much with it yet, but you actually get four microcontrollers... on the programming side there's:

- A TUSB3410 USB/8051 UART microcontroller

- And a MSP430F1612 - with considerably more RAM+ROM than the parts you're meant to develop for. (Why hasn't the code for this been rolled into the 3410 yet?)

There's a "modem" UART interface to the serial port on the target chip, and a HCI-based Debug interface. Oddly the 'modem' interface appears to be the one used for target programming.

To properly load the 5310 driver, you must modify the USB driver for the 5310 to add device 0x451:0xf432. Sadly I don't actually have a build tree on this laptop so I'll have to get back to this one in a while. *sigh*

State Machine Language notes (WIP)

The HP 9100A desktop calculator was an incredible piece of engineering. It basically implemented a VLIW processor without any digital IC logic - it had a 4K ROM carved into a 12-layer circuit board (needless to say the yields sucked!) It used a CRT as a 3-line 8-segment display!

Tom Osbourne's initial work on ASM sounds quite interesting, although I haven't found all the details yet. http://www.hp9825.com/html/osborne_s_story.html - I'd figure a lot of this got into current design, hopefully!

Doing some more reading - Woz used these techniques on Apple Integer Basic and the Disk II. (Makes sense, since he *did* work for HP)

---

programming ideas:

- *actually* passing a variable/object along, so it only has one "owner" at a time.

- making a state machine language that gets 'compiled' into straight C. already thinking of doing this for register definitions etc...

Jay notes (WIP)

Jay (to go along with finch and pidgeon) will be a web-server-based libpurple client, allowing users to set up a small server and use their web browsers to chat. While other web chat clients exist, some power users might appreciate *not* having to use someone else's cloud-based services.

(proposed logo: a simplified Jay bird in front of a cloud)

Jay contains three separate programs:

- libpurple<->JSON connector (jayd)

- JSON CGI program, handling authentication and sending updates as needed to the web client.

- Javascript/JSON web client.

If things go particularly well the JSON setup I'm using might become a standard.

Thursday, July 01, 2010

Unstuck in time...

Got a week off coming up - and about a year's worth of projects to fill it. ;)

- Creating "jay" - a libpurple web services server/client. Three pieces - libpurple client, json http connector, and finally a client. The latter two pieces might be extensible to work with other things... at the same time.

( ^ - that's probably the most practical project...)

- Getting back into the electronics thing... hopefully figuring out how to solder surface-mount components in truly ghetto fashion... on tape*! Search on "elm-chan uew" for my inspiration there.

- Tinkering with a bunch of old random stuff. Like a Pentium MMX toshiba... if I can find a caddy for it.

- Extending from Jay - a simple Linux web-browser-based UI system, ala ChromeOS but hopefully lighter weight. I was helping out a friend shopping for a computer - there's so much *crap* in a consumer Windows system that's utterly distracting for noobs.

(side-note: how long until Apple replaces the MacBook non-pro with an iOS-Book...? Or will iPad gain better mouse+keyboard support and become the new... iBook?)

- Looking at state machine languages (and way back to HP's ASM work) and figuring out an acceptably simple language (i.e. no characters that aren't on a standard keyboard!)

- Retrocomputing hacking (or: fun with expansion ports, buffers, and modern chips...) For instance on the Atari 8-bit front - SIO2PC, SIO2USB, etc are amazingly overpriced, considering it's just a 5V serial system that a simple microcontroller could deal with.

So basically I'm just unstuck in time... past, present, future... it's all good. I just need to do something meaningful.

(* - 3M 5419 Polymide - per 3M it can go up to 500F safely...)

Sunday, June 20, 2010

How to install Debian in qemu via console only...

Running Debian in a qemu VM on a remote machine is useful in quite a few cases, such as setting up KVM instances or preparing CompactFlash cards to bring up old laptops. This qemu command will bring up a serial console based installation session that even works in screen:

qemu -hda /dev/sdc -cdrom firmware-testing-i386-netinst.iso -boot d -kernel /mnt2/install.386/vmlinuz -initrd /mnt2/install.386/initrd.gz -nographic -append "fb=false console=ttyS0"

or, when doing a CF-destined install:

qemu -hda /dev/sdc -cdrom ~/emu/firmware-testing-i386-netinst.iso -boot d -kernel /mnt2/install.386/vmlinuz -initrd /mnt2/install.386/initrd.gz -curses -append "fb=false"

In my example I directly booted the kernel using qemu, with the debian image on /mnt2. hda is an 8GB Sandisk Ultra CF card (available for $35 at Costco)

From here it's pretty much the regular debian installer...

Saturday, April 17, 2010

preliminary spec: using old headless laptop as a network kbd+mouse

I'm pretty tired (at 1PM on a saturday. how lame!) but I'm scoping out an idea to use old headless laptops to work as mouse+kbd. I have a headless thinkpad t20 with pxe support (I think) that would work nicely for this.

These are notes mostly for myself on how this thing oughta work. I'll probably use OpenWRT with a uicat/client package (which I need to write) with uiclient autostarting.

Eventually this could be expanded into a full "drone" distribution capable of being a remote video player. Probably still OpenWRT based with a LUCI interface to set up wireless networking(?) although that needs non-volatile storage. But that doesn't have to be on the actual drone...

Now to get my brain together enough to write this silly thing... ;)

Pieces:

- Old laptop, booting via IDE-CF, USB, memory-loading CD, or network. Network must be present and support DHCP.

- (new) uicat (uinput cat, ala netcat) - can work with netcat to stream mouse/kbd in either direction.

- (new) uiclient (uinput client) - like uicat, but with extra commands on the client side.

Using a suitably loaded Linux, the uinput-drone system will automatically start. "blind" operation is fully supported (think headless laptop) and a special key sequence can be used to link up to a uicat "server" listening for a connection on a given port.

Once the Linux is loaded, the num lock LED will blink every second. Then press the caps lock key and the capslock LED will blink instead. Then type in the IP address of the target computer, and hit return (or escape to abort on a typo). It will then try to connect to the target, and if it works all two/three LED's will blink for one second. If an error occurs it will probably just go back to blinkiing num-lock.

After that, all input events will be 'tunneled' over the network and they will look like native events to the other computer.

To end a session, use control-capslock-enter? Something that isn't commonly used at least.

---

V2 of the uidrone system will support xorg (newest) with mplayer? so that it can be used as a remote video player as well. This mode would be quite useful for TV out, since many older laptops have S-Video output we can probably use.

Friday, April 09, 2010

copypasta from an ars thread-post i just made...

I figured out that WP7 was DOA a few days ago... why?

Because Microsoft is throwing *everything* out, and blindly copying the *worst* things Apple did that completely remove what strengths Windows Mobile *did* have. No multitasking (because iPhone doesn't have it) and a locked App store (because Apple has it)

Combine that with breaking back-compat (so *not* Microsoft) and relying on their development flavor-of-the-month, and it's a 'me too' product - all the downsides of Apple but little to none of the magic.

If Microsoft had a clue, they would've put in Enterprise features and they would have much of RIM's marketshare, and would be able to maintain their current positioning. (RIM should be ok, at least once they get the Webkit browser... the 9700/OS5 is quite similar to Android in *some* ways... enough to keep the customer base from jumping off IMO.)

The other huge problem? The web browser is going to be garbage compared to Webkit - which because Apple based it on KDE's browser, has to share... leading to everyone else using it. WM6.5's IE only gets 5/100 on Acid3, and I doubt WP7's will be anywhere near 100.

(IMO Webkit might be the one of the most significant software packages of the 10's...)

As for Symbian - a friend of mine got a Nokia from AT&T free w/contract - disguised as a non-smartphone. If Nokia can keep lower end Symbians enough like series 40, they'll quietly keep selling 'em. And in the Webkit/HTML5 era, Symbian^3 should do just fine.

Eventually simpler apps will all be HTML5+Javascript (hence me actually *rooting* for Steve Jobs in his Flash war. *nobody* else could win it...) and everyone with a decent browser will have a usable smartphone. It'll just be easier to pick up Android or perhaps Symbian now that it's opened.

Microsoft, having too much pride to adopt Webkit, might miss out on the party for years.

Tuesday, April 06, 2010

on the iPad and computing in the 10's...

I'll start with this: if you're at all interested in picking up programming, start with Javascript and write basic web pages and apps with it. It's the BASIC of the 10's... no, it's actually far more pervasive. ;)

---

I haven't actually played with an iPad yet (I was sick this weekend, and I don't really have $499-599 right this second... *glances at 32" LCD*) but I think it's a turning point.

Basically, it's one step closer to the computer that isn't there - something that fades away into the background. Getting rid of the keyboard might be risky, but...

... the iPad is a consumer device. It's not about writing, drawing, or creating content.

That's where the "PC" of the 10's comes in against the iPod's "Mac."

---

Android is nice, but one little piece fell out of their pre-planning that hurts it:

It's Javascript that matters, not Java.

---

Javascript is a very interesting language, wrapped in C semantics, various web browser crap, and labeled Java* to throw off any PHB's that would kill it off for actually being innovative.

But it managed to bring quite a few academic ideas into the real world - first class functions, lambdas, closures, dynamic code execution, etc.

Go to http://www.crockford.com to find out more.

---

Javascript could have gotten away with being as bad as it's rep, though. Think of a modern computer, sold to consumers, that doesn't have Javascript in it, in some form or another.

*chirp*

But partially because it *is* a very mallible language, and because webstuff is just *that* popular, it'll be tinkered around with until you can do anything that a low-complexity program needs to do.

For instance, you can make a basic iPhone app in html+javascript, provide it a manifest file, and it'll store it on the iPhone locally and even hide the location bar for you. (This is how the second pass at Google Voice works...)

---

Once you realize that HTML5+javascript can make decent apps for iProducts, it makes the store lock-down a *little* more tolerable. But to get to everything you still need native code, which means dealing with Apple and their censors. Blah.

---

Microsoft is now out of their element. Windows Mobile 7 will likely still be a 'me too' product, although it's their last chance to make something that *isn't*, especially since they're throwing backwards compatibility out the window, which is *very* non-Microsofty...

---

I really do think Apple's anti-Flash stance is the best thing for the entire computer industry, although part of that might be by accident. It's encouraging people to figure out just how far HTML5 can go and from there how unnecessary Adobe's bloated buggy plugin is.

(Yes, I know it's really because Steve's a control freak...)

---

It's time for the next generation of Linux GUI's to start coming about - one that can perform as well as the iPad's. Android will probably have to do for a year or two, but the real competition will come from a more web-centric engine.

---

At the very least, tech from Linux projects tend to resurface in odd ways. Like my Panasonic 32" TV (among others!) having the GPL and LGPL texts in the menu system!

And while Firefox had the biggest mindshare - at least for a while - Apple's move to commercialize KHTML and KJS into Webkit took some KDE code and made it what I think'll be the preeminent web browser engine this decade.

Being lighter-weight than Mozilla's engine, it has been picked up by almost everyone making mobile browsers - except Microsoft, and from what I can tell mobile IE is crap anyway. (The browser in Winmo 7 had *better not* suck, or it's DOA)

And Webkit runs well on full-size computers, too.

---

I have a nice used X41 Tablet I got for <$300 recently. It'd be nice if it had a finger touchscreen, but maybe that's where I should start experimenting with iPaddy stuff...

---

Tuesday, March 30, 2010

Current geeky plans...

- mini-Javascript interpreter (measured in xxK, or hopefully even xK, if possible)

- Getting Linux on my msntv 2 (RM4100 - Celeron 733, 128MB ram, i830, etc...)

- blipvert - flexible audio time compression (need to make it a sox plugin)

It's time for another (attempt at a) month of posts about stuff I'm doing...

Monday, February 01, 2010

It's very easy to make complex systems using pipes and other simple UNIX shell techniques, if you know how to fully exploit the properties of what you're using.

This is a great example - a two-line streaming system suitable for both recording DV and streaming it to an overflow room @ a conference:

record side:
dvgrab - | ffmpeg -f dv -i - -vcodec mpeg1video -deinterlace -bframes 0 -b 2048k -ab 128k -f mpeg - >> test.mpg

This runs fine on a P4/2.53B (Northwood) system with 512MB ram - easily obtainable for <$100 if you have a good local source.

MPEG-1 video and mp2 (not mp3) audio with no B frames are no longer patent-encumbered and are much faster than Ogg Theora, and with far wider software support. Almost all MPEG-2 decoding systems can deal with MPEG-1 files, and all properly coded mp3 players can play mp2, which can sound really good at 224Kb/sec (VCD bitrate)

mplayer is able to jump into MPEG-1 PS files mid-stream and handle new encoding sessions. So using >> for ffmpeg's output is quite reasonable and provides robustness if the DV capture fails, since dvgrab|ffmpeg can be put into a loop.

You can use other capture systems as well - anything ffmpeg supports, which is quite a lot. You just need to adjust the input-side -f parameter to tell it what to expect.

viewer side:
ssh 192.168.1.40 "tail -f -c 1024 test.mpg" | mplayer -cache 512 -

This is also very simple. It makes an ssh connection to the recording host. tail (at least with -c) is 8-bit clean so you can stream MPEG-1 data through it to mplayer, which can jump in at any point.

There are many different ways to handle the viewer. netcat would work, and anything that can deal with MPEG-1 from standard output, starting mid-stream can be used as a player. mplayer is just the most common one on Linux.

Saturday, January 16, 2010

Here's some code I've been playing with as part of that odd language concept. It converts binary, decimal or hex #'s and is 180-300 bytes -Os depending on CPU.

thumb2 really is small - it comes out about 70 bytes shorter than x86. Good for when this code's running on -m3.

It has error but not overflow checking and is written to work at native word size.

Hoping I can get my language running on the AVR as well eventually - ideally I'd have the core running in 2-4K as a bootloader. For some things there's nothing cooler than an 8 or 20-pin DIP chip. . o O (for everything else, there's master^WARM)


/* This flexible parser handles sign, dec, and hex bases while maintaining error checking */

/* Slightly less than 256 bytes on i386 when compiled -Os, slightly more on ARM non-thumb.
* That might still be a bit large. */

int parsenum(char *s, int len, unsigned int *o)
{
int first = 0, i;
int base = 10, m = 1, v;
char cc;

/* one can still handle full unsigned words and have a negative multiplier. */
if ((len > 0) && (s[0] == '-')) {
first++; m = -1;
}
if (len <= first) return -1;

if (s[first] == '0') {
if (s[first + 1] == 'x') {base = 16; first += 2;}
else if (s[first + 1] == 'b') {base = 2; first += 2;}
}

for (i = first; (s[i] != ' ') && (s[i] != 0) && (i < len); i++);

*o = 0;
i--;
while (i >= first) {
/* ASCII is actually pretty darn clever - if you mask out 0x20,
* it removes caps and maintains the characters we need. */
cc = s[i] & 0xdf;

/* '0'-'9' are 0x30, which are remapped to 0x10 */
if ((cc >= 0x10) && (cc <= 0x19)) {
v = cc - 0x10;
} else if ((cc >= 'A') && (cc <= 'F')) {
v = cc - ('A' - 10);
} else v = 255;

if (v >= base) return -1;
*o += (v * m);
m *= base;

i--;
}

return 0;
}

Tuesday, January 12, 2010

risp language concept...

Too tired to finish this, but this is hopefully going to be a simplified LISP/scheme with functions as objects with implicit continuations. I have a feeling there's profound stuff in here that I'm just too tired to reach, but I don't wanna lose this. Sorry about the incoherence. ;)

Risp Is a Small lisP.

everything is a list
all objects are immutable and reference counted - copy-on-write?
lists can have different cell sizes - 8/16/32/64-bit

functions have one parameter but multiple runtime states. function states are mutable.

for instance - divide:
• first load sets up base
• repeated loads do the divides

(func divide
(local value)
(= value $)
(/ value $)
)

functions don't end unless you say they end - they just automatically break/hold at the end of the list.

func list:

• name
• local variables
• run [1..x]

goto lets you jump between runs. don't know how to label them.

'up' keyword pushes a value into the return list.

(func addall
(local v)
((+ v $) (up v))
)

$ is the single parameter. handling multiple parameters is done via staged/multiple calls, you can set up multiple locals that way easily and do the heavy/repeated lifting with a later state.

(func gimmestuff
(local myaddall addall)
(myaddall 1 2 3 4 5)
(myaddall 6)
)

(def catcher (= gimmestuff)

= (may change) can "catch" up statements and build a new list.

you can have functions that run functions and as long as there's no active catching statement, it's returned to the next parent. if there's no parent that can receive it, it is caught by /dev/null. ;)

my 'data-function identity' - executing (variable) = (func variable (local value) (up value)) in other words a non-function variable pushes itself up when run. therefore everything is executable.

Monday, January 11, 2010

Tonight's hackish code...

... is a 16-bit ppm luminance booster/blower-outer.

To use:

- Convert your image into a 16-bit .ppm file. I use "dcraw -4 -h [file.cr2]" to convert a raw file. Raw DSLR files have enough color depth to do interesting things, even though there *is* a noise floor to contend with still...

- Build https://code.google.com/p/chadslab/source/browse/trunk/hsv2.c with "-O3" and preferably SSE math if you're not on a 64-bit system.

- Then run it as "./a.out 0.8 0.99 < [16-bit.ppm] > [new 16-bit ppm]"

- Finally do "gm convert [new ppm] [out.jpg]" to get a postable .jpg file.

The code is entirely uncommented and doesn't even care if you accidently feed it an 8-bit file, it'll just get very confused. Not recommended. ;)

The main concept is to convert RGB into HSL, play with L, and then you get a brighter output.

Some results are at http://www.flickr.com/photos/happycube

edit: source at http://code.google.com/p/chadslab/source/browse/trunk/hsv2.c

- Chad

Wednesday, January 06, 2010

Some new/random ideas...

A stateful/functional/concurrent programming language? These are very rough notes as I'm getting too tired to write more about it tonight.

const int exampleconstant = 12345;
^ syntatic sugar for:
object exampleconstant {
start() = {int this = 12345; state = const;}
}

class foo {
start(type(input) != foo) = {
int i = 0;
int a = 32;
int b = 64;
state = wait;
}
start(typeof(input) == foo)) {
this = input;
}
iterate(typeof(input) == integer) = {
a = a + input;
b = b - input;
i = i + input;
output = a * b;
state = (a < b) ? iterate : end;
}
iterate(typeof(input) != integer) = {
print("illegal input: " + input);
output = error;
}
end() = {
output = i;
}
}

It's an odd mixture of functional/concurrent programming with a C-like syntax.

What makes it different than you see in the code sample...

- input and output are reserved variables. you don't have to 'catch' the output if it's not the type you're looking for, i think. they can also be arrays.

- state is an implicit variable that denotes what to run on the next trigger. i.e. all objects are state machines.

- functions are transactional. everything you see changed is actually pushed into the object at the end of the iteration - what would be a side effect in a regular language is *not* one here.

- objects can also be an instance of one variable.

----

slightly leaving cloudcucooland, i should write a simple FM-type synthesizer because, well, they're not hard to do.

the synth algo i have in mind supports continuous frequency adjustment (calculus-)integration. the frequency and amplitude are continuous functions in time, allowing for smooth changes in generated sound.

sine waves can be flattened from from triangular (0) to square (1), with sine = 0.5. phase restrictions can create interesting waveform patterns on top of that. for instance sawtooth waves can be generated by using (0, pi/4?) phase restrictions.

---

haven't touched my ARM project lately. need to get interrupts working, add newBSD/MIT license, and give credit to Vijay Kumar for showing the path.

I want something simple to play with registers without flashing - it might mean making the serial code I have now a bootloader that can cut over to a new downloaded program in memory... or I might write something small and FORTHlike.