Skip to content

Instantly share code, notes, and snippets.

@barijaona
Created January 23, 2021 17:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save barijaona/da26156d04ca27fc633e80a367eab695 to your computer and use it in GitHub Desktop.
Save barijaona/da26156d04ca27fc633e80a367eab695 to your computer and use it in GitHub Desktop.
Perform USSD requests through USB modem
#!/usr/bin/env perl
#
# Send USSD requests
#
# Authored by Barijaona Ramaholimihaso
# https://gist.github.com/barijaona
# Loosely derived from https://gist.github.com/vshymanskyy/5085138
#
use strict;
use warnings;
use Getopt::Std;
use Device::SerialPort;
use 5.8.0; # Encode::GSM0338 only vailable since 5.8
use Encode qw/encode decode/;
# defaults
our ($opt_p, $opt_v, $opt_h);
my $USAGE = <<__EOU;
Usage: $0 -p io_port [-hv] [ussd_msg]
Description:
Send and receive USSD messages using GSM/UMTS USB modem.
Options:
-p port Port to send and receive.
-h Print this help.
-v Be verbose.
Examples:
Linux or macSOS: $0 -p /dev/ttyUSB2 *100#
Win32: $0 -p COM6 *100#
__EOU
$Getopt::Std::STANDARD_HELP_VERSION = 1;
sub HELP_MESSAGE { print "$USAGE\n"; exit; }
sub VERSION_MESSAGE { print "USSD v0.1\n";};
getopts ('p:hv');
HELP_MESSAGE() if (defined($opt_h) or not defined($opt_p));
print "Opening $opt_p\n" if $opt_v;
my $port = new Device::SerialPort($opt_p) || die "Can't open $opt_p: $^E\n";
$port->baudrate(115200);
$port->databits(8);
$port->stopbits(1);
$port->parity("none");
$port->handshake("none");
$port->write_settings or die;
$port->are_match("OK\r\n", "ERROR\r\n");
$port->write("ATZE0+CSCS=\"GSM\"\n"); # reset modem, no echo, GSM encoding
sleep(1);
$port->lookfor();
$port->write("AT+CUSD=2\n"); # cancel previous session
sleep(1);
$port->lookfor();
my $user_input;
if ($ARGV[0]) {
$user_input = $ARGV[0];
} else {
print "Command> ";
$user_input = <STDIN>;
$user_input =~ s/[\n\f\t]//g;
};
while ($user_input ne "") {
$port->lookclear; # empty buffers
sleep 1;
my $ussd_req = encode("gsm0338", $user_input);
print "Sending PDU USSD request: $ussd_req ($user_input)\n" if $opt_v;
$port->write("AT+CUSD=1,\"$ussd_req\",15\n");
print "Waiting for USSD reply...\n" if $opt_v;
my $answer = "";
until ("" ne $answer) {
$answer = $port->lookfor();
if ($answer) {
$port->lookclear;
my ($presentation, $ussd_reply, $ussd_coding);
if ($answer =~ m/\+CUSD:\s*(\d)\s*,\s*\"(.*)\",\s*([0-9]*)/s) {
($presentation, $ussd_reply, $ussd_coding) = ($1, $2, $3);
print "USSD encoding: $ussd_coding\n" if $opt_v;
print "USSD reply: $ussd_reply\n" if $opt_v;
if ($presentation eq "2") {
print "USSD session ended: ";
}
} else {
undef $ussd_reply;
print "Got unknown message: $answer\n";
}
if ($ussd_reply) {
print "Decoded: " if $opt_v;
if ($ussd_coding eq '15') {
printf "%s\n", decode("gsm0338", $ussd_reply);
} elsif ($ussd_coding eq '72') {
printf "%s\n", decode("UCS-2BE", $ussd_reply);
} else {
print "Could not decode: $ussd_reply,$ussd_coding\n";
}
}
} else {
sleep(1);
}
}
# next user input
print "Command> ";
$user_input = <STDIN>;
$user_input =~ s/[\n\f\t]//g;
}
$port->write("ATZ\n");
$port->close or die;
undef $port;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment