POP3 Email Checker (08/01/2006)
The other night I came across a 7-segment LED display and decided to interface it to a parallel port. I added a button as well. The 7-segment LED lines (each leg of the display plus the dot LEDs) are connected to the parallel port data pins (D0-D7). I have the button hooked up to nInitialize (bidirectional) and nAck (input only). I’ve never done a parallel port interface project before, so I figured this would be a good start.
I wrote some quick prototype software in Perl, of all languages. It requires Device::ParallelPort for parallel port access, which for some reason didn’t work well with writing data bytes, so I had to resort to doing everything bit by bit in software. For the switch, I bring nInitialize down, and poll nAck for changes. When nAck goes low, the switch has been pressed.
Actually the idea from the start was to make a New Message email checker on my desk. I’d like to be able to press a button and get a report of new email messages on the LED display. I achieved exactly that with the Mail::POP3Client module for perl. It works well, but for some reason I couldn’t get IO::Socket::SSL working in Windows ActiveState perl, so it doesn’t work with POP3 servers where SSL is required (Gmail). Other than that, it works perfectly.
If there are more than 9 new messages, it displays a 9 with the dot, otherwise it shows the number of new messages on the LED display. When it is connecting and checking the email, only the dot is displayed. When there is an error connecting or retrieving the number of new messages, an ‘E’ character with a dot is displayed. I would record a mini video demo but I just can’t seem to find a parallel port cable extension.
Code
# Vanya A. Sergeev <vsergeev@gmail.com>
# 08/01/2006
# Checks a POP3 account and displays the number of new messages on a
# 7-segment LED display, interfaced through the PC parallel port.
#
# Note: set_byte()/set_data() function of Device::ParallelPort was not
# working for me, so I had to manually set/check bits on the parallel port.
use strict;
use Device::ParallelPort;
use Mail::POP3Client;
############### CHANGE THESE ###############
my $username = '';
my $password = '';
my $hostname = '';
my $hostport = '';
############################################
# Digits coded in binary for the hardware output to the LED display
# Consists of characters 0 through 9, and 'E'
my @hwdigits = (0b00111111, 0b00110000, 0b01011011, 0b01001111, 0b01110010, 0b01101101, 0b01111101, 0b00000111, 0b01111111, 0b01101111, 0b01111001);
# Make parallel port driver object
my $pport = Device::ParallelPort->new();
# Set nInitialize bit to 0, this lets the switch pull down the nAck bit of
# the parallel port when pressed.
$pport->set_bit(18, 0);
# Main program execution loop
while (1) {
# Clear screen, set busy to show email is being checked, get number of new messages
clear_display();
set_busy();
my $newmessages = check_mail();
# If there are more than 9 new messages, display the 9 digit and the dot,
# otherwise display how many messages there are, and clear the dot.
# If an error occured ($newmessages is -1), display an 'E' character with the dot.
print STDERR "$newmessages new messages.\n";
if ($newmessages > 9) {
set_digit(9);
} elsif ($newmessages == -1) {
set_digit(10);
} else {
set_digit($newmessages);
clear_busy();
}
# Wait until button to check email is depressed again...
while ($pport->get_bit(14) == 1) { }
# Sleep to prevent button bouncing
sleep 1;
}
# Connect to the POP3 server with login details, and return the number of new messages.
sub check_mail {
# Make new pop3client object and connect
my $pop3client = new Mail::POP3Client(HOST => $hostname, PORT => $hostport);
$pop3client->User($username);
$pop3client->Pass($password);
$pop3client->Connect() >= 0 || die $pop3client->Message();
# Get number of new messages
my $newmessages = $pop3client->Count();
# Close pop3client object
$pop3client->Close();
# Return number of new messages
$_ = $newmessages;
}
# Clear the data bits of the parallel port (clears LED display)
sub clear_display {
# For some reason $pport->set_byte(0,0); leaves D4 and D5 on, but
# manual set_bit() calls work fine.
for (my $i = 0; $i < 8; $i++) {
$pport->set_bit($i, 0);
}
}
# Set the dot of the LED Display
sub set_busy {
$pport->set_bit(7, 1);
}
# Clear the dot of the LED Display
sub clear_busy {
$pport->set_bit(7, 0);
}
# Sets a certain digit on the LED Display
sub set_digit {
# Grab digit argument
my($digit) = @_;
# Go bit by bit through the digit encoded in binary for the hardware LEDs
# Toggle bit on parallel port when necessary.
for (my $i = 0; $i < 7; $i++) {
if (($hwdigits[$digit] & (1 << $i)) == 0) {
$pport->set_bit($i, 0);
} else {
$pport->set_bit($i, 1);
}
}
}