/* Copyright (C) 2009-2015 bg http://www.e1550.mobi Artem Makhutov http://www.makhutov.org Dmitry Vagin */ #ifndef CHAN_DONGLE_H_INCLUDED #define CHAN_DONGLE_H_INCLUDED #include "ast_config.h" #include #include #include "ast_compat.h" /* asterisk compatibility fixes */ #include "mixbuffer.h" /* struct mixbuffer */ //#include "ringbuffer.h" /* struct ringbuffer */ #include "cpvt.h" /* struct cpvt */ #include "export.h" /* EXPORT_DECL EXPORT_DEF */ #include "dc_config.h" /* pvt_config_t */ #include "at_command.h" #define MODULE_DESCRIPTION "Huawei 3G Dongle Channel Driver" #define MAXDONGLEDEVICES 128 INLINE_DECL const char * dev_state2str(dev_state_t state) { return enum2str(state, dev_state_strs, ITEMS_OF(dev_state_strs)); } INLINE_DECL const char * dev_state2str_msg(dev_state_t state) { static const char * const states[] = { "Stop scheduled", "Restart scheduled", "Removal scheduled", "Start scheduled" }; return enum2str(state, states, ITEMS_OF(states)); } #if ASTERISK_VERSION_NUM >= 100000 && ASTERISK_VERSION_NUM < 130000 /* 10-13 */ /* Only linear is allowed */ EXPORT_DECL struct ast_format chan_dongle_format; EXPORT_DECL struct ast_format_cap * chan_dongle_format_cap; #endif /* ^10-13 */ typedef enum { RESTATE_TIME_NOW = 0, RESTATE_TIME_GRACEFULLY, RESTATE_TIME_CONVENIENT, } restate_time_t; /* state */ typedef struct pvt_state { char audio_tty[DEVPATHLEN]; /*!< tty for audio connection */ char data_tty[DEVPATHLEN]; /*!< tty for AT commands */ uint32_t at_tasks; /*!< number of active tasks in at_queue */ uint32_t at_cmds; /*!< number of active commands in at_queue */ uint32_t chansno; /*!< number of channels in channels list */ uint8_t chan_count[CALL_STATES_NUMBER]; /*!< channel number grouped by state */ } pvt_state_t; #define PVT_STATE_T(state, name) ((state)->name) /* statictics */ typedef struct pvt_stat { uint32_t at_tasks; /*!< number of tasks added to queue */ uint32_t at_cmds; /*!< number of commands added to queue */ uint32_t at_responses; /*!< number of responses handled */ uint32_t d_read_bytes; /*!< number of bytes of commands actually read from device */ uint32_t d_write_bytes; /*!< number of bytes of commands actually written to device */ uint64_t a_read_bytes; /*!< number of bytes of audio read from device */ uint64_t a_write_bytes; /*!< number of bytes of audio written to device */ uint32_t read_frames; /*!< number of frames read from device */ uint32_t read_sframes; /*!< number of truncated frames read from device */ uint32_t write_frames; /*!< number of tries to frame write */ uint32_t write_tframes; /*!< number of truncated frames to write */ uint32_t write_sframes; /*!< number of silence frames to write */ uint64_t write_rb_overflow_bytes; /*!< number of overflow bytes */ uint32_t write_rb_overflow; /*!< number of times when a_write_rb overflowed */ uint32_t in_calls; /*!< number of incoming calls not including waiting */ uint32_t cw_calls; /*!< number of waiting calls */ uint32_t out_calls; /*!< number of all outgoing calls attempts */ uint32_t in_calls_handled; /*!< number of ncoming/waiting calls passed to dialplan */ uint32_t in_pbx_fails; /*!< number of start_pbx fails */ uint32_t calls_answered[2]; /*!< number of outgoing and incoming/waiting calls answered */ uint32_t calls_duration[2]; /*!< seconds of outgoing and incoming/waiting calls */ } pvt_stat_t; #define PVT_STAT_T(stat, name) ((stat)->name) struct at_queue_task; typedef unsigned int sms_inbox_item_type; #define SMS_INBOX_ITEM_BITS (sizeof(sms_inbox_item_type) * 8) #define SMS_INBOX_ARRAY_SIZE ((SMS_INDEX_MAX + SMS_INBOX_ITEM_BITS - 1) / SMS_INBOX_ITEM_BITS) typedef struct pvt { AST_LIST_ENTRY (pvt) entry; /*!< linked list pointers */ ast_mutex_t lock; /*!< pvt lock */ AST_LIST_HEAD_NOLOCK (, at_queue_task) at_queue; /*!< queue for commands to modem */ AST_LIST_HEAD_NOLOCK (, cpvt) chans; /*!< list of channels */ struct cpvt sys_chan; /*!< system channel */ struct cpvt *last_dialed_cpvt; /*!< channel what last call successfully set ATDnum; leave until ^ORIG received; need because real call idx of dialing call unknown until ^ORIG */ pthread_t monitor_thread; /*!< monitor (at commands reader) thread handle */ int audio_fd; /*!< audio descriptor */ int data_fd; /*!< data descriptor */ char * alock; /*!< name of lockfile for audio */ char * dlock; /*!< name of lockfile for data */ struct ast_dsp* dsp; /*!< silence/DTMF detector - FIXME: must be in cpvt */ dc_dtmf_setting_t real_dtmf; /*!< real DTMF setting */ struct ast_timer* a_timer; /*!< audio write timer */ char a_write_buf[FRAME_SIZE * 5]; /*!< audio write buffer */ struct mixbuffer a_write_mixb; /*!< audio mix buffer */ // struct ringbuffer a_write_rb; /*!< audio ring buffer */ // char a_read_buf[FRAME_SIZE + AST_FRIENDLY_OFFSET]; /*!< audio read buffer */ // struct ast_frame a_read_frame; /*!< read frame buffer */ char dtmf_digit; /*!< last DTMF digit */ struct timeval dtmf_begin_time; /*!< time of begin of last DTMF digit */ struct timeval dtmf_end_time; /*!< time of end of last DTMF digit */ int timeout; /*!< used to set the timeout for data */ #define DATA_READ_TIMEOUT 10000 /* 10 seconds */ unsigned long channel_instance; /*!< number of channels created on this device */ unsigned int rings; /*!< ring/ccwa number distributed to at_response_clcc() */ /* device state */ int gsm_reg_status; int rssi; int linkmode; int linksubmode; char provider_name[32]; char manufacturer[32]; char model[32]; char firmware[32]; char imei[17]; char imsi[17]; char subscriber_number[128]; char location_area_code[8]; char cell_id[8]; char sms_scenter[20]; unsigned int incoming_sms_index; sms_inbox_item_type incoming_sms_inbox[SMS_INBOX_ARRAY_SIZE]; volatile unsigned int connected:1; /*!< do we have an connection to a device */ unsigned int initialized:1; /*!< whether a service level connection exists or not */ unsigned int gsm_registered:1; /*!< do we have an registration to a GSM */ unsigned int dialing; /*!< HW state; true from ATD response OK until CEND or CONN for this call idx */ unsigned int ring:1; /*!< HW state; true if has incoming call from first RING until CEND or CONN */ unsigned int cwaiting:1; /*!< HW state; true if has incoming call waiting from first CCWA until CEND or CONN for */ unsigned int outgoing_sms:1; /*!< outgoing sms */ unsigned int volume_sync_step:2; /*!< volume synchronized stage */ #define VOLUME_SYNC_BEGIN 0 #define VOLUME_SYNC_DONE 3 unsigned int has_sms:1; /*!< device has SMS support */ unsigned int has_voice:1; /*!< device has voice call support */ unsigned int has_voice_quectel:1; /*!< device has Quectel voice call support */ unsigned int has_call_waiting:1; /*!< call waiting enabled on device */ unsigned int group_last_used:1; /*!< mark the last used device */ unsigned int prov_last_used:1; /*!< mark the last used device */ unsigned int sim_last_used:1; /*!< mark the last used device */ unsigned int terminate_monitor:1; /*!< non-zero if we want terminate monitor thread i.e. restart, stop, remove */ // unsigned int off:1; /*!< device not used */ // unsigned int prevent_new:1; /*!< prevent new usage */ unsigned int has_subscriber_number:1; /*!< subscriber_number field is valid */ // unsigned int monitor_running:1; /*!< true if monitor thread is running */ unsigned int must_remove:1; /*!< mean must removed from list: NOT FULLY THREADSAFE */ volatile dev_state_t desired_state; /*!< desired state */ volatile restate_time_t restart_time; /*!< time when change state */ volatile dev_state_t current_state; /*!< current state */ pvt_config_t settings; /*!< all device settings from config file */ pvt_state_t state; /*!< state */ pvt_stat_t stat; /*!< various statistics */ } pvt_t; #define CONF_GLOBAL(name) (gpublic->global_settings.name) #define SCONF_GLOBAL(state, name) ((state)->global_settings.name) #define CONF_SHARED(pvt, name) SCONFIG(&((pvt)->settings), name) #define CONF_UNIQ(pvt, name) UCONFIG(&((pvt)->settings), name) #define PVT_ID(pvt) UCONFIG(&((pvt)->settings), id) #define PVT_STATE(pvt, name) PVT_STATE_T(&(pvt)->state, name) #define PVT_STAT(pvt, name) PVT_STAT_T(&(pvt)->stat, name) typedef struct public_state { AST_RWLIST_HEAD(devices, pvt) devices; ast_mutex_t discovery_lock; pthread_t discovery_thread; /* The discovery thread handler */ volatile int unloading_flag; /* no need mutex or other locking for protect this variable because no concurent r/w and set non-0 atomically */ struct dc_gconfig global_settings; } public_state_t; EXPORT_DECL public_state_t * gpublic; EXPORT_DEF int sms_inbox_set(struct pvt* pvt, int index); EXPORT_DEF int sms_inbox_clear(struct pvt* pvt, int index); EXPORT_DEF int is_sms_inbox_set(const struct pvt* pvt, int index); EXPORT_DECL void clean_read_data(const char * devname, int fd); EXPORT_DECL int pvt_get_pseudo_call_idx(const struct pvt * pvt); EXPORT_DECL int ready4voice_call(const struct pvt* pvt, const struct cpvt * current_cpvt, int opts); EXPORT_DECL int is_dial_possible(const struct pvt * pvt, int opts); EXPORT_DECL const char * pvt_str_state(const struct pvt* pvt); EXPORT_DECL struct ast_str * pvt_str_state_ex(const struct pvt* pvt); EXPORT_DECL const char * GSM_regstate2str(int gsm_reg_status); EXPORT_DECL const char * sys_mode2str(int sys_mode); EXPORT_DECL const char * sys_submode2str(int sys_submode); EXPORT_DECL char* rssi2dBm(int rssi, char* buf, unsigned len); EXPORT_DECL void pvt_on_create_1st_channel(struct pvt* pvt); EXPORT_DECL void pvt_on_remove_last_channel(struct pvt* pvt); EXPORT_DECL void pvt_reload(restate_time_t when); EXPORT_DECL int pvt_enabled(const struct pvt * pvt); EXPORT_DECL void pvt_try_restate(struct pvt * pvt); EXPORT_DECL int opentty (const char* dev, char ** lockfile); EXPORT_DECL void closetty(int fd, char ** lockfname); EXPORT_DECL int lock_try(const char * devname, char ** lockname); EXPORT_DECL struct pvt * find_device_ex(struct public_state * state, const char * name); INLINE_DECL struct pvt * find_device (const char* name) { return find_device_ex(gpublic, name); } EXPORT_DECL struct pvt * find_device_ext(const char* name); EXPORT_DECL struct pvt * find_device_by_resource_ex(struct public_state * state, const char * resource, int opts, const struct ast_channel * requestor, int * exists); EXPORT_DECL void pvt_dsp_setup(struct pvt * pvt, const char * id, dc_dtmf_setting_t dtmf_new); INLINE_DECL struct pvt * find_device_by_resource(const char * resource, int opts, const struct ast_channel * requestor, int * exists) { return find_device_by_resource_ex(gpublic, resource, opts, requestor, exists); } EXPORT_DECL struct ast_module * self_module(); #define PVT_NO_CHANS(pvt) (PVT_STATE(pvt, chansno) == 0) #endif /* CHAN_DONGLE_H_INCLUDED */