struct zap_span *span;
struct zap_io_interface *zio;
zap_hash_t *variable_hash;
+ unsigned char cas_bits;
};
*/
int zap_config_next_pair(zap_config_t * cfg, char **var, char **val);
+/*!
+ \brief Retrieve the CAS bits from a configuration string value
+ \param strvalue pointer to the configuration string value (expected to be in format whatever:xxxx)
+ \param outbits pointer to aim at the CAS bits
+*/
+int zap_config_get_cas_bits(char *strvalue, unsigned char *outbits);
+
/** @} */
#endif
ZAP_OOB_ALARM_TRAP,
ZAP_OOB_ALARM_CLEAR,
ZAP_OOB_NOOP,
+ ZAP_OOB_CAS_BITS_CHANGE,
ZAP_OOB_INVALID
} zap_oob_event_t;
-#define OOB_STRINGS "DTMF", "ONHOOK", "OFFHOOK", "WINK", "FLASH", "RING_START", "RING_STOP", "ALARM_TRAP", "ALARM_CLEAR", "NOOP", "INVALID"
+#define OOB_STRINGS "DTMF", "ONHOOK", "OFFHOOK", "WINK", "FLASH", "RING_START", "RING_STOP", "ALARM_TRAP", "ALARM_CLEAR", "NOOP", "CAS_BITS_CHANGE", "INVALID"
ZAP_STR2ENUM_P(zap_str2zap_oob_event, zap_oob_event2str, zap_oob_event_t)
typedef enum {
ZAP_COMMAND_DISABLE_ECHOCANCEL,
ZAP_COMMAND_ENABLE_ECHOTRAIN,
ZAP_COMMAND_DISABLE_ECHOTRAIN,
+ ZAP_COMMAND_SET_CAS_BITS,
+ ZAP_COMMAND_GET_CAS_BITS,
ZAP_COMMAND_COUNT
} zap_command_t;
ZAP_CHAN_TYPE_FXS,
ZAP_CHAN_TYPE_FXO,
ZAP_CHAN_TYPE_EM,
+ ZAP_CHAN_TYPE_CAS,
ZAP_CHAN_TYPE_COUNT
} zap_chan_type_t;
-#define CHAN_TYPE_STRINGS "B", "DQ921", "DQ931", "FXS", "FXO", "EM", "INVALID"
+#define CHAN_TYPE_STRINGS "B", "DQ921", "DQ931", "FXS", "FXO", "EM", "CAS", "INVALID"
ZAP_STR2ENUM_P(zap_str2zap_chan_type, zap_chan_type2str, zap_chan_type_t)
typedef enum {
return ZAP_SUCCESS;
}
-static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start, unsigned end, zap_chan_type_t type, char *name, char *number)
+static unsigned char wanpipe_swap_bits(unsigned char cas_bits)
+{
+ unsigned char swapped_bits = 0x0;
+ if (cas_bits & 0x8) {
+ swapped_bits |= 0x1;
+ }
+ if (cas_bits & 0x4) {
+ swapped_bits |= 0x2;
+ }
+ if (cas_bits & 0x2) {
+ swapped_bits |= 0x4;
+ }
+ if (cas_bits & 0x1) {
+ swapped_bits |= 0x8;
+ }
+ return swapped_bits;
+}
+
+static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start, unsigned end, zap_chan_type_t type, char *name, char *number, unsigned char cas_bits)
{
unsigned configured = 0, x;
+ if (type == ZAP_CHAN_TYPE_CAS) {
+ zap_log(ZAP_LOG_DEBUG, "Configuring CAS channels with abcd == 0x%X\n", cas_bits);
+ }
for(x = start; x < end; x++) {
zap_channel_t *chan;
zap_socket_t sockfd = WP_INVALID_SOCKET;
chan->native_codec = chan->effective_codec = ZAP_CODEC_ULAW;
}
}
+
+ if (type == ZAP_CHAN_TYPE_CAS) {
+ tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_WRITE_RBS_BITS;
+ tdm_api.wp_tdm_cmd.rbs_tx_bits = wanpipe_swap_bits(cas_bits);
+ wp_tdm_cmd_exec(chan, &tdm_api);
+ }
if (!zap_strlen_zero(name)) {
zap_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
static ZIO_CONFIGURE_SPAN_FUNCTION(wanpipe_configure_span)
{
int items, i;
- char *mydata, *item_list[10];
+ char *mydata, *item_list[10];
char *sp, *ch, *mx;
+ unsigned char cas_bits = 0;
int channo;
int spanno;
int top = 0;
zap_log(ZAP_LOG_ERROR, "Invalid range number %d\n", top);
continue;
}
-
- configured += wp_open_range(span, spanno, channo, top, type, name, number);
+ if (ZAP_CHAN_TYPE_CAS == type && zap_config_get_cas_bits(ch, &cas_bits)) {
+ zap_log(ZAP_LOG_ERROR, "Failed to get CAS bits in CAS channel\n");
+ continue;
+ }
+ configured += wp_open_range(span, spanno, channo, top, type, name, number, cas_bits);
}
zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8);
}
break;
+ case ZAP_COMMAND_SET_CAS_BITS:
+ {
+ tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_WRITE_RBS_BITS;
+ tdm_api.wp_tdm_cmd.rbs_tx_bits = wanpipe_swap_bits(ZAP_COMMAND_OBJ_INT);
+ err = wp_tdm_cmd_exec(zchan, &tdm_api);
+ }
+ break;
+ case ZAP_COMMAND_GET_CAS_BITS:
+ {
+ /* wanpipe does not has a command to get the CAS bits so we emulate it */
+ ZAP_COMMAND_OBJ_INT = zchan->cas_bits;
+ }
+ break;
default:
break;
};
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? ZAP_OOB_ONHOOK : ZAP_OOB_OFFHOOK;
}
break;
+ case WP_TDMAPI_EVENT_RBS:
+ {
+ event_id = ZAP_OOB_CAS_BITS_CHANGE;
+ /* save the CAS bits, user should retrieve it with ZAP_COMMAND_GET_CAS_BITS
+ is there a best play to store this? instead of adding cas_bits member to zap_chan? */
+ span->channels[i]->cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
+ }
+ break;
default:
{
zap_log(ZAP_LOG_WARNING, "Unhandled event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event);
ZIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event);
-static unsigned zt_open_range(zap_span_t *span, unsigned start, unsigned end, zap_chan_type_t type, char *name, char *number)
+static unsigned zt_open_range(zap_span_t *span, unsigned start, unsigned end, zap_chan_type_t type, char *name, char *number, unsigned char cas_bits)
{
unsigned configured = 0, x;
char path[] = "/dev/zap/channel";
memset(&ztp, 0, sizeof(ztp));
+ if (type == ZAP_CHAN_TYPE_CAS) {
+ zap_log(ZAP_LOG_DEBUG, "Configuring CAS channels with abcd == 0x%X\n", cas_bits);
+ }
for(x = start; x < end; x++) {
zap_channel_t *zchan;
zap_socket_t sockfd = ZT_INVALID_SOCKET;
}
}
+ if (type == ZAP_CHAN_TYPE_CAS) {
+ struct zt_chanconfig cc;
+ memset(&cc, 0, sizeof(cc));
+ cc.chan = cc.master = x;
+ cc.sigtype = ZT_SIG_CAS;
+ cc.idlebits = cas_bits;
+ if (ioctl(CONTROL_FD, ZT_CHANCONFIG, &cc)) {
+ zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d err:%s", path, zchan->span_id, zchan->chan_id, sockfd, strerror(errno));
+ close(sockfd);
+ continue;
+ }
+ }
+
if (zchan->type != ZAP_CHAN_TYPE_DQ921 && zchan->type != ZAP_CHAN_TYPE_DQ931) {
len = zt_globals.codec_ms * 8;
if (ioctl(zchan->sockfd, ZT_SET_BLOCKSIZE, &len)) {
{
int items, i;
- char *mydata, *item_list[10];
+ char *mydata, *item_list[10];
char *ch, *mx;
+ unsigned char cas_bits = 0;
int channo;
int top = 0;
unsigned configured = 0;
zap_log(ZAP_LOG_ERROR, "Invalid range number %d\n", top);
continue;
}
-
- configured += zt_open_range(span, channo, top, type, name, number);
+ if (ZAP_CHAN_TYPE_CAS == type && zap_config_get_cas_bits(ch, &cas_bits)) {
+ zap_log(ZAP_LOG_ERROR, "Failed to get CAS bits in CAS channel\n");
+ continue;
+ }
+ configured += zt_open_range(span, channo, top, type, name, number, cas_bits);
}
}
}
break;
+ case ZAP_COMMAND_SET_CAS_BITS:
+ {
+ int bits = ZAP_COMMAND_OBJ_INT;
+ err = ioctl(zchan->sockfd, ZT_SETTXBITS, &bits);
+ }
+ break;
+ case ZAP_COMMAND_GET_CAS_BITS:
+ {
+ /* probably we should call ZT_GETRXBITS instead? */
+ ZAP_COMMAND_OBJ_INT = zchan->cas_bits;
+ }
+ break;
default:
break;
};
event_id = ZAP_OOB_ALARM_CLEAR;
}
break;
+ case ZT_EVENT_BITSCHANGED:
+ {
+ event_id = ZAP_OOB_CAS_BITS_CHANGE;
+ int bits = 0;
+ int err = ioctl(span->channels[i]->sockfd, ZT_GETRXBITS, &bits);
+ if (err) {
+ return ZAP_FAIL;
+ }
+ span->channels[i]->cas_bits = bits;
+ }
+ break;
default:
{
zap_log(ZAP_LOG_WARNING, "Unhandled event %d\n", zt_event_id);
ZT_SIG_EM = (1 << 6), /* E&M */
ZT_SIG_CLEAR = (1 << 7),
ZT_SIG_HDLCRAW = ((1 << 8) | ZT_SIG_CLEAR),
-ZT_SIG_HDLCFCS = ((1 << 9) | ZT_SIG_HDLCRAW)
+ZT_SIG_HDLCFCS = ((1 << 9) | ZT_SIG_HDLCRAW),
+ZT_SIG_CAS = (1 << 15)
} zt_sigtype_t;
+typedef enum {
+ZT_DBIT = 1,
+ZT_CBIT = 2,
+ZT_BBIT = 4,
+ZT_ABIT = 8
+} zt_cas_bit_t;
/* Defines */
#define ZT_GETCONFMUTE _IOR (ZT_CODE, 49, int) /* Get Conference to mute mode */
#define ZT_ECHOTRAIN _IOW (ZT_CODE, 50, int) /* Control Echo Trainer */
+/* Set/Get CAS bits */
+#define ZT_SETTXBITS _IOW (ZT_CODE, 43, int)
+#define ZT_GETRXBITS _IOR (ZT_CODE, 45, int)
+
#endif
memset(cfg, 0, sizeof(*cfg));
cfg->lockto = -1;
-
+ zap_log(ZAP_LOG_DEBUG, "Configuration file is %s.\n", path);
f = fopen(path, "r");
if (!f) {
}
+int zap_config_get_cas_bits(char *strvalue, unsigned char *outbits)
+{
+ char cas_bits[5];
+ unsigned char bit = 0x8;
+ char *double_colon = strchr(strvalue, ':');
+ if (!double_colon) {
+ zap_log(ZAP_LOG_ERROR, "No CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", double_colon);
+ return -1;
+ }
+ double_colon++;
+ *outbits = 0;
+ cas_bits[4] = 0;
+ if (sscanf(double_colon, "%c%c%c%c", &cas_bits[0], &cas_bits[1], &cas_bits[2], &cas_bits[3]) != 4) {
+ zap_log(ZAP_LOG_ERROR, "Invalid CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", double_colon);
+ return -1;
+ }
+ zap_log(ZAP_LOG_DEBUG, "CAS bits specification found: %s\n", cas_bits);
+ int x = 0;
+ for (; cas_bits[x]; x++) {
+ if ('1' == cas_bits[x]) {
+ *outbits |= bit;
+ } else if ('0' != cas_bits[x]) {
+ zap_log(ZAP_LOG_ERROR, "Invalid CAS pattern specified: %s, just 0 or 1 allowed for each bit\n");
+ return -1;
+ }
+ bit >>= 1;
+ }
+ return 0;
+}
+
/* For Emacs:
* Local Variables:
* mode:c
configured += zio->configure_span(span, val, qtype, name, number);
d++;
}
+ } else if (!strcasecmp(var, "cas-channel")) {
+ configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_CAS, name, number);
} else if (!strcasecmp(var, "dtmf_hangup")) {
span->dtmf_hangup = strdup(val);
span->dtmf_hangup_len = strlen(val);
+ } else {
+ zap_log(ZAP_LOG_ERROR, "unknown span variable '%s'\n", var);
}
} else {
zap_log(ZAP_LOG_ERROR, "unknown param [%s] '%s' / '%s'\n", cfg.category, var, val);
zap_mutex_create(&globals.mutex);
modcount = zap_load_modules();
+ zap_log(ZAP_LOG_NOTICE, "Modules configured: %d \n", modcount);
if (load_config() == ZAP_SUCCESS) {
globals.running = 1;