--- /dev/null
+# Device::Nokia
+# Author: Tim Pope
+
+# A Perl class to interface GSM devices as AT modems
+# Basically just a few enhancements to Device::Gsm
+
+package Device::Nokia;
+$Device$Revision: 1.1 $ =~ /(\d+)\.(\d+)/;
+
+use strict;
+use Device::Gsm;
+
+@Device::Nokia::ISA = ('Device::Gsm');
+
+#
+# Who is the manufacturer of this device?
+#
+sub manufacturer() {
+ my $self = shift;
+ my($ok, $man);
+
+ # Test if manufacturer code command is supported
+ if( $self->test_command('+CGMI') ) {
+
+ $self->atsend( 'AT+CGMI' . Device::Modem::CR );
+ ($ok, $man) = $self->parse_answer();
+
+ $self->log->write('info', 'manufacturer of this device appears to be ['.$man.']');
+
+ }
+
+ return $man || $ok;
+
+}
+#
+# What is the model of this device?
+#
+sub model() {
+ my $self = shift;
+ my($code, $model);
+
+ # Test if manufacturer code command is supported
+ if( $self->test_command('+CGMM') ) {
+
+ $self->atsend( 'AT+CGMM' . Device::Modem::CR );
+ ($code, $model) = $self->parse_answer();
+
+ $self->log->write('info', 'model of this device is ['.$model.']');
+
+ }
+
+ return $model || $code;
+}
+
+#
+# Get mobile phone indicators
+#
+sub indicators() {
+ my $self = shift;
+ my($supported,$values,%results);
+
+ # Test if manufacturer code command is supported
+ if( $self->test_command('+CIND') ) {
+ $self->atsend( 'AT+CIND=?' . Device::Modem::CR );
+ ($_, $supported) = $self->parse_answer();
+ $supported =~ s/^\+CIND: //;
+ $self->atsend( 'AT+CIND?' . Device::Modem::CR );
+ ($_, $values) = $self->parse_answer();
+ $values =~ s/^\+CIND: //;
+ #@values = split (/,/, $values);
+ foreach (split (/,/, $values)) {
+ $supported =~ s/\("([^"]*)",\([^)]*\)\),?//;
+ $results{$1} = $_;
+ }
+ $self->log->write('info', 'Indicator data retrieved (' . scalar(keys(%results)) . 'values)');
+
+ }
+ return %results;
+}
+
+#
+# Get mobile phone battery strength
+#
+sub battery_strength() {
+ my $self = shift;
+ # Error code, dBm (signal power), bit error rate
+ my($code, $strength, $line_power);
+
+ # Test if signal quality command is implemented
+ if( $self->test_command('+CBC') ) {
+
+ $self->atsend( 'AT+CBC' . Device::Modem::CR );
+ ($code, $strength) = $self->parse_answer();
+
+ if( $strength =~ /\+CBC: (\d+),(\d+)/ ) {
+
+ ($line_power, $strength) = ($1, $2);
+
+ $self->log->write('info', 'battery strength is ['.$strength.'], line power ['.$line_power.']');
+
+ } else {
+
+ $self->log->write('warn', 'cannot obtain battery strength');
+
+ }
+
+ } else {
+
+ $self->log->write('warn', 'battery strength command not supported!');
+
+ }
+
+ return wantarray ? ($line_power, $strength) : $strength;
+
+}
+
+1;
+
+__END__
--- /dev/null
+#!/usr/bin/perl
+# Author: Tim Pope
+
+# Monitors a bluetooth mobile phome for calls. You'll need to bind rfcomm1 to
+# your mobile phone's SP service. You'll also need my Device::Nokia module
+# (the name is misleading, it's not Nokia specific).
+
+use strict;
+use Device::Nokia;
+my $number;
+my %status;
+
+my $gsm = new Device::Nokia( port => '/dev/rfcomm1', log => 'file,/dev/null');
+
+$SIG{INT} = 'death';
+$SIG{TERM} = 'death';
+$SIG{QUIT} = 'death';
+
+sub initialize {
+ my $gsm=shift;
+ $gsm->connect() || return 0;
+ $gsm->atsend( 'AT+CLIP=1' . Device::Modem::CR );
+ $gsm->answer();
+ return 1;
+}
+
+initialize($gsm) || die "Could not initialize modem: $!";
+
+daemonize() if (shift eq "-d");
+
+while(1) {
+%status=("is_active"=>1);
+while($status{"is_active"} ne 0) {
+ for(my $i=0;$i<8;$i++) {
+ sleep 1;
+ $number = wait_for_ring();
+ if($number) {
+ $status{"number"} = $number;
+ output_status(%status);
+ ring($number);
+ last;
+ } elsif(!defined($number)) { $status{"is_active"}=0; last; };
+ }
+ my %newstatus=gather_data($gsm);
+ ring() if($newstatus{"call"}!=0 && $status{"call"}!=0);
+ foreach (keys %newstatus) {
+ $status{$_} = $newstatus{$_} if(defined ($newstatus{$_}));
+ }
+ undef $status{"number"} if (!$number && $status{"callsetup"}==0 && $status{"call"}==0);
+ output_status(%status);
+}
+$gsm->disconnect();
+#print "Chillin'...\n";
+output_status(is_active => 0);
+do {sleep 60}
+until(initialize($gsm));
+}
+
+sub wait_for_ring {
+ local $_;
+ eval {
+ local $SIG{ALRM} = sub { die "alarm\n" };
+ alarm 5;
+ $_ = $gsm->answer("\\+CLIP: \"[0-9]+\",[0-9]+\$", 30);
+ alarm 0
+ };
+ if($@) {
+ die unless $@ eq "alarm\n";
+ return undef;
+ } else {
+ m/CLIP: "([0-9]+)",/;
+ return "$1";
+ }
+}
+
+sub ring {
+ system($ENV{"HOME"} . "/bin/phone-call " . $_[0]);
+}
+
+sub gather_data {
+ my %data;
+ my $gsm=shift;
+ eval {
+ local $SIG{ALRM} = sub { die "alarm\n" };
+ alarm 15;
+ %data=$gsm->indicators();
+ my ($first, $second) = $gsm->battery_strength();
+ $data{"source"}=$first;
+ $data{"battery"}=$second;
+ ($first, $second) = $gsm->signal_quality();
+ $data{"signal"}=$first;
+ alarm 0;
+ };
+ if($@) {
+ die unless $@ eq "alarm\n";
+ return (is_active => 0);
+ } else {
+ $data{"is_active"}=$gsm->is_active() && $data{"signal"} && 1 || 0;
+ return %data;
+ }
+}
+
+sub output_status {
+ my %status = @_;
+ open STATUS, ">/tmp/.phone-status.new" || die $!;
+ foreach my $indicator (sort keys %status) {
+ print STATUS "$indicator=" . $status{$indicator} . "\n";
+ };
+ close STATUS;
+ rename "/tmp/.phone-status.new", "/tmp/.phone-status" || die $!;
+}
+
+
+sub daemonize {
+ chdir "/";
+ my $pid=fork();
+ if($pid) {
+ exit(0)
+ }
+ elsif(defined($pid))
+ {
+ close STDIN;
+ close STDOUT;
+ close STDERR;
+ }
+ else { exit(1); }
+}
+
+sub death {
+ $gsm->disconnect() if($gsm);
+ unlink "/tmp/.phone-status.new", "/tmp/.phone-status";
+ exit(0);
+}