📄 gsm0710muxd.c
字号:
} else//channel already opened LOG(LOG_WARNING, "Received SABM even though channel %d for %s was already closed", frame->channel, channellist[frame->channel].origin); channellist[frame->channel].opened = 1; write_frame(frame->channel, NULL, 0, GSM0710_TYPE_UA | GSM0710_PF); break; } } destroy_frame(frame); } LOG(LOG_DEBUG, "Leave"); return frames_extracted;}/** * Function responsible by all signal handlers treatment * any new signal must be added here */void signal_treatment( int param){ switch (param) { case SIGPIPE: exit(0); break; case SIGHUP://reread the configuration files break; case SIGINT: case SIGTERM: case SIGUSR1: //exit(0);//sig_term(param); g_main_loop_quit(main_loop); break; case SIGKILL: default: exit(0); break; }}static int modem_hw_(const char* pm_base_dir, const char* entry, int on){ LOG(LOG_DEBUG, "Enter"); if (pm_base_dir != NULL) { char fn[256]; SYSCHECK(snprintf(fn, sizeof(fn), "%s/%s", pm_base_dir, entry)); LOG(LOG_DEBUG, "echo %c > %s", on?'1':'0', fn); int fd; SYSCHECK(fd = open(fn, O_RDWR | O_NONBLOCK)); SYSCHECK(write(fd, on?"1\n":"0\n", 2)); SYSCHECK(close(fd)); } else LOG(LOG_DEBUG, "no pm_base_dir"); LOG(LOG_DEBUG, "Leave"); return 0;}static int modem_hw_off(const char* pm_base_dir){ LOG(LOG_DEBUG, "Enter"); SYSCHECK(modem_hw_(pm_base_dir, "power_on", 0)); SYSCHECK(modem_hw_(pm_base_dir, "reset", 0)); LOG(LOG_DEBUG, "Leave"); return 0;}static int modem_hw_on(const char* pm_base_dir){ LOG(LOG_DEBUG, "Enter"); SYSCHECK(modem_hw_off(pm_base_dir)); sleep(1); SYSCHECK(modem_hw_(pm_base_dir, "power_on", 1)); sleep(1); SYSCHECK(modem_hw_(pm_base_dir, "reset", 1)); sleep(1); SYSCHECK(modem_hw_(pm_base_dir, "reset", 0)); sleep(4); LOG(LOG_DEBUG, "Leave"); return 0;}gboolean serial_device_read(GIOChannel *source, GIOCondition condition, gpointer data){ Serial* serial = (Serial*)data; LOG(LOG_DEBUG, "Enter"); if (condition == G_IO_IN) { switch (serial->state) { case MUX_STATE_MUXING: { unsigned char buf[4096]; int len; //input from serial port LOG(LOG_DEBUG, "Serial Data"); int length; if ((length = gsm0710_buffer_free(serial->in_buf)) > 0 && (len = read(serial->fd, buf, min(length, sizeof(buf)))) > 0) { syslogdump("<s ", buf, len); gsm0710_buffer_write(serial->in_buf, buf, len); //extract and handle ready frames if (extract_frames(serial->in_buf) > 0) { time(&serial->frame_receive_time); //get the current time serial->ping_number = 0; } } LOG(LOG_DEBUG, "Leave keep watching"); return TRUE; } break; default: LOG(LOG_WARNING, "Don't know how to handle reading in state %d", serial->state); break; } } else if (condition == G_IO_HUP) { LOG(LOG_WARNING, "hup on serial file, closing"); serial->state = MUX_STATE_CLOSING; } LOG(LOG_DEBUG, "Leave stop watching"); return FALSE;}int open_serial_device( Serial* serial ){ LOG(LOG_DEBUG, "Enter"); SYSCHECK(modem_hw_on(serial->pm_base_dir)); int i; for (i=0;i<GSM0710_MAX_CHANNELS;i++) SYSCHECK(logical_channel_init(channellist+i, i));//open the serial port SYSCHECK(serial->fd = open(serial->devicename, O_RDWR | O_NOCTTY | O_NONBLOCK)); LOG(LOG_INFO, "Opened serial port"); int fdflags; SYSCHECK(fdflags = fcntl(serial->fd, F_GETFL)); SYSCHECK(fcntl(serial->fd, F_SETFL, fdflags & ~O_NONBLOCK)); struct termios t; tcgetattr(serial->fd, &t); t.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD); t.c_cflag |= CREAD | CLOCAL | CS8 | CRTSCTS; t.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG); t.c_iflag &= ~(INPCK | IGNPAR | PARMRK | ISTRIP | IXANY | ICRNL); t.c_iflag &= ~(IXON | IXOFF); t.c_oflag &= ~(OPOST | OCRNL); t.c_cc[VMIN] = 0; t.c_cc[VINTR] = _POSIX_VDISABLE; t.c_cc[VQUIT] = _POSIX_VDISABLE; t.c_cc[VSTART] = _POSIX_VDISABLE; t.c_cc[VSTOP] = _POSIX_VDISABLE; t.c_cc[VSUSP] = _POSIX_VDISABLE; speed_t speed = baud_bits[cmux_port_speed]; cfsetispeed(&t, speed); cfsetospeed(&t, speed); SYSCHECK(tcsetattr(serial->fd, TCSANOW, &t)); int status = TIOCM_DTR | TIOCM_RTS; ioctl(serial->fd, TIOCMBIS, &status); LOG(LOG_INFO, "Configured serial device"); serial->ping_number = 0; time(&serial->frame_receive_time); //get the current time serial->state = MUX_STATE_INITILIZING; return 0;}int start_muxer( Serial* serial ){ LOG(LOG_INFO, "Configuring modem"); char gsm_command[100]; if (chat(serial->fd, "\r\n\r\n\r\nAT\r\n", 1) < 0) { LOG(LOG_WARNING, "Modem does not respond to AT commands, trying close mux mode"); //if (cmux_mode) we do not know now so write both write_frame(0, NULL, 0, GSM0710_CONTROL_CLD | GSM0710_CR); //else write_frame(0, close_channel_cmd, 2, GSM0710_TYPE_UIH); SYSCHECK(chat(serial->fd, "AT\r\n", 1)); } SYSCHECK(chat(serial->fd, "ATZ\r\n", 3)); SYSCHECK(chat(serial->fd, "ATE0\r\n", 1)); if (0)// additional siemens c35 init { SYSCHECK(snprintf(gsm_command, sizeof(gsm_command), "AT+IPR=%d\r\n", baud_rates[cmux_port_speed])); SYSCHECK(chat(serial->fd, gsm_command, 1)); SYSCHECK(chat(serial->fd, "AT\r\n", 1)); SYSCHECK(chat(serial->fd, "AT&S0\r\n", 1)); SYSCHECK(chat(serial->fd, "AT\\Q3\r\n", 1)); } //SYSCHECK(chat(serial->fd, "AT+CMUX=?\r\n", 1)); if (pin_code >= 0) { LOG(LOG_DEBUG, "send pin %04d", pin_code);//Some modems, such as webbox, will sometimes hang if SIM code//is given in virtual channel SYSCHECK(snprintf(gsm_command, sizeof(gsm_command), "AT+CPIN=%04d\r\n", pin_code)); SYSCHECK(chat(serial->fd, gsm_command, 10)); } SYSCHECK(chat(serial->fd, "AT+CFUN=0\r\n", 10)); SYSCHECK(snprintf(gsm_command, sizeof(gsm_command), "AT+CMUX=%d,%d,%d,%d" //",%d,%d,%d,%d,%d" "\r\n" , cmux_mode , cmux_subset , cmux_port_speed , cmux_N1 //, cmux_T1 //, cmux_N2 //, cmux_T2 //, cmux_T3 //, cmux_k )); LOG(LOG_INFO, "Starting mux mode"); SYSCHECK(chat(serial->fd, gsm_command, 3)); serial->state = MUX_STATE_MUXING; LOG(LOG_INFO, "Waiting for mux-mode"); sleep(1); LOG(LOG_INFO, "Init control channel"); write_frame(0, NULL, 0, GSM0710_TYPE_SABM | GSM0710_PF); GIOChannel* channel = g_io_channel_unix_new(serial->fd); serial->g_source = g_io_add_watch(channel, G_IO_IN | G_IO_HUP, serial_device_read, serial); return 0;}static int close_devices(){ LOG(LOG_DEBUG, "Enter"); g_source_remove(serial.g_source); serial.g_source = -1; int i; for (i=1;i<GSM0710_MAX_CHANNELS;i++) {//terminate command given. Close channels one by one and finaly close//the mux mode if (channellist[i].fd >= 0) { SYSCHECK(dbus_signal_send_deactivate(channellist[i].ptsname)); if (channellist[i].opened) { LOG(LOG_INFO, "Closing down the logical channel %d", i); if (cmux_mode) write_frame(i, NULL, 0, GSM0710_CONTROL_CLD | GSM0710_CR);//multiplexer close down command doesn't work with benqM22a module, use: write_frame(0, NULL, 0, GSM0710_TYPE_DISC | GSM0710_PF); else write_frame(i, close_channel_cmd, 2, GSM0710_TYPE_UIH); SYSCHECK(logical_channel_close(channellist+i)); } LOG(LOG_INFO, "Logical channel %d closed", channellist[i].id); } } if (serial.fd >= 0) { if (cmux_mode) write_frame(0, NULL, 0, GSM0710_CONTROL_CLD | GSM0710_CR); else write_frame(0, close_channel_cmd, 2, GSM0710_TYPE_UIH); static const char* poff = "AT@POFF\r\n"; syslogdump(">s ", (unsigned char *)poff, strlen(poff)); write(serial.fd, poff, strlen(poff)); SYSCHECK(close(serial.fd)); serial.fd = -1; } SYSCHECK(modem_hw_off(serial.pm_base_dir)); serial.state = MUX_STATE_OFF; return 0;}static gboolean watchdog(gpointer data){ LOG(LOG_DEBUG, "Enter"); Serial* serial = (Serial*)data; LOG(LOG_DEBUG, "Serial state is %d", serial->state); switch (serial->state) { case MUX_STATE_OPENING: if (open_serial_device(serial) < 0) LOG(LOG_WARNING, "Could not open all devices and start muxer"); serial->g_source_watchdog = g_timeout_add_seconds(5, watchdog, data); // let the dog watch every 5 sec LOG(LOG_INFO, "Watchdog started"); case MUX_STATE_INITILIZING: if (start_muxer(serial) < 0) LOG(LOG_WARNING, "Could not open all devices and start muxer errno=%d", errno); break; case MUX_STATE_MUXING: if (use_ping) { if (serial->ping_number > use_ping) { LOG(LOG_DEBUG, "no ping reply for %d times, resetting modem", serial->ping_number); serial->state = MUX_STATE_CLOSING; } else { LOG(LOG_DEBUG, "Sending PING to the modem"); //write_frame(0, psc_channel_cmd, sizeof(psc_channel_cmd), GSM0710_TYPE_UI); write_frame(0, test_channel_cmd, sizeof(test_channel_cmd), GSM0710_TYPE_UI); serial->ping_number++; } } if (use_timeout) { time_t current_time; time(¤t_time); //get the current time if (current_time - serial->frame_receive_time > use_timeout) { LOG(LOG_DEBUG, "timeout, resetting modem"); serial->state = MUX_STATE_CLOSING; } } break; case MUX_STATE_CLOSING: close_devices(); serial->state = MUX_STATE_OPENING; break; default: LOG(LOG_WARNING, "Don't know how to handle state %d", serial->state); break; } return 1;}/** * shows how to use this program */static int usage( char *_name){ fprintf(stderr, "\tUsage: %s [options]\n", _name); fprintf(stderr, "Options:\n"); // process control fprintf(stderr, "\t-d: Fork, get a daemon [%s]\n", no_daemon?"no":"yes"); fprintf(stderr, "\t-v: verbose logging\n"); // modem control fprintf(stderr, "\t-s <serial port name>: Serial port device to connect to [%s]\n", serial.devicename); fprintf(stderr, "\t-t <timeout>: reset modem after this number of seconds of silence [%d]\n", use_timeout); fprintf(stderr, "\t-P <pin-code>: PIN code to unlock SIM [%d]\n", pin_code); fprintf(stderr, "\t-p <number>: use ping and reset modem after this number of unanswered pings [%d]\n", use_ping); fprintf(stderr, "\t-x <dir>: power managment base dir [%s]\n", serial.pm_base_dir?serial.pm_base_dir:"<not set>"); // legacy - will be removed fprintf(stderr, "\t-b <baudrate>: mode baudrate [%d]\n", baud_rates[cmux_port_speed]); fprintf(stderr, "\t-m <modem>: Mode (basic, advanced) [%s]\n", cmux_mode?"advanced":"basic"); fprintf(stderr, "\t-f <framsize>: Frame size [%d]\n", cmux_N1); // fprintf(stderr, "\t-h: Show this help message and show current settings.\n"); return -1;}/** * The main program */int main( int argc, char *argv[], char *env[]){ LOG(LOG_DEBUG, "Enter"); int opt; pid_t parent_pid;//for fault tolerance serial.devicename = "/dev/ttySAC0"; while ((opt = getopt(argc, argv, "dvs:t:p:f:h?m:b:P:x:")) > 0) { switch (opt) { case 'v': syslog_level++; break; case 'd': no_daemon = !no_daemon; break; case 'x': serial.pm_base_dir = optarg; break; case 's': serial.devicename = optarg; break; case 't': use_timeout = atoi(optarg); break; case 'p': use_ping = atoi(optarg); break; case 'P': pin_code = atoi(optarg); break; // will be removed if +CMUX? works case 'f': cmux_N1 = atoi(optarg); break; case 'm': if (!strcmp(optarg, "basic")) cmux_mode = 0; else if (!strcmp(optarg, "advanced")) cmux_mode = 1; else cmux_mode = 0; break; case 'b': cmux_port_speed = baud_rate_index(atoi(optarg)); break; default: case '?': case 'h': usage(argv[0]); exit(0); break; } } if (serial.pm_base_dir == NULL) { // auto detect - i hate windows-like-behavior but mickey want's it ;) struct stat sb; int i; static char* fn[] = { "/sys/bus/platform/devices/neo1973-pm-gsm.0", "/sys/bus/platform/devices/gta01-pm-gsm.0", NULL }; for (i=0;fn[i];i++) if (stat(fn[i], &sb) >= 0) { serial.pm_base_dir = fn[i]; LOG(LOG_INFO, "using '%s' as basedir for pm", fn[i]); break; } }//daemonize show time parent_pid = getpid(); if (!no_daemon && daemon(0, 0)) { fprintf(stderr, "Failed to daemonize: %s (%d)", strerror(errno), errno); exit(1); } umask(0);//signals treatment signal(SIGHUP, signal_treatment); signal(SIGPIPE, signal_treatment); signal(SIGKILL, signal_treatment); signal(SIGINT, signal_treatment); signal(SIGUSR1, signal_treatment); signal(SIGTERM, signal_treatment); if (no_daemon) openlog(argv[0], LOG_NDELAY | LOG_PID | LOG_PERROR, LOG_LOCAL0); else openlog(argv[0], LOG_NDELAY | LOG_PID, LOG_LOCAL0); SYSCHECK(dbus_init());//allocate memory for data structures if ((serial.in_buf = gsm0710_buffer_init()) == NULL || (serial.adv_frame_buf = (unsigned char*)malloc((cmux_N1 + 3) * 2 + 2)) == NULL) { LOG(LOG_ALERT, "Out of memory"); exit(-1); } LOG(LOG_DEBUG, "%s %s starting", *argv, revision);//Initialize modem and virtual ports serial.state = MUX_STATE_OPENING; watchdog(&serial);//start waiting for input and forwarding it back and forth -- main_loop = g_main_loop_new(NULL, FALSE); g_main_loop_run(main_loop); // will/may be terminated in signal_treatment g_main_loop_unref(main_loop);//finalize everything SYSCHECK(close_devices()); free(serial.adv_frame_buf); gsm0710_buffer_destroy(serial.in_buf); LOG(LOG_INFO, "Received %ld frames and dropped %ld received frames during the mux-mode", serial.in_buf->received_count, serial.in_buf->dropped_count); SYSCHECK(dbus_deinit()); LOG(LOG_DEBUG, "%s finished", argv[0]); closelog();// close syslog return 0;}// vim:path=/usr/include,/usr/include/glib-2.0,/usr/include/dbus-1.0,src:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -