Added bluetooth phone monitor
authorTim Pope <code@tpope.net>
Fri, 23 Jul 2004 01:33:28 +0000 (01:33 +0000)
committerTim Pope <code@tpope.net>
Fri, 23 Jul 2004 01:33:28 +0000 (01:33 +0000)
perl/Device/Nokia.pm [new file with mode: 0755]
perl/mobile-phone-monitor [new file with mode: 0755]

diff --git a/perl/Device/Nokia.pm b/perl/Device/Nokia.pm
new file mode 100755 (executable)
index 0000000..5a58914
--- /dev/null
@@ -0,0 +1,119 @@
+# 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__
diff --git a/perl/mobile-phone-monitor b/perl/mobile-phone-monitor
new file mode 100755 (executable)
index 0000000..246cad5
--- /dev/null
@@ -0,0 +1,133 @@
+#!/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);
+}