?? smsc_at.c
字號(hào):
/* * smsc_at.c - implement interface to wireless modems using AT commands * * Yann Muller, Nick Clarey - 3G Lab, 2001. * * Ericsson code by Chris Blown 30/01/2001 - Hinterlands Aust. * * Make sure your kannel configuration file contains the following lines * to be able to use the AT SMSC: * group = smsc * smsc = at * modemtype = wavecom | premicell | siemens | siemens-tc35 | falcom | * nokiaphone | ericsson * device = /dev/xxx */#include <errno.h>#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <ctype.h>#include <termios.h>#include <sys/time.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include <sys/ioctl.h>#include <time.h>#include "gwlib/gwlib.h"#include "gwlib/charset.h"#include "smsc.h"#include "smsc_p.h"#include "sms.h"#ifndef CRTSCTS#define CRTSCTS 0#endif/* The number of times to attempt to send a message should sending fail */#define RETRY_SEND 3/****************************************************************************** * Prototypes for private functions */static int at_data_read(int fd, Octstr *ostr);static int send_modem_command(int fd, char *cmd, int multiline);static int pdu_extract(SMSCenter *smsc, Octstr **ostr);static Msg *pdu_decode(Octstr *data);static Msg *pdu_decode_deliver_sm(Octstr *data);static int pdu_encode(Msg *msg, unsigned char *pdu, SMSCenter *smsc);static Octstr *convertpdu(Octstr *pdutext);static int hexchar(int hexc);static int encode7bituncompressed(Octstr *input, unsigned char *encoded, int offset);static int encode8bituncompressed(Octstr *input, unsigned char *encoded);static void decode7bituncompressed(Octstr *input, int len, Octstr *decoded, int offset);static int numtext(int num);/****************************************************************************** * Types of GSM modems (as used in kannel.conf: at_type=xxxx) */#define WAVECOM "wavecom"#define PREMICELL "premicell"#define SIEMENS "siemens"#define SIEMENS_TC35 "siemens-tc35"#define FALCOM "falcom"#define NOKIAPHONE "nokiaphone"#define ERICSSON "ericsson"/****************************************************************************** * Message types defines */#define AT_DELIVER_SM 0#define AT_SUBMIT_SM 1/****************************************************************************** * type of phone number defines */#define PNT_UNKNOWN 0#define PNT_INTER 1#define PNT_NATIONAL 2/****************************************************************************** * Open the connection * * returns the file descriptor (fd) if ok, -1 on failure */static int at_open_connection(SMSCenter *smsc) { int fd = -1; struct termios tios; int ret; fd = open(smsc->at_serialdevice, O_RDWR|O_NONBLOCK|O_NOCTTY); if(fd == -1) { error(errno, "at_open_data_link: error opening the character device <%s>", smsc->at_serialdevice); return -1; } tcgetattr(fd, &tios); if((strcmp(smsc->at_modemtype, SIEMENS) == 0) || (strcmp(smsc->at_modemtype, SIEMENS_TC35) == 0) || (strcmp(smsc->at_modemtype, NOKIAPHONE) == 0)) { cfsetospeed(&tios, B19200); /* check radio pad parameter*/ cfsetispeed(&tios, B19200); } else { cfsetospeed(&tios, B9600); /* check radio pad parameter*/ cfsetispeed(&tios, B9600); } kannel_cfmakeraw(&tios); /* parameters: * IGNBRK, IGNPAR: ignore BREAK and PARITY errors * INPCK: enable parity check * CSIZE: for CS8 * HUPCL: hang up on close * CREAD: enable receiver * CRTSCTS: enable flow control */ tios.c_iflag |= IGNBRK | IGNPAR | INPCK; tios.c_cflag |= CSIZE | HUPCL | CREAD | CRTSCTS; if (strcmp(smsc->at_modemtype, NOKIAPHONE) == 0) tios.c_cflag ^= PARODD; tios.c_cflag |=CS8; ret = tcsetattr(fd, TCSANOW, &tios); /* apply changes now */ if(ret == -1){ error(errno,"at_data_link: fail to set termios attribute"); goto error; } tcflush(fd, TCIOFLUSH); return fd; error: return -1;}/****************************************************************************** * Open the (Virtual) SMSCenter */SMSCenter *at_open(char *serialdevice, char *modemtype, char *pin, char *validityperiod, int alt_dcs) { SMSCenter *smsc; char setpin[20]; int ret; smsc = smscenter_construct(); if(smsc == NULL) goto error; smsc->type = SMSC_TYPE_AT; smsc->at_serialdevice = gw_strdup(serialdevice); if (validityperiod != NULL) smsc->at_validityperiod = gw_strdup(validityperiod); smsc->at_modemtype = gw_strdup(modemtype); if(pin) smsc->at_pin = gw_strdup(pin); smsc->at_received = list_create(); smsc->at_inbuffer = octstr_create(""); smsc->at_alt_dcs = alt_dcs; smsc->at_fd = at_open_connection(smsc); if (smsc->at_fd < 0) goto error; /* Nokia 7110 and 6210 need some time between opening * the connection and sending the first AT commands */ if (strcmp(smsc->at_modemtype, NOKIAPHONE) == 0) sleep(1); /* lets initialize the modem to a safe state */ send_modem_command(smsc->at_fd, "AT", 0); send_modem_command(smsc->at_fd, "AT&F", 0); send_modem_command(smsc->at_fd, "AT", 0); /* Turn Echo off on the modem: we don't need it */ if(send_modem_command(smsc->at_fd, "ATE0", 0) == -1) { /* ok that was the first command we tried. */ goto error; } /* Let's collect some information from modem */ if(send_modem_command(smsc->at_fd, "ATI", 0) == -1) goto error; sleep(1); if(send_modem_command(smsc->at_fd, "ATI1", 0) == -1) goto error; sleep(1); if(send_modem_command(smsc->at_fd, "ATI2", 0) == -1) goto error; sleep(1); if(send_modem_command(smsc->at_fd, "ATI3", 0) == -1) goto error; sleep(1); if(send_modem_command(smsc->at_fd, "ATI4", 0) == -1) goto error; sleep(1); /* Check does the modem require a PIN and, if so, send it * This is not supported by the Nokia Premicell */ if(strcmp(smsc->at_modemtype, PREMICELL) != 0) { ret = send_modem_command(smsc->at_fd, "AT+CPIN?", 0); if(ret == -1) goto error; if(ret == -2) { if(smsc->at_pin == NULL) goto error; sprintf(setpin, "AT+CPIN=%s", smsc->at_pin); if(send_modem_command(smsc->at_fd, setpin, 0) == -1) goto error; } } /* Set the modem to PDU mode and autodisplay of new messages */ if(send_modem_command(smsc->at_fd, "AT+CMGF=0", 0) == -1) goto error; sleep(1); /* The Ericsson GM12 modem requires different new message * indication options from the other modems */ if(strcmp(smsc->at_modemtype, ERICSSON) == 0) { if(send_modem_command(smsc->at_fd, "AT+CNMI=3,2,0,0", 0) == -1) goto error; } else if(strcmp(smsc->at_modemtype, SIEMENS_TC35) == 0) { if(send_modem_command(smsc->at_fd, "AT+CSMS=1", 0) == -1) goto error; if(send_modem_command(smsc->at_fd, "AT+CNMI=1,2,0,0,1",0)== -1) goto error; } else { if(send_modem_command(smsc->at_fd, "AT+CNMI=1,2,0,0,0", 0) == -1) goto error; } sprintf(smsc->name, "AT: %s", smsc->at_serialdevice); info(0, "AT SMSC successfully opened."); return smsc; error: return NULL;}/****************************************************************************** * Re-Open the AT (Virtual) SMSCenter */int at_reopen(SMSCenter *smsc) { /* Do we really have an open connection to start with? */ if (smsc->at_fd == -1) { info(0, "trying to close already closed AT, ignoring"); } /* If we do, then try to close the file descriptor */ else if (close(smsc->at_fd) == -1) { /* This situation could occur as a result of errors not being reported until the serial connection is closed. Supposing we do get here, we should reset the at_fd value to -1 to stop infinitely retrying the close. We also need to printing out the error message reported, just in case it's significant. */ smsc->at_fd = -1; error(errno, "Attempt to close connection to modem `%s' failed. Forcing reset.", smsc->at_serialdevice); } /* Reopen the connection. Note that the at_open_connection call returns a file descriptor, which we should set in the smsc structure */ smsc->at_fd = at_open_connection(smsc); /* Supposing that failed */ if (smsc->at_fd == -1) { error(0, "Attempt to open connection to modem '%s' failed.", smsc->at_serialdevice); /* Give up */ return -1; } /* Report success */ return 0;}/****************************************************************************** * Close the SMSCenter */int at_close(SMSCenter *smsc) { /* Do we really have an open connection to start with? */ if (smsc->at_fd == -1) { info(0, "trying to close already closed AT, ignoring"); } /* If we do, then try to close the file descriptor */ else if (close(smsc->at_fd) == -1) { error(errno, "Attempt to close connection to modem `%s' failed. Forcing reset.", smsc->at_serialdevice); } /* Our file descriptor can now be safely declared closed */ smsc->at_fd = -1; /* Deallocate any miscellany */ smscenter_destruct(smsc); /* Report success */ return 0;}/****************************************************************************** * Check for pending messages */int at_pending_smsmessage(SMSCenter *smsc) { Octstr *pdu = NULL; int ret=0; Msg *msg = NULL; /* Receive raw data */ ret = at_data_read(smsc->at_fd, smsc->at_inbuffer); if(ret == -1) { ret = at_reopen(smsc); if(ret == -1) goto error; return 0; } ret = 0; while( pdu_extract(smsc, &pdu) == 1) { msg = pdu_decode(pdu); if(msg != NULL) { list_append(smsc->at_received, (void *)msg); ret = 1; } octstr_destroy(pdu); } if(list_len(smsc->at_received) > 0) ret = 1; return ret; error: error(errno,"at_pending message: device error"); return -1;}/****************************************************************************** * Send a message */int at_submit_msg(SMSCenter *smsc, Msg *msg) { unsigned char command[500], pdu[500]; int ret = -1; char sc[3]; int retries = RETRY_SEND; /* Some modem types need a '00' prepended to the PDU * to indicate to use the default SC. * NB: This extra padding is not counted in the CMGS byte count */ sc[0] = '\0'; if((strcmp(smsc->at_modemtype, WAVECOM ) == 0) || (strcmp(smsc->at_modemtype, SIEMENS ) == 0) || (strcmp(smsc->at_modemtype, SIEMENS_TC35 ) == 0) ||
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -