📄 modemutil.c
字号:
/* voifax low level modem interface library * Copyright (C) 2004 Simone Freddio & Andrea Emanuelli * * 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 */#include "modemutil.h"#include "common.h"#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <string.h>#include <sys/select.h>#include <termios.h>#include <stdio.h>#include <stdlib.h>#include "util.h"#include "libconfig.h"/* Local prototypes *//* Chiama le callbacks associate per i dati contenuti in un buffer */int call_handlers(t_modem *modem, char *buf, int size);int search_free_handler(t_modem *modem);int from_num_to_bps(int num);/* Local functions */int call_handlers(t_modem *modem, char *buf, int size){ char module[] = "call_handlers"; int a = 0; int c = 0; char args[100]; /* Scorrimento buffer dati */ for (c = 0; c < size; c++) { /* Controllo per ogni handler installato */ for (a = 0; a < MODEM_MAX_HANDLERS; a++) { /* Controllo se l'handler attuale e' attivo */ if (modem->handlers[a].str[0] != 0 && modem->handlers[a].callback != NULL) { /* Check fine buffer */ if (c + modem->handlers[a].len < size) { /* Confronto chiave */ if(!memcmp(&buf[c], modem->handlers[a].str, modem->handlers[a].len)) { /* La chiave e' contenuta nel buffer di ricezione */ memset(args, 0, sizeof(args)); memmove(args, &buf[c + modem->handlers[a].len], modem->handlers[a].arg_chars); /* Verifica il caso in cui è un falso <DLE> */ if (buf[c] == 0x10 && buf[c + 1] == 0x10) { /* Nel qual caso, salta il successivo carattere dall'analisi */ c++; } else { /* Altrimenti esegui la callback */ if (!modem->handlers[a].callback(args)) { TRC(TRC_ERR, module, "Event handler failed!"); return false; } } } }/* else TRC("Last buffer characters = EVENT!!!");*/ } } } return true;}int search_free_handler(t_modem *modem){ int a = 0; for (a = 0; a < MODEM_MAX_HANDLERS; a++) { if (modem->handlers[a].str[0] == 0 && modem->handlers[a].callback == NULL) { return a; } } return -1;}#define BPS_MATCH(num) case num: return B##num; break;int from_num_to_bps(int num){ switch (num) { BPS_MATCH(50); BPS_MATCH(75); BPS_MATCH(110); BPS_MATCH(134); BPS_MATCH(150); BPS_MATCH(200); BPS_MATCH(300); BPS_MATCH(600); BPS_MATCH(1200); BPS_MATCH(1800); BPS_MATCH(2400); BPS_MATCH(4800); BPS_MATCH(9600); BPS_MATCH(19200); BPS_MATCH(38400); BPS_MATCH(57600); BPS_MATCH(115200); BPS_MATCH(230400); BPS_MATCH(460800); BPS_MATCH(500000); BPS_MATCH(576000); BPS_MATCH(921600); BPS_MATCH(1000000); BPS_MATCH(1152000); BPS_MATCH(1500000); BPS_MATCH(2000000); BPS_MATCH(2500000); BPS_MATCH(3000000); BPS_MATCH(3500000); BPS_MATCH(4000000); default: return -1; }}#undef BPS_MATCH/* Exported functions */int modem_init(t_modem *modem, char *dev){ char module[] = "modem_init"; char whole_dev[100]; char trc[300]; struct termios new_term; struct termios old_term; int ret; sprintf(whole_dev, "%s/%s", libconfig_getvalue(dev, "device_path", "/dev"), dev); /* Apertura device di lettura*/ modem->r_fd = open(whole_dev, O_RDONLY | O_NONBLOCK | O_NOCTTY, 0); if (modem->r_fd == -1) { TRC(TRC_ERR, module, "Unable to open serial device (read)"); return false; } modem->w_fd = open(libconfig_getvalue(dev, "write_dev", whole_dev), O_WRONLY | O_NONBLOCK | O_NOCTTY, 0); if (modem->w_fd == -1) { TRC(TRC_ERR, module, "Unable to open serial device (read)"); return false; } /* Impostazione dati di configurazione */ strcpy(modem->dev, dev); strcpy(modem->full_dev, whole_dev); modem->seek_end = atoi(libconfig_getvalue(dev, "seek_end", "0")); modem->retries = atoi(libconfig_getvalue(dev, "retries", "10")); modem->response_timeout.tv_sec = atoi(libconfig_getvalue(dev, "timeout_sec", "0")); modem->response_timeout.tv_usec = atoi(libconfig_getvalue(dev, "timeout_usec", "100000")); modem->response_initialsleep = 0; modem->baudrate = atoi(libconfig_getvalue(dev, "baudrate", "115200")); modem->baudrate_const = from_num_to_bps(modem->baudrate); memset(modem->handlers, 0, sizeof(modem->handlers)); sprintf(trc, "Timeouts: sec %d, usec %d, retries %d", (int)modem->response_timeout.tv_sec, (int)modem->response_timeout.tv_usec, modem->retries); TRC(TRC_INFO, module, trc); if (strcmp( libconfig_getvalue(dev, "skip_serial_init", "0"), "1") == 0) { TRC(TRC_WARN, module, "Skipping serial init..."); return true; } /* TODO: Controllare le seguenti impostazioni della seriale! Quelle che ci sono adesso le ho copiate da un frammento di codice di un programma che comunica via seriale e che funziona :))) */ /* Parte di inizializzazione porta seriale */ ret=tcgetattr(modem->r_fd, &old_term); if( ret== -1 ) { TRC(TRC_ERR, module, "Error on getattr"); return false; } memset((void *)&new_term, '\0', sizeof(new_term)); new_term.c_cflag = CS8 | CLOCAL | CREAD | CRTSCTS; new_term.c_iflag = 0; new_term.c_lflag = 0; new_term.c_oflag = 0; new_term.c_cc[VINTR] = 0; new_term.c_cc[VMIN] = 1; new_term.c_cc[VTIME] = 0; sprintf(trc, "Port %s baudrate: %d", dev, modem->baudrate); TRC(TRC_INFO, module, trc); ret = cfsetospeed(&new_term, modem->baudrate_const); if (ret == -1) { TRC(TRC_ERR, module, "Failed cfsetospeed"); return false; } ret = cfsetispeed(&new_term, modem->baudrate_const); if (ret == -1) { TRC(TRC_ERR, module, "Failed cfsetispeed"); return false; } ret = tcsetattr(modem->r_fd, TCSANOW, &new_term); if (ret == -1) { TRC(TRC_ERR, module, "Failed tcsetattr"); return false; } return true;}int modem_close(t_modem *modem){ char module[] = "modem_close"; int ret; ret = close(modem->r_fd); if (ret == -1) { TRC(TRC_ERR, module, "Unable to close device (read)"); return false; } ret = close(modem->w_fd); if (ret == -1) { TRC(TRC_ERR, module, "Unable to close device (write)"); return false; } memset(modem, 0, sizeof(t_modem)); return true;}int modem_sendcmd(t_modem *modem, char *cmd){ char module[] = "modem_sendcmd"; int bytes, len; char cmd_to_send[100]; /* Aggiunta \n alla stringa */ sprintf(cmd_to_send, "%s\r", cmd); len = strlen(cmd_to_send);/* if (modem->seek_end) lseek(modem->fd, 0, SEEK_END);*/ bytes = write(modem->w_fd, cmd_to_send, len); if (bytes == -1) { TRC(TRC_ERR, module, "Write error on fd"); return false; } if (bytes != len) { TRC(TRC_ERR, module, "Communication broken"); return false; } return true;}int modem_receiveresp(t_modem *modem, char *buf, int maxlen, int clean_resp){ char module[] = "modem_receiveresp"; struct timeval tv; fd_set set; int retsel = 1, bytes = 0, totread = 0; /*TRC(TRC_INFO, module, "Start");*/ memset(buf, 0, maxlen); while (retsel > 0 && totread < maxlen) { /* Delay iniziale per l'attesa dati */ usleep(modem->response_initialsleep); FD_ZERO(&set); FD_SET(modem->r_fd, &set); memcpy(&tv, &modem->response_timeout, sizeof(tv)); /* Attesa dati in coda (esce con timeout */ retsel = select(modem->r_fd + 1, &set, NULL, NULL, &tv); if (retsel > 0) { if (FD_ISSET(modem->r_fd, &set)) { /* Dati ricevuti, lettura dalla porta */ bytes = read(modem->r_fd, &buf[totread], maxlen - totread); /*TRC(TRC_INFO, module, buf);*/ if (bytes != 0) { /* Verifica e chiamata handlers */ if (!call_handlers(modem, &buf[totread], bytes)) { TRC(TRC_ERR, module, "Failed handler!"); return -1; } } else retsel = 0; totread += bytes; } else { TRC(TRC_ERR, module, "Fd mismatch?"); return -1; } } } /*TRC(TRC_INFO, module, "End");*/ if (retsel < 0) { TRC(TRC_ERR, module, "Error on select!"); return -1; } if (clean_resp) { remove_special_chars(buf); } return totread;}int modem_chat(t_modem *modem, char *cmd, char *resp){ char module[] = "modem_chat"; char curr_resp[200]; int readed; char trc[300]; int found = false, timeout = modem->retries; sprintf(trc, "Command to send: '%s'", cmd); TRC(TRC_INFO, module, trc); if (!modem_sendcmd(modem, cmd)) { TRC(TRC_ERR, module, "Chat send failed"); return -1; } if (strlen(resp) != 0) { while (found == false && timeout != 0) { readed = modem_receiveresp(modem, curr_resp, sizeof(curr_resp), true); if (readed == -1) { TRC(TRC_ERR, module, "Chat receiveresp failed"); return -1; } if (readed < (int)sizeof(curr_resp)) timeout--; sprintf(trc, "Response received: '%s', %d", curr_resp, readed); TRC(TRC_INFO, module, trc); found = memory_search(curr_resp, readed, resp, strlen(resp)) == -1 ? false : true; sprintf(trc, "Response compare: '%s', %d", found ? "true" : "false", timeout); TRC(TRC_INFO, module, trc); } } return found;}int modem_chat_timeout(t_modem *modem, char *cmd, char *resp, int sec, int usec){ int o_sec = modem->response_timeout.tv_sec; int o_usec = modem->response_timeout.tv_usec; int ret; modem->response_timeout.tv_sec = sec; modem->response_timeout.tv_usec = usec; ret = modem_chat(modem, cmd, resp); modem->response_timeout.tv_sec = o_sec; modem->response_timeout.tv_usec = o_usec; return ret;}int modem_add_handler(t_modem *modem, t_callback *callback, char *str, int chars_to_get){ char module[] = "modem_add_handler"; int hndl = search_free_handler(modem); if (hndl == -1) { TRC(TRC_ERR, module, "No free handlers!"); return false; } strcpy(modem->handlers[hndl].str, str); modem->handlers[hndl].callback = callback; modem->handlers[hndl].len = strlen(str); modem->handlers[hndl].arg_chars = chars_to_get; return true;}int modem_remove_handler(t_modem *modem, t_callback *callback){ int a = 0; for (a = 0; a < MODEM_MAX_HANDLERS; a++) { if (modem->handlers[a].callback == callback) { memset(&modem->handlers[a], 0, sizeof(modem->handlers[a])); return true; } } return false;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -