CUFP
stevieb
<p>Well, I've finally released [metamod://RPi::WiringPi]. This uses the [metamod://WiringPi::API] wrapper that wraps the C-based [http://wiringpi.com|wiringPi] Raspberry Pi hacking software.</p>
<p>Anyway, I thought I'd throw something together that's kind of silly to play around with it. A couple of points: a) I know this isn't the proper way to web-scrape, it's just an example ;) b) forgive the global variables. The interrupt code in wiringPi library does not allow you to pass in any parameters, so until I submit a possible patch, globals are all I have. This was not meant to be prod code :D</p>
<p>The following code, infinitely looping every 60 seconds, scrapes my number of posts and XP from PerlMonks (in a *very* crude way), collects up the current time, then prints the data out onto an LCD display attached to my Pi:</p>
<c>
p: 1293 18:15
x: 10361
</c>
<p>Number of posts and then the time on the top line, XP on the bottom.</p>
<p>We introduce a button connected to a pin, when pressed, triggers an interrupt, and the interrupt handler rewrites the bottom line with the amount of XP remaining until my next PM level, instead of current XP (changes from <c>x: 10361</c> to <c>r: 1638</c>. Every button press flips this back and forth.</p>
<p>Pics: [https://github.com/stevieb9/p5-rpi-wiringpi/blob/master/test/images/before.jpg|before button press], and [https://github.com/stevieb9/p5-rpi-wiringpi/blob/master/test/images/after.jpg|after button press].</p>
<c>
use warnings;
use strict;
use LWP::Simple;
use RPi::WiringPi;
use RPi::WiringPi::Constant qw(:all);
# catch a sigint. This allows us to
# safely exit the while() loop and perform
# emergency LCD/pin cleanup. The main class
# catches die()
my $continue = 1;
$SIG{INT} = sub { $continue = 0; };
# initialize a Raspberry Pi object using the
# BCM GPIO pin numbering scheme
my $pi = RPi::WiringPi->new(setup => 'gpio');
# prepare and initialize the LCD
my $lcd = $pi->lcd;
# the following list of args looks daunting, but
# it's very straightforward, and the docs are
# pretty clear
my %args = (
cols => 16,
rows => 2,
bits => 4,
rs => 21,
strb => 16,
d0 => 12,
d1 => 25,
d2 => 24,
d3 => 23,
d4 => 0,
d5 => 0,
d6 => 0,
d7 => 0,
);
$lcd->init(%args);
# set up a pin with a button, and set an
# interrupt handler to do something when
# the button is pressed
my $button_pin = $pi->pin(26);
# we're going to interrupt when the pin
# goes LOW (off), so we'll pull it HIGH
# with the built-in pull up resistor.
# only when the button is pressed, will the
# pin briefly go LOW, and this triggers
# an interrupt
$button_pin->pull(PUD_UP);
# the second arg to interrupt_set() is the
# name of the perl sub I've defined below
# that I want handling the interrupt
$button_pin->interrupt_set(
EDGE_FALLING,
'button_press'
);
my $button_presses = 0;
my ($posts, $xp, $next);
while ($continue){
my (
$sec,$min,$hour,$mday,$mon,
$year,$wday,$yday,$isdst
) = localtime();
$min = "0$min" if length $min == 1;
# get my post and xp count from PM
($posts, $xp) = perlmonks();
# manually get xp needed for next level
$next = 12000 - $xp;
# set the LCD cursor to top row, first
# column, and print my num of PM posts
$lcd->position(0, 0);
$lcd->print("p: $posts");
# sub for bottom line, because the
# code needs to be called also in our
# interrupt handler. What's printed depends
# on the cumulative number of button presses
display_xp();
# on top row of the LCD at column 12,
# we print the time
$lcd->position(11, 0);
$lcd->print("$hour:$min");
print "$hour:$min posts: $posts, " .
"xp: $xp, next lvl: $next\n";
# rinse, repeat every minute
sleep 60;
}
# wipe the LCD clean
$lcd->clear;
# reset pins to default state
$pi->cleanup;
sub button_press {
# this is the interrupt handler
print "button pressed\n";
$button_presses++;
display_xp();
}
sub display_xp {
# this is the manager for the bottom LCD
# row. It'll update things even when the
# main program is sleeping in the while()
# loop
# print XP for 0 and even number of button
# presses, and print XP remaining to next level
# on odd number of presses
$lcd->position(0, 1);
if ($button_presses % 2){
$lcd->print("r: $next");
}
else {
$lcd->print("x: $xp");
}
}
sub perlmonks {
my $url = "http://perlmonks.org/?node_id=789891";
my $page = get $url;
my @content = split /\n/, $page;
my ($xp, $posts);
my $i = 0;
for (@content){
if (/Experience:/){
my $line = $i;
$line += 2;
$xp = $1 if $content[$line] =~ /(\d+)/;
}
if (/Writeups:/){
my $line = $i;
$line += 2;
$posts = $1 if $content[$line] =~ />(\d+)/;
}
$i++;
}
return ($posts, $xp);
}
</c>
<p>Here's the code without all of the comments....</p>
<readmore>
<c>
use warnings;
use strict;
use LWP::Simple;
use RPi::WiringPi;
use RPi::WiringPi::Constant qw(:all);
my $continue = 1;
$SIG{INT} = sub { $continue = 0; };
my $pi = RPi::WiringPi->new(setup => 'gpio');
my $lcd = $pi->lcd;
my %args = (
cols => 16,
rows => 2,
bits => 4,
rs => 21,
strb => 16,
d0 => 12,
d1 => 25,
d2 => 24,
d3 => 23,
d4 => 0,
d5 => 0,
d6 => 0,
d7 => 0,
);
$lcd->init(%args);
my $button_pin = $pi->pin(26);
$button_pin->pull(PUD_UP);
$button_pin->interrupt_set(
EDGE_FALLING,
'button_press'
);
my $button_presses = 0;
my ($posts, $xp, $next);
while ($continue){
my (
$sec,$min,$hour,$mday,$mon,
$year,$wday,$yday,$isdst
) = localtime();
$min = "0$min" if length $min == 1;
($posts, $xp) = perlmonks();
$next = 12000 - $xp;
$lcd->position(0, 0);
$lcd->print("p: $posts");
display_xp();
$lcd->position(11, 0);
$lcd->print("$hour:$min");
print "$hour:$min posts: $posts, " .
"xp: $xp, next lvl: $next\n";
sleep 60;
}
$lcd->clear;
$pi->cleanup;
sub button_press {
print "button pressed\n";
$button_presses++;
display_xp();
}
sub display_xp {
$lcd->position(0, 1);
if ($button_presses % 2){
$lcd->print("r: $next");
}
else {
$lcd->print("x: $xp");
}
}
sub perlmonks {
my $url = "http://perlmonks.org/?node_id=789891";
my $page = get $url;
my @content = split /\n/, $page;
my ($xp, $posts);
my $i = 0;
for (@content){
if (/Experience:/){
my $line = $i;
$line += 2;
$xp = $1 if $content[$line] =~ /(\d+)/;
}
if (/Writeups:/){
my $line = $i;
$line += 2;
$posts = $1 if $content[$line] =~ />(\d+)/;
}
$i++;
}
return ($posts, $xp);
}
</c>
</readmore>