Programsko pošiljanje sporočil SMS
Sporočila SMS (Short Message Service) so danes povsem normalen način komunikacije, zlasti pri mlajši generaciji uporabnikov prenosnih telefonov. Prednost pošiljanja sporočil SMS je razmeroma nizka cena, slabost pa čas, potreben za pisanje sporočila - a to ni ovira, če se sporočilo pošlje z namenskim programom. Ta način obveščanja se najpogosteje uporablja za posredovanje alarmov in dogodkov na področjih procesne avtomatike, telekomunikacij in sistemske administracije.
Za računalniško pošiljanje sporočil SMS potrebujemo osebni računalnik, modem GSM ter namenski program za pošiljanje sporočil SMS.
Modem GSM
Modeme GSM povezujemo z osebnim računalnikom z zaporednim ali USB priključkom. Slednji potrebuje za svoje delovanje ustrezen gonilnik. Trg ponuja precej modelov, od katerih se najpogosteje srečujemo z modemi GSM podjetij Siemens in Wavecom.
Kot zgled pošiljanja sporočil SMS lahko uporabimo modem GSM podjetja Siemens, model TC35, ki uporablja zaporedni (COM) priključek za povezovanje. Za delovanje modema potrebujemo še kartico SIM izbranega ponudnika storitev GSM, podobno kot pri navadnem prenosnem telefonu.
Modem GSM Siemens TC35
Komunikacija modemov GSM z osebnim računalnikom poteka ob pomoči Hayesovih ukazov oziroma ukazov AT. Gospod Hayes je leta 1977 postavil temelj modemski komunikaciji. Načelo le-te temelji na izmenjevanju podatkovnega (data mode) in ukaznega (command mode) prenosa podatkov. Ukaze AT pošiljamo v ukaznem načinu za inicializacijo začetnih nastavitev, spreminjanje hitrosti prenosa podatkov, klic nove telefonske številke itn. V podatkovnem načinu prenašamo čiste podatke, na primer prenos datotek in elektronsko pošto.
Ukaz AT izhaja od angleške besede attention (pozor) in opozarja, da za nizom AT sledi ukaz modemu.
Za pošiljanje sporočila SMS potrebujemo le dva osnovna ukaza AT, ki ju posredujemo modemu s terminalskim programom, na primer Hyperterminal (Windows) ali Minicom (Linux).
Nastavitve terminalskega programa naj bodo naslednje:
Baudna hitrost: 38400
Število podatkovnih bitov: 8
Število končnih bitov: 1
Pariteta: nobena
Krmiljenje toka: nobeno
Priporočam, da predhodno nastavite kartico SIM modema GSM na vašem prenosnem telefonu, tako da ob vklopu ne bo preverjala kode PIN. V nasprotnem primeru bo potrebna programska nastavitev kode PIN s pomočjo ustreznega ukaza AT. Prav tako se prepričajte, da je na kartici SIM nastavljena številka SMS centra (Mobitel: +38641001333, Simobil: +38640441000).
Za pošiljanje sporočila SMS vtipkajte naslednje ukaze AT v terminalskem programu:
AT+CMGF=1
AT+CMGS="+38640111222" (Telefonska številka, na katero pošiljamo sporočilo SMS.)
> To je sporocilo SMS (Sporočilo vtipkajte in nato pošljite s hkratnim pritiskom
tipk CTRL in Z.)
Zgled komunikacije v minicomu:
Welcome to minicom 2.00.0
OPTIONS: History Buffer, F-key Macros, Search History Buffer, I18n
Compiled on Mar 14 2003, 01:20:23.
Press CTRL-A Z for help on special keys
AT S7=45 S0=0 L1 V1 X4 &c1 E1 Q0
OK
AT+CMGF=1
OK
AT+CMGS="+38640111222"
> To je sporocilo SMS
+CMGS: 73
OK
Pomen ukazov AT je naslednji:
AT+CMGF=1
Nastavi tekstovni način pošiljanja (text mode).
AT+CMGF=0
Nastavi protokolni način pošiljanja (PDU mode).
AT+CMGF?
Vrne način prenosa (tekst ali PDU).
AT+CMGS="Številka"
Pošlje SMS sporočilo.
AT+CPIN=PIN
Vnos kode PIN.
AT+CPIN?
Vrne kodo PIN.
AT+CSCA="Številka"
Vnos številke SMS centra (prej uporabi ukaz CMGF=1).
AT+CSCA?
Vrne številko SMS centra.
ATE0
Izklopi odmev (echo off), vrnitev vtipkanega ukaza.
Programska rešitev pošiljanja sporočil SMS
Podali bomo programsko rešitev pošiljanja sporočil SMS v programskem jeziku C. Izvedba programa bo narejena v operacijskem sistemu Linux.
Program je sestavljen iz dveh delov. V prvem izvajamo inicializacijo zaporednih vrat oziroma datoteko naprave /dev/ttyS0, ki predstavlja prva zaporedna vrata (COM1). V drugem delu pošiljamo ukaze AT v neskončni zanki while. Do pošiljanja pride ob spremembi vsebine datoteke sms_dat (glej makro #define SMSFILE), ki vsebuje sporočilo SMS.
Inicializacijo zaporednih vrat omogočajo knjižnice termios, ki vsebujejo številne funkcije za nadzor asinhrone zaporedne povezave. Večina funkcij uporablja kot parameter kazalec na strukturo termios, ki vsebuje naslednje člane:
tcflag_t c_iflag; /* vhodni načini */
tcflag_t c_oflag; /* izhodni načini */
tcflag_t c_cflag; /* kontrolni načini */
tcflag_t c_lflag; /* lokalni načini */
cc_t c_cc[NCCS]; /* kontrolni znaki */
Zaporedna vrata najprej odpremo s funkcijo open, ki vrne njihov datotečni deskriptor. Ta se bo nanašal na zaporedna vrata v drugih funkcijah. Funkcija tcgetattr() prebere obstoječe parametre zaporednih vrat, na katere se sklicuje datotečni deskriptor, ter jih shrani v spremenljivki strukture termios (my_termios).
Sledi nastavljanje kontrolnih načinov (c_cflag) v vrstici kode:
my_termios.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
Pomen izbranih kontrolnih načinov je naslednji:
BAUDRATE: baudna hitrost
CRTSCTS: omogoči (RTS/CTS) strojno krmiljenje toka.
CS8: število podatkovnih bitov
CLOCAL: ignorira modemske statusne linije.
CREAD: aktivira sprejemnik.
Izklop odmeva odposlanih znakov ter izklop ustvarjanja kontrolnih signalov izvedemo v vrstici kode:
my_termios.c_lflag = 0;
Pri nastavljanju vhodnih načinov izberemo možnost IGNPAR, ki ignorira podatkovne paritetne napake (parity error) ter napake na podatkovnih okvirih (framing error).
Izhodni načini (c_oflag) so nastavljeni tako, da se znaki oddajajo neposredno brez vpletanja (obdelave) operacijskega sistema (raw output).
Podatke, ki so bili sprejeti, a niso prebrani, zavrže funkcija tcflush. Inicializacijo končamo s funkcijo tcsetattr, ki dejansko nastavi parametre zaporednih vrat.
Do pošiljanja sporočila SMS pride, če je datoteka sms_dat (makro SMSFILE), ki vsebuje sporočilo, polna (število znakov je večje od 0).
Programska koda:
/*** Datoteka: sms.c ***/
/*** Pošlje SMS sporočilo na GSM modem Siemens TC35 ***/
/*** Sporočilo prebere iz datoteke sms_dat ***/
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <termios.h>
#include <string.h>
#include <sys/times.h>
#include <errno.h>
#define MODEM_PORT "/dev/ttyS0" // Zaporedna vrata COM 1
#define BSIZE 200 // Velikost ukaza AT
#define SMSSIZE 160 // Velikost sporočila SMS
#define BAUDRATE B38400 // Hitrost prenosa
// Modemski AT ukazi
#define ECHO_OFF "ATE0"
#define NO_PDU "AT+CMGF=1"
// Telefonska stevilka na katero posiljamo SMS
#define SEND_SMS "AT+CMGS=\"+38640111222\""
// Lokacija SMS datoteke sms_dat
#define SMSFILE "/home/dalibor/sms_dat"
#define TRUE 1
#define FALSE 0
/*******************/
/*** Funkcije ***/
/******************/
// Odpre datoteko
FILE* open_file(const char *path, const char *mode)
{
FILE* fd = fopen(path, mode);
if (fd == NULL)
printf("Odpiranje porta %d %s\n", errno, strerror(errno));
return (fd);
}
// Vpiši podatke na zaporedna vrata
void write_modem(char *psz_buf, int fds)
{
// Poslani niz končujemo z znakom \n (0x0d)
// za novo vrstico ter \r (0x0a) za začetek vrstice
psz_buf[strlen(psz_buf)] = 0x0d;
psz_buf[strlen(psz_buf)+1] = 0x0a;
if (write(fds, psz_buf, strlen(psz_buf)) < 0)
fprintf(stderr, " Error writing... \n");
}
// Bere podatke z zaporednih vrat
void read_modem(int fds)
{
char sz_inbuf[BSIZE]; // Izhodni ukaz
memset(sz_inbuf, 0, BSIZE);
usleep(1000000); // Počakaj trenutek
if (read(fds, sz_inbuf, sizeof(sz_inbuf)) < 0)
fprintf(stderr, "Napaka pri citanju... \n");
printf ("Sprejeti niz je:%s \n", sz_inbuf);
}
// Pošlje ukaz AT
void send_AT_recv(char *psz_buf, int fds)
{
printf ("Pošiljam ukaz < %s >. \n", psz_buf);
write_modem(psz_buf, fds);
read_modem(fds);
memset (psz_buf, 0, BSIZE);
}
/*********************/
/*** Konec funkcij ***/
/*********************/
/**********************/
/*** Glavni program ***/
/**********************/
int main()
{
int fd; // datotečni deskriptor za zaporedna vrata
int n_file_full = FALSE;
int nch = 0, ch = 0;
FILE *fds;
struct termios my_termios;
char sz_at_com[BSIZE]; // ukaz AT
char sz_sms[SMSSIZE]; // SMS
// Odpiranje zaporednih vrat
if ((fd = open(MODEM_PORT, O_RDWR | O_NOCTTY)))
printf("Odpiranje porta: %d %s\n", errno, strerror(errno));
// Odpiranje SMS datoteke
fds = open_file(SMSFILE, "r");
//*** Konfiguriranje modema ***
// Prebere obstoječe parametre vrat
tcgetattr(fd, &my_termios);
// Nastavi: baudno hitrost, strojno krmiljenje, število podatkovnih bitov
// Ignorira modemske statusne linije ter aktivira sprejemnik.
my_termios.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
// Izklopi odmev in ne ustvarjaj kontrolnih signalov
my_termios.c_lflag = 0;
// Ignorira paritetne napake in napake na okvirih
my_termios.c_iflag = IGNPAR;
// Direktno pošiljanje brez procesiranja (raw output)
my_termios.c_oflag = 0;
tcflush(fd, TCIFLUSH);
// Nastavi parametre vrat
tcsetattr(fd, TCSAFLUSH, &my_termios);
// *** Konec konfiguracije modema ***
// Pošlji SMS, ko je datoteka SMSFILE polna
while (TRUE) {
if (n_file_full) {
fds = open_file(SMSFILE, "r");
n_file_full = FALSE;
}
// Preštej znake
while ((ch = getc(fds)) != EOF) nch++;
// Pošlji SMS, če datoteka ni prazna
if (nch > TRUE) {
n_file_full = TRUE;
// Preberi vsebino datoteke od začetka
memset (sz_sms, 0, 160);
fseek(fds, 0, SEEK_SET);
fread (sz_sms, 1, 160, fds);
// Ponastavi vrednosti
nch = ch = 0;
printf ("SMS vsebina: %s \n", sz_sms);
// Izbriši datoteko z vnovičnim odpiranjem
fds = open_file(SMSFILE, "w");
fclose (fds);
// Pošlji ATE0 - ugasni odmev (echo off)
sprintf (sz_at_com, ECHO_OFF);
send_AT_recv(sz_at_com, fd);
// Nastavi tekstovni način pošiljanja
sprintf (sz_at_com, NO_PDU);
send_AT_recv(sz_at_com, fd);
// Pošlji sporočilo SMS
sprintf (sz_at_com, SEND_SMS);
send_AT_recv(sz_at_com, fd);
// Dejansko pošiljanje sporočila SMS
sprintf(sz_at_com, "%s %c ", sz_sms, 26);
send_AT_recv(sz_at_com, fd);
}
}
close (fd);
} // END
Program prevedemo in poženemo kot root uporabnik v lupini shell na naslednji način:
# gcc sms.c -o sms
# ./sms
Pred zagonom programa ustvarite prazno datoteko sms_dat, definirano z makrom SMSFILE. Sporočilo dejansko pošljete s pisanjem v to datoteko, in sicer na naslednji način:
# echo To je sporočilo SMS > /lokacija datoteke (glej makro SMSFILE)
Program bo ustvaril naslednji izpis ob pošiljanju sporočila SMS:
SMS vsebina: To je sporočilo SMS
Pošiljam ukaz < ATE0 >.
Sprejeti niz je:
OK
OK
Pošiljam ukaz < AT+CMGF=1 >.
Sprejeti niz je:
OK
Pošiljam ukaz < AT+CMGS="+38640111222" >.
Sprejeti niz je:
>
Pošiljam ukaz < To je sporočilo SMS
>.
Sprejeti niz je:
+CMGS: 128
Izvirna koda je na voljo na spletnem naslovu http://www.monitor.si/datoteke/sms-c.zip.