четверг, 11 августа 2016 г.

GSM modem woes

I've had a task to send SMS messages over a bunch of GSM USB modems.

Gnokii proved to work well with Nokia phones only, so I have written a custom perl script to send AT commands directly.

It took some time to program encoding the SMS in packet mode, but the main difficulty was unreliability of the modems and/or USB subsystem of linux.

Sometimes /dev/ttyUSBx devices stopped responding. Unplugging the modems by hand seemed unworthy thing to do, so I searched the internet for solutions.

At first I have found usbreset.c and fortunately it could recover the /dev/ttyUSBx devices, but it required /dev/bus/usb/... path to work on, so I searched again and found a method of mapping ttyUSB to /dev/bus/usb here.

Then I have added the following function to my perl script and called it during modem initialization if the modem did not reply to the first AT command.

sub usbreset($) {
        my ($device)=@_;
        use File::Slurp;
        require 'sys/ioctl.ph';
        my ($rdev)=(stat($device))[6];
        return if !$rdev;
        my ($major,$minor)=($rdev>>8,$rdev&255);
        my $path="/sys/dev/char/$major:$minor/../../../..";
        my $bus=read_file("$path/busnum");
        my $dev=read_file("$path/devnum");
        my $ctl=sprintf('/dev/bus/usb/%03d/%03d',$bus,$dev);
        open my $fd,'>',$ctl || return;
        # USBDEVFS_RESET from linux/usbdevice_fs.h
        my $res=ioctl($fd,_IO(ord('U'),20),0);
        return if !defined $res;
        return 1;

I'll have to monitor the modems for some time to find out if there are other problems with them.

Feel free to use this piece of code if you like (public domain).

P.S. using a quality USB hub solved the problem completely.