📄 gsm0710muxd.c
字号:
/* * GSM 07.10 Implementation with User Space Serial Ports * * Code heavily based on gsmMuxd written by * Copyright (C) 2003 Tuukka Karvonen <tkarvone@iki.fi> * Modified November 2004 by David Jander <david@protonic.nl> * Modified January 2006 by Tuukka Karvonen <tkarvone@iki.fi> * Modified January 2006 by Antti Haapakoski <antti.haapakoski@iki.fi> * Modified March 2006 by Tuukka Karvonen <tkarvone@iki.fi> * Modified October 2006 by Vasiliy Novikov <vn@hotbox.ru> * * Copyright (C) 2008 M. Dietrich <mdt@emdete.de> * * 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; either version 2 * of the License, or (at your option) any later version. * * 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. */#ifndef _GNU_SOURCE#define _GNU_SOURCE#endif#include <errno.h>#include <fcntl.h>#include <features.h>#include <paths.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <sys/stat.h>#include <sys/time.h>#include <sys/types.h>#include <sys/wait.h>#include <syslog.h>#include <termios.h>#include <time.h>#include <unistd.h>#include <glib.h> // http://library.gnome.org/devel/glib/unstable/glib-core.html#include <dbus/dbus.h> // http://dbus.freedesktop.org/doc/dbus/libdbus-tutorial.html#include <dbus/dbus-glib.h> // http://dbus.freedesktop.org/doc/dbus-glib/DBusConnection* dbus_g_connection_get_connection(DBusGConnection *gconnection); // why isn't this in dbus-glib.h?// http://maemo.org/api_refs/4.0/dbus-glib/group__DBusGLibInternals.html#gfac56b6025a90951510d33423ff04120// http://wiki.bluez.org/wiki/HOWTO/DiscoveringDevices// http://dbus.freedesktop.org/doc/api/html/example-service_8c-source.html// ~/Source/openmoko/build/tmp/work/i686-linux/glib-2.0-native-2.12.4-r1/glib-2.12.4/tests/mainloop-test.c// http://www.linuxquestions.org/questions/linux-software-2/dbus-problem-505442/// dbus-send --system --print-reply --type=method_call --dest=org.pyneo.muxer /org/pyneo/Muxer org.freesmartphone.GSM.MUX.AllocChannel string:xxx///////////////////////////////////////////////////////////////// defines#define LOG(lvl, f, ...) do{if(lvl<=syslog_level)syslog(lvl,"%s:%d:%s(): " f "\n", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);}while(0)#define SYSCHECK(c) do{if((c)<0){\ LOG(LOG_ERR, "system-error: '%s' (code: %d)", strerror(errno), errno);\ return -1;\ }}while(0)#define GSM0710_FRAME_FLAG 0xF9// basic mode flag for frame start and end#define GSM0710_FRAME_ADV_FLAG 0x7E// advanced mode flag for frame start and end#define GSM0710_FRAME_ADV_ESC 0x7D// advanced mode escape symbol#define GSM0710_FRAME_ADV_ESC_COPML 0x20// advanced mode escape complement mask#define GSM0710_FRAME_ADV_ESCAPED_SYMS { GSM0710_FRAME_ADV_FLAG, GSM0710_FRAME_ADV_ESC, 0x11, 0x91, 0x13, 0x93 }// advanced mode escaped symbols: Flag, Escape, XON and XOFF// bits: Poll/final, Command/Response, Extension#define GSM0710_PF 0x10//16#define GSM0710_CR 0x02//2#define GSM0710_EA 0x01//1// type of frames#define GSM0710_TYPE_SABM 0x2F//47 Set Asynchronous Balanced Mode#define GSM0710_TYPE_UA 0x63//99 Unnumbered Acknowledgement#define GSM0710_TYPE_DM 0x0F//15 Disconnected Mode#define GSM0710_TYPE_DISC 0x43//67 Disconnect#define GSM0710_TYPE_UIH 0xEF//239 Unnumbered information with header check#define GSM0710_TYPE_UI 0x03//3 Unnumbered Acknowledgement// control channel commands#define GSM0710_CONTROL_PN (0x80|GSM0710_EA)//?? DLC parameter negotiation#define GSM0710_CONTROL_CLD (0xC0|GSM0710_EA)//193 Multiplexer close down#define GSM0710_CONTROL_PSC (0x40|GSM0710_EA)//??? Power Saving Control#define GSM0710_CONTROL_TEST (0x20|GSM0710_EA)//33 Test Command#define GSM0710_CONTROL_MSC (0xE0|GSM0710_EA)//225 Modem Status Command#define GSM0710_CONTROL_NSC (0x10|GSM0710_EA)//17 Non Supported Command Response#define GSM0710_CONTROL_RPN (0x90|GSM0710_EA)//?? Remote Port Negotiation Command#define GSM0710_CONTROL_RLS (0x50|GSM0710_EA)//?? Remote Line Status Command#define GSM0710_CONTROL_SNC (0xD0|GSM0710_EA)//?? Service Negotiation Command // V.24 signals: flow control, ready to communicate, ring indicator,// data valid three last ones are not supported by Siemens TC_3x#define GSM0710_SIGNAL_FC 0x02#define GSM0710_SIGNAL_RTC 0x04#define GSM0710_SIGNAL_RTR 0x08#define GSM0710_SIGNAL_IC 0x40//64#define GSM0710_SIGNAL_DV 0x80//128#define GSM0710_SIGNAL_DTR 0x04#define GSM0710_SIGNAL_DSR 0x04#define GSM0710_SIGNAL_RTS 0x08#define GSM0710_SIGNAL_CTS 0x08#define GSM0710_SIGNAL_DCD 0x80//128//#define GSM0710_COMMAND_IS(type, command) ((type & ~GSM0710_CR) == command)#define GSM0710_FRAME_IS(type, frame) ((frame->control & ~GSM0710_PF) == type)#ifndef min#define min(a,b) ((a < b) ? a :b)#endif#define GSM0710_WRITE_RETRIES 5#define GSM0710_MAX_CHANNELS 32// Defines how often the modem is polled when automatic restarting is// enabled The value is in seconds#define GSM0710_POLLING_INTERVAL 5#define GSM0710_BUFFER_SIZE 2048////////////////////////////////////////////////////// types//typedef struct GSM0710_Frame{ unsigned char channel; unsigned char control; int length; unsigned char *data;} GSM0710_Frame;//typedef struct GSM0710_Buffer{ unsigned char data[GSM0710_BUFFER_SIZE]; unsigned char *readp; unsigned char *writep; unsigned char *endp; int flag_found;// set if last character read was flag unsigned long received_count; unsigned long dropped_count; unsigned char adv_data[GSM0710_BUFFER_SIZE]; int adv_length; int adv_found_esc;} GSM0710_Buffer;// Channel data typedef struct Channel{ int id; // gsm 07 10 channel id char* devicename; int fd; int opened; unsigned char v24_signals; char* ptsname; char* origin; int remaining; unsigned char *tmp; guint g_source;} Channel;typedef enum MuxerStates { MUX_STATE_OPENING, MUX_STATE_INITILIZING, MUX_STATE_MUXING, MUX_STATE_CLOSING, MUX_STATE_OFF, MUX_STATES_COUNT // keep this the last} MuxerStates;typedef struct Serial{ char *devicename; char* pm_base_dir; int fd; MuxerStates state; GSM0710_Buffer *in_buf;// input buffer unsigned char *adv_frame_buf; time_t frame_receive_time; int ping_number; guint g_source; guint g_source_watchdog;} Serial;/////////////////////////////////////////// function prototypes/** * increases buffer pointer by one and wraps around if necessary *///void gsm0710_buffer_inc(GSM0710_Buffer *buf, void&* p);#define gsm0710_buffer_inc(buf,p) do { p++; if (p == buf->endp) p = buf->data; } while (0)/** * Tells how many chars are saved into the buffer. *///int gsm0710_buffer_length(GSM0710_Buffer *buf);#define gsm0710_buffer_length(buf) ((buf->readp > buf->writep) ? (GSM0710_BUFFER_SIZE - (buf->readp - buf->writep)) : (buf->writep-buf->readp))/** * tells how much free space there is in the buffer *///int gsm0710_buffer_free(GSM0710_Buffer *buf);#define gsm0710_buffer_free(buf) ((buf->readp > buf->writep) ? (buf->readp - buf->writep) : (GSM0710_BUFFER_SIZE - (buf->writep-buf->readp)))////////////////////////////////// constants & globalsstatic unsigned char close_channel_cmd[] = { GSM0710_CONTROL_CLD | GSM0710_CR, GSM0710_EA | (0 << 1) };static unsigned char test_channel_cmd[] = { GSM0710_CONTROL_TEST | GSM0710_CR, GSM0710_EA | (6 << 1), 'P', 'I', 'N', 'G', '\r', '\n', };//static unsigned char psc_channel_cmd[] = { GSM0710_CONTROL_PSC | GSM0710_CR, GSM0710_EA | (0 << 1), };static unsigned char wakeup_sequence[] = { GSM0710_FRAME_FLAG, GSM0710_FRAME_FLAG, };// crc table from gsm0710 specstatic const unsigned char r_crctable[] = {//reversed, 8-bit, poly=0x07 0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B, 0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67, 0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43, 0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F, 0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B, 0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17, 0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33, 0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F, 0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B, 0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87, 0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3, 0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF, 0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB, 0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7, 0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3, 0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF, };// config stuffstatic char* revision = "$Rev: 295 $";static int no_daemon = 1;static int pin_code = -1;static int use_ping = 0;static int use_timeout = 0;static int syslog_level = LOG_INFO;static char* object_name = "/org/pyneo/Muxer";// serial iostatic Serial serial;// muxed io channelsstatic Channel channellist[GSM0710_MAX_CHANNELS]; // remember: [0] is not used acticly because it's the control channel// some statestatic GMainLoop* main_loop = NULL;static DBusGConnection* g_conn = NULL;// +CMUX=<mode>[,<subset>[,<port_speed>[,<N1>[,<T1>[,<N2>[,<T2>[,<T3>[,<k>]]]]]]]]static int cmux_mode = 1;static int cmux_subset = 0;static int cmux_port_speed = 5;// Maximum Frame Size (N1): 64/31static int cmux_N1 = 64;#if 0// Acknowledgement Timer (T1) sec/100: 10 static int cmux_T1 = 10;// Maximum number of retransmissions (N2): 3static int cmux_N2 = 3;// Response Timer for multiplexer control channel (T2) sec/100: 30static int cmux_T2 = 30;// Response Timer for wake-up procedure(T3) sec: 10static int cmux_T3 = 10;// Window Size (k): 2static int cmux_k = 2;#endif// TODO: set automatically from at+cmux=?// neo: +CMUX: (1),(0),(1-5),(10-100),(1-255),(0-100),(2-255),(1-255),(1-7)/* * The following arrays must have equal length and the values must * correspond. also it has to correspond to the gsm0710 spec regarding * baud id of CMUX the command. */static int baud_rates[] = { 0, 9600, 19200, 38400, 57600, 115200, 230400, 460800};static speed_t baud_bits[] = { 0, B9600, B19200, B38400, B57600, B115200, B230400, B460800};/** * Determine baud-rate index for CMUX command */static int baud_rate_index( int baud_rate){ int i; for (i = 0; i < sizeof(baud_rates) / sizeof(*baud_rates); ++i) if (baud_rates[i] == baud_rate) return i; return -1;}/** * Calculates frame check sequence from given characters. * * PARAMS: * input - character array * length - number of characters in array (that are included) * RETURNS: * frame check sequence */static unsigned char frame_calc_crc( const unsigned char *input, int length){ unsigned char fcs = 0xFF; int i; for (i = 0; i < length; i++) fcs = r_crctable[fcs ^ input[i]]; return 0xFF - fcs;}/** * Escapes GSM0710_FRAME_ADV_ESCAPED_SYMS characters. * returns escaped buffer length. */static int fill_adv_frame_buf( unsigned char *adv_buf, const unsigned char *data, int length){ static const unsigned char esc[] = GSM0710_FRAME_ADV_ESCAPED_SYMS; int i, esc_i, adv_i = 0; for (i = 0; i < length; ++i, ++adv_i) { adv_buf[adv_i] = data[i]; for (esc_i = 0; esc_i < sizeof(esc) / sizeof(esc[0]); ++esc_i) if (data[i] == esc[esc_i]) { adv_buf[adv_i] = GSM0710_FRAME_ADV_ESC; adv_i++; adv_buf[adv_i] = data[i] ^ GSM0710_FRAME_ADV_ESC_COPML; break; } } return adv_i;}/** * ascii/hexdump a byte buffer */static int syslogdump( const char *prefix, const unsigned char *ptr, unsigned int length){ if (LOG_DEBUG>syslog_level) return 0; char buffer[100]; unsigned int offset = 0l; int i; while (offset < length) { int off; strcpy(buffer, prefix); off = strlen(buffer); SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, "%08x: ", offset)); off = strlen(buffer); for (i = 0; i < 16; i++) { if (offset + i < length) SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, "%02x%c", ptr[offset + i], i == 7 ? '-' : ' ')); else SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, " .%c", i == 7 ? '-' : ' ')); off = strlen(buffer); } SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, " ")); off = strlen(buffer); for (i = 0; i < 16; i++) if (offset + i < length) { SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, "%c", (ptr[offset + i] < ' ') ? '.' : ptr[offset + i])); off = strlen(buffer); } offset += 16; LOG(LOG_DEBUG, "%s", buffer); } return 0;}/** * Writes a frame to a logical channel. C/R bit is set to 1. * Doesn't support FCS counting for GSM0710_TYPE_UI frames. * * PARAMS: * channel - channel number (0 = control) * input - the data to be written * length - the length of the data * type - the type of the frame (with possible P/F-bit) * * RETURNS: * number of characters written */static int write_frame( int channel, const unsigned char *input, int length, unsigned char type){ LOG(LOG_DEBUG, "Enter");//flag, GSM0710_EA=1 C channel, frame type, length 1-2 unsigned char prefix[5] = { GSM0710_FRAME_FLAG, GSM0710_EA | GSM0710_CR, 0, 0, 0 }; unsigned char postfix[2] = { 0xFF, GSM0710_FRAME_FLAG }; int prefix_length = 4; int c;// char w = 0;// int count = 0;// do// { syslogdump(">s ", (unsigned char *)wakeup_sequence, sizeof(wakeup_sequence)); write(serial.fd, wakeup_sequence, sizeof(wakeup_sequence));// SYSCHECK(tcdrain(serial.fd));// fd_set rfds;// FD_ZERO(&rfds);// FD_SET(serial.fd, &rfds);// struct timeval timeout;// timeout.tv_sec = 0;// timeout.tv_usec = 1000 / 100 * cmux_T2;// int sel = select(serial.fd + 1, &rfds, NULL, NULL, &timeout);// if (sel > 0 && FD_ISSET(serial.fd, &rfds))// read(serial.fd, &w, 1);// else// count++;// } while (w != wakeup_sequence[0] && count < cmux_N2);// if (w != wakeup_sequence[0])// LOG(LOG_WARNING, "Didn't get frame-flag after wakeup"); LOG(LOG_DEBUG, "Sending frame to channel %d", channel);//GSM0710_EA=1, Command, let's add address prefix[1] = prefix[1] | ((63 & (unsigned char) channel) << 2);//let's set control field prefix[2] = type;//let's not use too big frames length = min(cmux_N1, length); if (!cmux_mode) {//Modified acording PATCH CRC checksum//postfix[0] = frame_calc_crc (prefix + 1, prefix_length - 1);//length if (length > 127) { prefix_length = 5; prefix[3] = (0x007F & length) << 1; prefix[4] = (0x7F80 & length) >> 7; } else prefix[3] = 1 | (length << 1); postfix[0] = frame_calc_crc(prefix + 1, prefix_length - 1); c = write(serial.fd, prefix, prefix_length); if (c != prefix_length) { LOG(LOG_WARNING, "Couldn't write the whole prefix to the serial port for the virtual port %d. Wrote only %d bytes", channel, c); return 0; } if (length > 0) { c = write(serial.fd, input, length); if (length != c) { LOG(LOG_WARNING, "Couldn't write all data to the serial port from the virtual port %d. Wrote only %d bytes", channel, c); return 0; } } c = write(serial.fd, postfix, 2); if (c != 2) { LOG(LOG_WARNING, "Couldn't write the whole postfix to the serial port for the virtual port %d. Wrote only %d bytes", channel, c); return 0; } } else//cmux_mode { int offs = 1; serial.adv_frame_buf[0] = GSM0710_FRAME_ADV_FLAG; offs += fill_adv_frame_buf(serial.adv_frame_buf + offs, prefix + 1, 2);// address, control offs += fill_adv_frame_buf(serial.adv_frame_buf + offs, input, length);// data//CRC checksum postfix[0] = frame_calc_crc(prefix + 1, 2); offs += fill_adv_frame_buf(serial.adv_frame_buf + offs, postfix, 1);// fcs serial.adv_frame_buf[offs] = GSM0710_FRAME_ADV_FLAG; offs++; syslogdump(">s ", (unsigned char *)serial.adv_frame_buf, offs); c = write(serial.fd, serial.adv_frame_buf, offs); if (c != offs) { LOG(LOG_WARNING, "Couldn't write the whole advanced option packet to the serial port for the virtual port %d. Wrote only %d bytes", channel, c);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -