| |
| #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; |
| |
| |