blob: 9abeb4b96b1469ce084b0fcb25494dec28c4226a [file] [log] [blame]
#define ql_system system
#define GSM0710_DEBUG 0
/*MUX defines */
#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*10)
#define DATABITS CS8
#define BAUD B115200
#define STOPBITS 0
#define PARITYON 0
#define PARITY 0
/**************************/
/* 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;
unsigned int datacount;
int newdataready; /*newdataready = 1: new data written to internal buffer. newdataready=0: acknowledged by assembly thread*/
int input_sleeping; /*input_sleeping = 1 if ser_read_thread (input to buffer) is waiting because buffer is full */
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;
typedef struct Channel // Channel data
{
int id; // gsm 07 10 channel id
char* devicename;
int fd;
int opened;
unsigned char v24_signals;
char* ptsname;
char* ptslinkname;
char* origin;
int remaining;
unsigned char *tmp;
int reopen;
int disc_ua_pending;
} 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;
int fd;
MuxerStates state;
GSM0710_Buffer *in_buf;// input buffer
unsigned char *adv_frame_buf;
time_t frame_receive_time;
int ping_number;
} Serial;
/* Struct is used for passing fd, read function and read funtion arg to a device polling thread */
typedef struct Poll_Thread_Arg
{
int fd;
int (*read_function_ptr)(void *);
void * read_function_arg;
}Poll_Thread_Arg;
static int watchdog(Serial * serial);
static int close_devices();
static int thread_serial_device_read(void * vargp);
static int pseudo_device_read(void * vargp);
static void* poll_thread(void* vargp);
static void* assemble_frame_thread(void* vargp);
static int create_thread(pthread_t * thread_id, void * thread_function, void * thread_function_arg );
static void set_main_exit_signal(int signal);
static int restart_pty_interface(Channel* channel);
static char *get_cur_time();
#define LOGMUX(lvl,f,...) do{if(lvl<=syslog_level){\
fprintf(stderr,"%s %d:%s(): " f "\n", get_cur_time(), __LINE__, __FUNCTION__, ##__VA_ARGS__);\
}\
}while(0)
#define SYSCHECK(c) do{if((c)<0){LOGMUX(LOG_ERR,"system-error: '%s' (code: %d)", strerror(errno), errno);\
return -1;}\
}while(0)
#define gsm0710_buffer_inc(readp,datacount) do { readp++; datacount--; \
if (readp == buf->endp) readp = buf->data; \
} while (0)
#define gsm0710_buffer_length(buf) (buf->datacount)
#define gsm0710_buffer_free(buf) (GSM0710_BUFFER_SIZE - buf->datacount)
#define STATE_CASE(state) case state: return #state;
static unsigned char close_channel_cmd[] = { GSM0710_CONTROL_CLD | GSM0710_CR, GSM0710_EA | (0 << 1) };
/* crc table from gsm0710 spec */
static 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, };
// serial io
static Serial serial;
// muxed io channels
static Channel channellist[GSM0710_MAX_CHANNELS]; // remember: [0] is not used acticly because it's the control channel
static int cmux_mode = 0;
static int cmux_port_speed = 5; //115200 baud rate
static int cmux_N1 = 2407;//1509;
static int baud_rates[] = {
0, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600,1500000
};
static speed_t baud_bits[] = {
0, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B921600, B1500000,
};
static char* revision = "$Rev: 1 $";
static int no_daemon = 0;
static int syslog_level = LOG_ERR;//LOG_ERR;
static int vir_ports = 4; /* number of virtual ports to create */
static char *dev_symlink_prefix = "/dev/ttyMux";//"/dev/ttyMux";NULL;
/*misc global vars */
static int main_exit_signal=0; /* 1:main() received exit signal */
static int uih_pf_bit_received = 0;
static unsigned int pts_reopen=0; /*If != 0, signals watchdog that one cahnnel needs to be reopened */
/*pthread */
pthread_t ser_read_thread;
pthread_t frame_assembly_thread;
pthread_t pseudo_terminal[GSM0710_MAX_CHANNELS-1]; /* -1 because control channel cannot be mapped to pseudo-terminal /dev/pts */
pthread_cond_t newdataready_signal = PTHREAD_COND_INITIALIZER;
pthread_cond_t bufferready_signal = PTHREAD_COND_INITIALIZER;
pthread_attr_t thread_attr;
pthread_mutex_t syslogdump_lock;
pthread_mutex_t write_frame_lock;
pthread_mutex_t main_exit_signal_lock;
pthread_mutex_t pts_reopen_lock;
pthread_mutex_t datacount_lock;
pthread_mutex_t newdataready_lock;
pthread_mutex_t bufferready_lock;