Introduce capi_sendf() for easy capi message creation.

This commit is contained in:
MelwareDE 2007-04-19 20:24:15 +00:00
parent 9d4968ab3a
commit e9d1bbe5c5
3 changed files with 196 additions and 66 deletions

View File

@ -513,8 +513,6 @@ static void capi_channel_task(struct ast_channel *c, int task)
static void capi_echo_canceller(struct ast_channel *c, int function)
{
struct capi_pvt *i = CC_CHANNEL_PVT(c);
_cmsg CMSG;
char buf[10];
int ecAvail = 0;
if ((i->isdnstate & CAPI_ISDN_STATE_DISCONNECT))
@ -552,28 +550,20 @@ static void capi_echo_canceller(struct ast_channel *c, int function)
cc_verbose(3, 0, VERBOSE_PREFIX_2 "%s: Setting up echo canceller (PLCI=%#x, function=%d, options=%d, tail=%d)\n",
i->vname, i->PLCI, function, i->ecOption, i->ecTail);
FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
FACILITY_REQ_PLCI(&CMSG) = i->PLCI;
FACILITY_REQ_FACILITYSELECTOR(&CMSG) = i->ecSelector;
memset(buf, 0, sizeof(buf));
buf[0] = 9; /* msg size */
write_capi_word(&buf[1], function);
if (function == EC_FUNCTION_ENABLE) {
buf[3] = 6; /* echo cancel param struct size */
write_capi_word(&buf[4], i->ecOption); /* bit field - ignore echo canceller disable tone */
write_capi_word(&buf[6], i->ecTail); /* Tail length, ms */
/* buf 8 and 9 are "pre-delay lenght ms" */
i->isdnstate |= CAPI_ISDN_STATE_EC;
} else {
i->isdnstate &= ~CAPI_ISDN_STATE_EC;
}
FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)buf;
if (_capi_put_cmsg(&CMSG) != 0) {
return;
}
capi_sendf(CAPI_FACILITY_REQ, i->PLCI, get_capi_MessageNumber(),
"w(w(www))",
i->ecSelector,
function,
i->ecOption, /* bit field - ignore echo canceller disable tone */
i->ecTail, /* Tail length, ms */
0
);
return;
}
@ -585,8 +575,6 @@ static int capi_detect_dtmf(struct ast_channel *c, int flag)
{
struct capi_pvt *i = CC_CHANNEL_PVT(c);
MESSAGE_EXCHANGE_ERROR error;
_cmsg CMSG;
char buf[9];
if ((i->isdnstate & CAPI_ISDN_STATE_DISCONNECT))
return 0;
@ -609,23 +597,18 @@ static int capi_detect_dtmf(struct ast_channel *c, int flag)
if ((capi_controllers[i->controller]->dtmf != 1) || (i->doDTMF != 0))
return 0;
memset(buf, 0, sizeof(buf));
cc_verbose(3, 0, VERBOSE_PREFIX_2 "%s: Setting up DTMF detector (PLCI=%#x, flag=%d)\n",
i->vname, i->PLCI, flag);
FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
FACILITY_REQ_PLCI(&CMSG) = i->PLCI;
FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_DTMF;
buf[0] = 8; /* msg length */
if (flag == 1) {
write_capi_word(&buf[1], 1); /* start DTMF listen */
} else {
write_capi_word(&buf[1], 2); /* stop DTMF listen */
}
write_capi_word(&buf[3], CAPI_DTMF_DURATION);
write_capi_word(&buf[5], CAPI_DTMF_DURATION);
FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)buf;
if ((error = _capi_put_cmsg(&CMSG)) != 0) {
error = capi_sendf(CAPI_FACILITY_REQ, i->PLCI, get_capi_MessageNumber(),
"w(www()())",
FACILITYSELECTOR_DTMF,
(flag == 1) ? 1:2, /* start/stop DTMF listen */
CAPI_DTMF_DURATION,
CAPI_DTMF_DURATION
);
if (error != 0) {
return error;
}
if (flag == 1) {
@ -761,8 +744,6 @@ static int pbx_capi_send_digit(struct ast_channel *c, char digit)
#endif
{
struct capi_pvt *i = CC_CHANNEL_PVT(c);
_cmsg CMSG;
char buf[10];
char did[2];
int ret = 0;
@ -771,8 +752,6 @@ static int pbx_capi_send_digit(struct ast_channel *c, char digit)
return -1;
}
memset(buf, 0, sizeof(buf));
cc_mutex_lock(&i->lock);
if ((c->_state == AST_STATE_DIALING) &&
@ -800,20 +779,16 @@ static int pbx_capi_send_digit(struct ast_channel *c, char digit)
cc_mutex_unlock(&i->lock);
return -1;
}
ret = capi_sendf(CAPI_FACILITY_REQ, i->NCCI, get_capi_MessageNumber(),
"w(www(b)())",
FACILITYSELECTOR_DTMF,
3, /* send DTMF digit */
CAPI_DTMF_DURATION, /* XXX: duration comes from asterisk in 1.4 */
CAPI_DTMF_DURATION,
digit
);
FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
FACILITY_REQ_PLCI(&CMSG) = i->NCCI;
FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_DTMF;
buf[0] = 8;
write_capi_word(&buf[1], 3); /* send DTMF digit */
/* XXX: duration comes from asterisk in 1.4 */
write_capi_word(&buf[3], CAPI_DTMF_DURATION);
write_capi_word(&buf[5], CAPI_DTMF_DURATION);
buf[7] = 1;
buf[8] = digit;
FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)buf;
if ((ret = _capi_put_cmsg(&CMSG)) == 0) {
if (ret == 0) {
cc_verbose(3, 0, VERBOSE_PREFIX_4 "%s: sent dtmf '%c'\n",
i->vname, digit);
}

View File

@ -7,6 +7,8 @@
*
* Armin Schindler <armin@melware.de>
*
* capi_sendf() by Eicon Networks / Dialogic
*
* This program is free software and may be modified and
* distributed under the terms of the GNU Public License.
*/
@ -73,6 +75,28 @@ _cword get_capi_MessageNumber(void)
return(mn);
}
/*
*
*/
static void log_capi_message(MESSAGE_EXCHANGE_ERROR err, _cmsg *CMSG)
{
unsigned short wCmd;
if (err) {
cc_log(LOG_ERROR, "CAPI error sending %s (NCCI=%#x) (error=%#x %s)\n",
capi_cmsg2str(CMSG), (unsigned int)HEADER_CID(CMSG),
err, capi_info_string((unsigned int)err));
} else {
wCmd = HEADER_CMD(CMSG);
if ((wCmd == CAPI_P_REQ(DATA_B3)) ||
(wCmd == CAPI_P_RESP(DATA_B3))) {
cc_verbose(7, 1, "%s\n", capi_cmsg2str(CMSG));
} else {
cc_verbose(4, 1, "%s\n", capi_cmsg2str(CMSG));
}
}
}
/*
* write a capi message to capi device
*/
@ -84,28 +108,43 @@ MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG)
cc_log(LOG_WARNING, "Unable to lock capi put!\n");
return -1;
}
error = capi20_put_cmsg(CMSG);
error = capi_put_cmsg(CMSG);
if (cc_mutex_unlock(&capi_put_lock)) {
cc_log(LOG_WARNING, "Unable to unlock capi put!\n");
return -1;
}
if (error) {
cc_log(LOG_ERROR, "CAPI error sending %s (NCCI=%#x) (error=%#x %s)\n",
capi_cmsg2str(CMSG), (unsigned int)HEADER_CID(CMSG),
error, capi_info_string((unsigned int)error));
} else {
unsigned short wCmd = HEADER_CMD(CMSG);
if ((wCmd == CAPI_P_REQ(DATA_B3)) ||
(wCmd == CAPI_P_RESP(DATA_B3))) {
cc_verbose(7, 1, "%s\n", capi_cmsg2str(CMSG));
} else {
cc_verbose(4, 1, "%s\n", capi_cmsg2str(CMSG));
}
log_capi_message(error, CMSG);
return error;
}
/*
* write a capi message to capi device
*/
MESSAGE_EXCHANGE_ERROR _capi_put_msg(unsigned char *msg)
{
MESSAGE_EXCHANGE_ERROR error;
_cmsg CMSG;
if (cc_mutex_lock(&capi_put_lock)) {
cc_log(LOG_WARNING, "Unable to lock capi put!\n");
return -1;
}
capi_message2cmsg(&CMSG, msg);
error = capi20_put_message(CMSG.ApplId, msg);
if (cc_mutex_unlock(&capi_put_lock)) {
cc_log(LOG_WARNING, "Unable to unlock capi put!\n");
return -1;
}
log_capi_message(error, &CMSG);
return error;
}
@ -150,6 +189,109 @@ MESSAGE_EXCHANGE_ERROR capidev_check_wait_get_cmsg(_cmsg *CMSG)
return Info;
}
/*
* Eicon's capi_sendf() function to create capi messages easily
* and send this message.
* Copyright by Eicon Networks / Dialogic
*/
MESSAGE_EXCHANGE_ERROR capi_sendf(
_cword command, _cdword Id, _cword Number, char * format, ...)
{
MESSAGE_EXCHANGE_ERROR ret;
int i, j;
unsigned int d;
unsigned char *p, *p_length;
unsigned char *string;
va_list ap;
capi_prestruct_t *s;
unsigned char msg[2048];
write_capi_word(&msg[2], capi_ApplID);
write_capi_word(&msg[4], command);
write_capi_word(&msg[6], Number);
write_capi_dword(&msg[8], Id);
p = &msg[12];
p_length = 0;
va_start(ap, format);
for (i = 0; format[i]; i++) {
if (((p - (&msg[0])) + 12) >= sizeof(msg)) {
cc_log(LOG_ERROR, "capi_sendf: message too big (%d)\n",
(p - (&msg[0])));
return 0x1004;
}
switch(format[i]) {
case 'b': /* byte */
d = (unsigned char)va_arg(ap, unsigned int);
*(p++) = (unsigned char) d;
break;
case 'w': /* word (2 bytes) */
d = (unsigned short)va_arg(ap, unsigned int);
*(p++) = (unsigned char) d;
*(p++) = (unsigned char)(d >> 8);
break;
case 'd': /* double word (4 bytes) */
d = va_arg(ap, unsigned int);
*(p++) = (unsigned char) d;
*(p++) = (unsigned char)(d >> 8);
*(p++) = (unsigned char)(d >> 16);
*(p++) = (unsigned char)(d >> 24);
break;
case 's': /* struct, length is the first byte */
string = va_arg(ap, unsigned char *);
for (j = 0; j <= string[0]; j++)
*(p++) = string[j];
break;
case 'a': /* ascii string, NULL terminated string */
string = va_arg(ap, unsigned char *);
for (j = 0; string[j] != '\0'; j++)
*(++p) = string[j];
*((p++)-j) = (unsigned char) j;
break;
case 'c': /* predefined capi_prestruct_t */
s = va_arg(ap, capi_prestruct_t *);
if (s->wLen < 0xff) {
*(p++) = (unsigned char)(s->wLen);
} else {
*(p++) = 0xff;
*(p++) = (unsigned char)(s->wLen);
*(p++) = (unsigned char)(s->wLen >> 8);
}
for (j = 0; j < s->wLen; j++)
*(p++) = s->info[j];
break;
case '(': /* begin of a structure */
*p = (p_length) ? p - p_length : 0;
p_length = p++;
break;
case ')': /* end of structure */
if (p_length) {
j = *p_length;
*p_length = (unsigned char)((p - p_length) - 1);
p_length = (j != 0) ? p_length - j : 0;
} else {
cc_log(LOG_ERROR, "capi_sendf: inconsistent format \"%s\"\n",
format);
}
break;
default:
cc_log(LOG_ERROR, "capi_sendf: unknown format \"%s\"\n",
format);
}
}
va_end(ap);
if (p_length) {
cc_log(LOG_ERROR, "capi_sendf: inconsistent format \"%s\"\n", format);
}
write_capi_word(&msg[0], (unsigned short)(p - (&msg[0])));
ret = _capi_put_msg(&msg[0]);
return (ret);
}
/*
* decode capi 2.0 info word
*/

View File

@ -35,4 +35,17 @@ extern struct ast_channel *cc_get_peer_link_id(const char *p);
#define capi_number(data, strip) \
capi_number_func(data, strip, alloca(AST_MAX_EXTENSION))
typedef struct capi_prestruct_s {
unsigned short wLen;
unsigned char *info;
} capi_prestruct_t;
/*
* Eicon's capi_sendf() function to create capi messages easily
* and send this message.
* Copyright by Eicon Networks / Dialogic
*/
extern MESSAGE_EXCHANGE_ERROR capi_sendf(
_cword command, _cdword Id, _cword Number, char * format, ...);
#endif