#!/usr/bin/perl -w ############################################################################### # THIS SOFTWARE IS FREE SOFTWARE! IT IS LICENCED UNDER THE GNU PUBLIC LICENCE # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ############################################################################### # (c) Hartmut Schimmel, 10.02.2008 # 07.10.2007 sml first release # 10.02.2008 sml complete rewrite for better code readability # 02.03.2008 sml added write settings support # 09.03.2008 sml added write wav ssupport # TODO # USB device Blacklist: /dev/usbdev6.4_ep81 use IO::Handle; use Fcntl; use Getopt::Std; use strict; STDOUT->autoflush(1); ############################################################################### # Settings ############################################################################### # Names of the wav-Files, they are expected exactly in this order my @WavFiles = qw( battery_low.wav BT_close.wav BT_open.wav Error_Beep.wav GPS_search.wav GPS_search_finished.wav OK_Beep.wav OK1_Beep.wav ); # Dirs, where we should look for the wav-Files my @WavDirs = ( "$ENV{'PWD'}", "$ENV{'HOME'}/wav" ); ############################################################################### # Declarations and definitions ############################################################################### use constant NULL => chr 0; use constant MEMSIZE => 3997680; use constant SERIAL_MODE => "cs8 raw 115200"; use constant TIMEOUT => 1; sub CheckForStty(); sub InstallAlarmHandler(); sub AutoDetectUSBDeviceNames(); sub OpenAndTestUSBDevices(@); sub ConfigureSerialDevice($); sub OpenDevice($); sub GetDeviceInfo(); sub GetDeviceSettings(); sub PrintDeviceSettings(); sub GetMemoryDump(); sub FindWavFiles(); sub CreateWavBin($); sub CreateConfigBin($$$$$$$); sub WriteConfigToDevice($); sub WriteDumpToFile($$); sub CreateSrFileName(); sub EraseDeviceMemory(); sub WriteDataToDevice($); sub WriteStringToDevice($); sub ReadDataFromDevice(); sub ReadStringFromDevice(); sub Usage(); sub CloseDevice(); my %o; ( my $prg = $0 ) =~ s/^.*\/([^\/]+)$/$1/g; ############################################################################### # Does the given options make sense ? ############################################################################### Usage() unless getopts('asd:fio:ew:', \%o); Usage() unless ( defined($o{a}) or defined($o{s}) or defined($o{d}) or defined($o{w})); die "It does not make sense to combine the options -a and -d\n" if ((defined $o{a}) and (defined $o{d})); die "It does not make sense to combine the options -s and -d\n" if ((defined $o{s}) and (defined $o{d})); die "It does not make sense to combine the options -w and -s\n" if ((defined $o{w}) and (defined $o{s})); die "It does not make sense to combine the options -w and -i\n" if ((defined $o{w}) and (defined $o{i})); die "It does not make sense to combine the options -w and -e\n" if ((defined $o{w}) and (defined $o{e})); die "It does not make sense to combine the options -w and -o\n" if ((defined $o{w}) and (defined $o{o})); die "Option -f does make sense only together with option -w\n" if ((defined $o{f}) and not (defined $o{w})); die "Option -e (erase) is not accepted without memory reading for security\n" . "reasons. So combine -e always with -a or -d \n" if ( (defined $o{e}) and not ((defined $o{d}) or (defined $o{a}))); ############################################################################### # Main ############################################################################### CheckForStty(); InstallAlarmHandler(); my @device = $o{d} ? $o{d} : AutoDetectUSBDeviceNames(); OpenAndTestUSBDevices( @device); if ( defined $o{s} ) { CloseDevice(); print "\nAll done.\n"; exit 0; # exit here if only scan was wanted } PrintDeviceSettings(); if ( defined $o{i} ) { CloseDevice(); print "\nAll done.\n"; exit 0; # exit here if only info was wanted } # Special operation: Write settings if ( defined $o{w} ) { # option -w correct used ? if ( $o{w} =~ /^(\w+)=(\w+)$/ ) { my ( $param, $value ) = ( $1, $2 ); my ( $time, $dist, $sens, $tag, $vMin ) = GetDeviceSettings(); my $bin = CreateConfigBin( $time, $dist, $sens, $tag, $vMin, $param, $value); $bin .= CreateWavBin( FindWavFiles() ); WriteConfigToDevice( $bin ); } else { Usage() }; CloseDevice(); print "\nAll done.\n"; exit 0; # exit here if writing settings was wanted } # Normal operation: Read memory WriteDumpToFile( defined $o{o} ? $o{o} : CreateSrFileName(), GetMemoryDump() ); EraseDeviceMemory() if ( defined $o{e} ); CloseDevice(); print "\nAll done.\n"; exit 0; ############################################################################### ############################################################################### ############################################################################### # Subroutines ############################################################################### ############################################################################### ############################################################################### ############################################################################### # FindWavFiles ############################################################################### sub FindWavFiles() { my $d; print "\nSearching wav-files in:\n"; foreach my $Dir ( @WavDirs ) { print " $Dir:\n"; if ( opendir DIR, $Dir ) { while (defined( my $FileInDir = readdir DIR )) { foreach my $Wav ( @WavFiles ) { next unless $FileInDir eq $Wav; $d->{"$Wav"} = $Dir; print " Found $Wav\n"; last; } } closedir DIR; } else { warn "Error while opening dir $Dir: $!\n"; } } @_ = keys %{$d}; if ( $#WavFiles == $#_ ) { print "Found all wav-files\n"; } else { die "Found ", $#_ + 1, " wav-files, but it should be ", $#WavFiles + 1, "\nThe wav-files should be in one of the folders noted above.\n", "Abort\n"; } return $d; } ############################################################################### # CreateWavBin ############################################################################### sub CreateWavBin($) { my $Dir = shift; my $WavBin; # lt. Hexdump von Set_Log_Data.exe max. 128 kByte mit oder ohne Config ? # lt. Hexdump von Upgrade(BTCD110-V2_5).exe max. 1 MByte Wav-Daten foreach my $Wav ( @WavFiles ) { open WAV, "$Dir->{$Wav}/${Wav}" or die "Error while reading $Dir->{$Wav}/${Wav}: $!\n"; while ( read WAV, $_, 1 ) { $WavBin .= $_; } close WAV; } return ( $WavBin); } ############################################################################### # CreateConfigBin ############################################################################### sub CreateConfigBin($$$$$$$) { my ( $time, $dist, $sens, $tag, $vMin, $param, $value ) = @_; $param = lc $param; # overwrite with new settings, if available if (( $param eq 't') or ( $param eq 'time' )) { $time = sprintf( "%d", $value); } elsif (( $param eq 'd') or ( $param eq 'distance' )) { $dist = sprintf( "%d", $value); } elsif (( $param eq 's') or ( $param eq 'sensitivity' )) { $sens = sprintf( "%d", $value); } elsif (( $param eq 'm') or ( $param eq 'marker' )) { $tag = sprintf( "%d", $value); } elsif (( $param eq 'v' ) or ( $param eq 'vmin' )) { $vMin = sprintf( "%d", $value / 1.852); } else { die "Unknown option $param - Abort\n"; } # time and dist are exclusive $dist= 0xFFFFFFFF if $param eq 't'; $time = 0xFFFFFFFF if $param eq 'd'; # check, if values make sense unless ( defined $o{f} ) { die "Time should be greater 0\n" if ($time < 0); die "Distance should be greater 0\n" if ($dist < 0); die "Senisivity should be 0...3\n" if (($sens < 0) or ($sens > 3)); die "Tag should be 0 or 1\n" if (( $tag < 0) or ( $tag > 1)); die "Velosity should be 0...36 km/h\n" if (($vMin < 0) or ($vMin > 20)); } # Time : Byte 4-1: unsigned 32 bit # Distance : Byte 8-5: unsigned 32 bit # Sensitivity: Byte 9: 2-high, 1-middle, 3-low, 0-disable # Tag : Byte 25: 0-off, 1-on # v_min : Byte 26: 0 km/h = 0x00 Knoten ( km/h = Knoten * 1.852) # max. 36 km/h = 0x14 (20 Knoten), 0xFF = unused return( pack( "L L C A15 C C A870", $time, $dist, $sens, chr(0xFF) x 15, $tag, $vMin, chr(0xFF) x 870)); } ############################################################################### # WriteConfigToDevice ############################################################################### sub WriteConfigToDevice($) { print "\nWriting settings into the device\n"; print " Erasing flash\n"; # 0x55 0xAA 0x76 0x33 0x01 0x00 0x # how the chk_sum is calculated ? # however, chk_sum error does not matter # # device answers not before at least 78720 bytes are sent, but so much data # is only needed, if the wav-files should be updated. For config only update # no answer is needed WriteStringToDevice( chr(0x55) . chr(0xAA) . chr(0x76) . chr(0x33) . chr(0x01) . NULL . NULL ); sleep 2; WriteDataToDevice( shift ); # device has to be closed after config writing or it not responds sensefull return 1; } ############################################################################### # CreateSrFileName ############################################################################### sub CreateSrFileName() { my $now = time(); my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime( $now); $mon++; $year += 1900; return sprintf( "iTU4l_%04d%02d%02d%02d%02d%02d.sr", $year, $mon, $mday, $hour, $min, $sec); } ############################################################################### # WriteDumpToFile ############################################################################### sub WriteDumpToFile($$) { my $file = shift; my $data = shift; print "Writing ", length( $data), " Bytes to $file\n"; open OUTFILE, ">$file" or die "Error while writing $file: $!\n"; print OUTFILE $data; close OUTFILE; return 1; } ############################################################################### # EraseDeviceMemory ############################################################################### sub EraseDeviceMemory() { print "\nErasing memory\n"; WriteStringToDevice( chr(0x61) . chr(0xB6) . NULL . NULL . NULL . NULL . NULL ); if ( ReadStringFromDevice() ne 'WP Update Over' ) { print " Unexpected answer\n"; } return 1; } ############################################################################### # GetMemoryDump ############################################################################### sub GetMemoryDump() { print "\nReading memory\n"; WriteStringToDevice( chr(0x60) . chr(0xB5) . NULL . NULL . NULL . NULL . NULL ); my $dump = ReadDataFromDevice(); die < /dev/null'); We need the stty tool to set mode 8N1 raw 115200 to the serial device. It should be available on most common Linux/Unix systems. However here it is missing. Please install it according to your distributions rules. For Debian and Ubuntu it is included in the package 'coreutils'. To install it you have to type as root: apt-get install coreutils Please tell the author of $prg, how stty is installed on other distributions than Debian and Ubuntu. EOF } ############################################################################### # Install an alarm handler to interrupt a pending access to the device ############################################################################### sub InstallAlarmHandler() { $SIG{ALRM} = sub { die "timeout\n" }; # \n required } ############################################################################### # Autodetect USB device name magic ;-) ############################################################################### sub AutoDetectUSBDeviceNames() { print "\nFound USB devices:\n"; # Scan directories which typical contain USB device files foreach my $dir ( qw( /dev /dev/usb/tts )) { if ( opendir DH, $dir ) { while ( defined( $_ = readdir DH)) { # /dev/usb/tty device files all should match if ( $dir eq '/dev/usb/tts' ) { push @_, "$dir/$_"; print " $dir/$_\n"; } # other devices names should contain at least USB else { next unless /^(.*USB.*\d+).*$/i; push @_, "$dir/$1"; print " $dir/$1\n"; } } close DH; } } die <= 0; No USB devices found. To find them please follow the instructions on http://iTU4l.schimmelnetz.de/usb.html Good luck. EOF return @_; } ############################################################################### # OpenAndTestUSBDevices ############################################################################### sub OpenAndTestUSBDevices(@) { print "\nTrying to talk to the USB device\n"; my $device_found = 0; foreach my $device ( sort shift) { unless ( ConfigureSerialDevice( $device) ) { print " Error while setting $device to " . SERIAL_MODE . "\n"; next; } print " Device $device set to " . SERIAL_MODE . "\n"; unless ( OpenDevice( $device) ) { print " Error during access to $device - assuming that this\n" . " device is not the right one\n\n"; next; } print " Opened $device\n"; # try to Initialize the logger WriteStringToDevice( "WP AP-Exit" . NULL ); # close possibly pending session WriteStringToDevice( "W'P Camera Detect" . NULL ); # init new session my $name = ReadStringFromDevice(); print " Device $device answered with \'$name\'\n"; if ( $name eq 'WP GPS+BT' ) { print " *** fine, $device is it ***\n\n"; $device_found = 1; last; } else { print " *** unexpected, assuming that this device is not the right " . "one\n\n"; next; } } die <autoflush(1); # not for sysopen/syswritr/sysread return 1; } ############################################################################### # CloseDevice ############################################################################### sub CloseDevice() { WriteStringToDevice( "WP AP-Exit" . NULL ) or die "Error while writing to device: $!\n"; close SERIAL; } ############################################################################### # ReadDataFromDevice ############################################################################### sub ReadDataFromDevice() { my $data; use constant BLK_SIZE => 64; eval { my $last_kByte = 0; while (1) { alarm( TIMEOUT ); sysread( SERIAL, $_, BLK_SIZE); alarm(0); $data .= $_; if ( int( length( $data) / 1024) - BLK_SIZE + 1 > $last_kByte) { printf " % 4d kByte\r", int( length( $data) / 1024); $last_kByte = int( length( $data) / 1024); } } }; if ($@) { die "Error while reading from device: $!\n" unless $@ eq "timeout\n"; } return $data; } ############################################################################### # ReadStringFromDevice ############################################################################### sub ReadStringFromDevice() { my $string; eval { alarm( TIMEOUT ); while (1) { sysread( SERIAL, $_, 1); last if $_ eq NULL; $string .= $_; } alarm(0); }; if ($@) { die "Error while reading from device: $!\n" unless $@ eq "timeout\n"; } return $string; } ############################################################################### # WriteDataToDevice (16 Byte-blockwise) ############################################################################### sub WriteDataToDevice( $ ) { my $data = shift; my $bytes_wrote; for ( my $i = 0; $i < length( $data); $i += 16 ) { $bytes_wrote += syswrite SERIAL, $data, 16, $i; print " Wrote $bytes_wrote bytes\r"; } print "\n"; return 1; } ############################################################################### # WriteStringToDevice ############################################################################### sub WriteStringToDevice( $ ) { syswrite SERIAL, shift or die "Error while writing to device: $!\n"; return 1; } ############################################################################### # Usage ############################################################################### sub Usage() { die < USB device to use, if the automatic detection does not work, includes memory reading -i only print out information about the logger settings -o write output to this file instead of the default file name, which is generated from the actual system time -e erase logger data, for security only possible together with reading the memory to disk, always combine with -d or -a -w

