because of dissatisfaction with several aspects of shoutcast i decided to migrate kpsu's streaming servers (hi, lo) to icecast.
the hardest part was poking around until i found the sample shoutcast config file (icecast_shoutcast_compat.xml). after that i setup the server on a different port to test it, added a few extra entries:
<shoutcast-mount>/listen</shoutcast-mount>
<paths>
<logdir>./logs</logdir>
<webroot>./web</webroot>
<adminroot>./admin</adminroot>
<alias source="/" dest="/status.xsl"/>
<alias source="/listen.pls" dest="/listen.m3u"/>
</paths>
the shoutcast-mount and the aliases provide a bit of backwards compatilbity for old links.
Lady Ada, patron saint of all things POV and all things housed in an Altoid's tin, has a new POV project up based around the Amtel ATtiny2313. Best of all she shows how to program the controller via parallel port so you don't need to buy yet another programmer. There are free plans or she'll sell you a kit.
school started on monday but i'm not quite ready for it. i'm becoming ever more desperate to avoid homework. today, i spent four hours putting an optical mouse into an altoids tin.
i've spent the last few months working on a persistence of vision (pov) circuit for a bike wheel. this is my first foray into electronics and micro-controllers so, while it works, it's a bit of a hack. in fact, you might just want to skip on down to the "things to fix" section.
the project is based on two of lady ada's plans for pov projects, the minipov and spoke pov. the minipov uses only a single pic16f630 while the spoke uses an amtel micro-controller, an eeprom, and several 74x259 8-bit latches.
i wanted to enhance the minpov to display text on both sides of the bike wheel. i chose to use microchip's pic because they sold a cheap programmer and i had lady ada's working source code. the biggest challenge with displaying text on both sides of the wheel each side needs to read from a different end of the string. if you're displaying ABC the left side needs to start at C and the right side needs to start at A. that meant i needed 16 outputs, four more than the 16f630 has. to work around this i used an 8-bit addressable latch for each side.
the minipov project uses a simple bitmap to determine what to output. i wanted to have separate bitmaps for each character and link them together in a string. i started by modifying the minipov to use two jump tables. the first selected the character from the string, and the second returned individual lines in the character. once that was working, i started trying to figure out how to read it backwards. i wasn't able to think of anything cleaver so i decided to throw memory at it. i duplicated the code in and reversed order.
i went through a hell of a time finding the proper LEDs for this. trying to find bright LEDs that had a wide viewing angle and didn't cost a buck each was hard. i probably ordered ten different kinds from digikey. the ones below are 1500 mcd with a 70° by 40° viewing angle and only cost about 30 cents each.
| description | quantity | supplier | part number |
|---|---|---|---|
| PCB board | 1 | advanced circuits | custom order |
| PIC16F630 8-bit PIC microcontroller | 1 | digikey | PIC16F630-I/P-ND |
| 14-pin IC socket | 1 | digikey | AE7214-ND |
| 74HC259 8-bit addressable latch | 2 | digikey | 296-8291-5-ND |
| high brightness LEDs | 16 | digikey | 160-1620-ND |
| 3 volt lithium battery with soldering tabs | 1 | digikey | P201-ND |
| SPDT slide switch | 1 | digikey | EG1901-ND |
here's the PIC assembly code. to assemble it you'll need microchip's mplab IDE or the gnu PIC tools. you'll need something to program the PIC with. i threw down the $30 for microchip's pickit 1 flash starter kit.
the board layout was done using cadsoft's freeware version of eagle. you can download the board and schematic files by clicking on the images below.
this is the first board i've ever designed so i made plenty of mistakes :
in the next revision i've got several things i'm looking at changing :
i'll get some more photos up here when i'm making the next set of them.
update: stoked. i got linked to by hack a day. my 15 minutes of internet fame begins.
another update: people have emailed to ask me if i plan to sell these either assembled or as a kit. i do not. my feeling is that you shouldn't sell something unless you can stand behind it. this project is really just a prototype put together by someone who hadn't used a soldering iron since he was 12 years old (i actually had to go down to fry's and buy one). i'm learning it as i go. i was inspired by lady ada and the whole make crowd to stop staring at other people's cool projects on the internet and start making my own.
after my gallery albums got corrupted i started messing around with flickr and got hooked. i'd been pretty frustrated by gallery's rigid album structure, flickr's usage of tags and sets is much more to my liking. there's also an excellent api for those times when you need to roll your own app. the fact that they handle all the backup convinced me to throw down the $45 on a pro account.
now the task it to upload all of my photos to their servers. it's a good chance to go back and import all the old stuff that never made it into gallery. i'm starting with some albums i'd make using jason molenda's makethumbs shell script. i hacked together a perl script to parse the titles and descriptions from the description.txt file, upload the images, and add them to a set. click the read more link to view the script. i hope someone else may find it of use.
update: i finally got around to encoding it as valid html. copy and paste should work better.
#!/usr/bin/perl
use strict;
use warnings;
# upload a makethumbs album to flickr
#
# by andrew morton - http://drewish.com
#
# to use this script fill in the next three variables, then change
# to the directory with the makethumbs album and run it. email if
# you have problems.
my $flickr_email = 'your@email;
my $flickr_pass = 'secret';
my $photo_tags;
# shouldn't need to change anything below here.
# variables
my $flickr_key = '58ac590250ef4eeb81e6d853ee942034';
my @photo_ids; # id assigned after upload
my $config_file = 'descriptions.txt';
my $album_title; # album title
my $album_desc; # album description
my %image_title; # file titles
my %image_desc; # file descriptions
$|= 1; # auto flush
use Flickr::API;
use Flickr::API::Request;
use Flickr::Upload;
use LWP::UserAgent;
use XML::Parser::Lite::Tree::XPath;
ReadMakeThumbsData();
UploadToFlickr();
AddToNewSet();
print "All done.\n";
sub ReadMakeThumbsData() {
print "Loading makethumbs data from $config_file\n";
open(CONFIG, $config_file) or die "Can't open $config_file : $!\n";
# skip to short title section
while (<CONFIG>) {
last if /^\[short title\]/;
}
# suck up album title.
while (<CONFIG>) {
chomp;
last if /^\[longer page description\]/;
$album_title .= $_;
}
# suck up album description
while (<CONFIG>) {
chomp;
last if /^\[captions\]/;
$album_desc .= $_;
}
# suck up image titles
while (<CONFIG>) {
chomp;
next unless $_; # skip empty lines
last if /^\[descriptions\]/;
/^(\S*)\s(.*)/;
$image_title{$1} = $2;
}
# suck up image descriptions
while (<CONFIG>) {
chomp;
next unless $_; # skip empty lines
/^(\S*)\s(.*)/;
$image_desc{$1} = $2;
}
close CONFIG;
}
sub DebugPrintData() {
print("album title: $album_title\n");
print("album desc: $album_desc\n");
foreach my $key (keys %image_title) {
print "$key\n\ttitle: $image_title{$key}\n";
print "\tdesc: $image_desc{$key}\n";
}
}
sub UploadToFlickr() {
my $ua = LWP::UserAgent->new;
my $file;
my $id;
print "Uploading photos to flickr for $flickr_email\n";
foreach $file (sort(keys %image_title)) {
print "$file";
print "\n\ttitle: $image_title{$file}" if $image_title{$file};
print "\n\tdescription: $image_desc{$file}" if $image_desc{$file};
print "...";
$id = Flickr::Upload::upload(
$ua,
'email' => $flickr_email,
'password' => $flickr_pass,
'photo' => $file,
'title' => $image_title{$file},
'description' => $image_desc{$file},
# Everyone can view
'is_public' => 1,
'is_friend' => 1,
'is_family' => 1,
'tags' => $photo_tags
);
if ($id) {
push @photo_ids, $id;
print " assigned id $id\n";
} else {
print STDERR "Failed to upload $file";
}
}
}
sub AddToNewSet() {
my $api = new Flickr::API({'key' => $flickr_key});
my $response;
my $xpath;
my @nodes;
print "Creating set '$album_title' ...";
$response = $api->execute_method(
'flickr.photosets.create',
{
'email' => $flickr_email,
'password' => $flickr_pass,
'title' => $album_title,
'description' => $album_desc,
'primary_photo_id' => 3654245# $photo_ids[0]
}
);
$response->{success} or
die "Could not create the set : $response->{error_message} \n";
$xpath = new XML::Parser::Lite::Tree::XPath($response->{tree});
@nodes = $xpath->select_nodes('/photoset');
print " assigned id: $nodes[0]->{attributes}->{id}\n";
print "Adding photos to set...";
$response = $api->execute_method(
'flickr.photosets.editPhotos',
{
'email' => $flickr_email,
'password' => $flickr_pass,
'photoset_id' => $nodes[0]->{attributes}->{id},
'primary_photo_id' => $photo_ids[0],
'photo_ids' => join(', ', @photo_ids)
}
);
$response->{success} or
die "Could not add photos to set : $response->{error_message} \n";
print " finished.\n";
}