= write settings into the device. p is the setting parameter and v is the value for it. It is only possible to write one parameter at once. So you have to call the tool multiple times if you want to write more than one setting. Use with care and on your own risk ! Be warned, you can destroy your device with this option ! p Parameters Values -------------------------------------------------------- t or time Time-Step 0... sec d or distance Distance-Step 0... meter s or sensitivity Sensitivity 2-high, 1-middle, 3-low, 0-disable m or marker Marker (Tag) 0-off, 1-on v or vmin Velosity min. 0...36 km/h For writing settings you also need the wav-files which are played by the logger when he talks to you. Copy them to one of the following folders, because the are exepted there by this programm: \$HOME/wav or current directory -f force - skip sense checks for config values to write Use with care and on your own risk ! Be warned, you can destroy your device with this option ! Example: $prg -s # scan $prg -d /dev/ttyUSB1 # use /dev/ttyUSB1 as device $prg -a -i # print information about logger settings $prg -o my_gps_log.sr # write to file named "my_gps_log.sr" $prg -e # erase all track data on the logger $prg -a -w t=5 # write setting: Time-Step 5 sec $prg -a -w time=5 # the same $prg -a -w d=1000 # write setting: Distance-Step 1000 meter $prg -a -w distance=1000 # the same $prg -a -w s=2 # write setting: Sensitivity high $prg -a -w sensitivity=2 # the same $prg -a -w m=1 # write setting: Marker (Tag) on $prg -a -w marker=1 # the same $prg -a -w v=5 # write setting: Minimal Velosity 5 km/h $prg -a -w vmin=5 # the same however, in most cases it should do what you want if you only type $prg -a This software is published under the GPL V2.0 EOF }