Newer
Older
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <libubus.h>
#include <libpicoevent.h> // for err_exit()
#include "line.h"
#include "line-dect.h"
#include "main.h"
#include "ubus.h"
enum {
STATE_OFF = 0,
STATE_ON,
STATE_LAST,
};
enum {
ACTION_CREATE,
ACTION_DESTROY,
ACTION_LAST,
};
struct epsig {
const char *name;
EPSIG epsig;
};
static const struct epsig epsig_map[] = { // For generating a signal to the phone
{ .name = "dial", .epsig = EPSIG_DIAL },
{ .name = "ringback", .epsig = EPSIG_RINGBACK },
{ .name = "stutter", .epsig = EPSIG_STUTTER },
{ .name = "unobtainable", .epsig = EPSIG_RINGBACK_CUST1 }, // Maps onto ToneUserDefined1 in endpoint_api.h
{ .name = "callwt", .epsig = EPSIG_CALLWT },
{ .name = "busy", .epsig = EPSIG_BUSY },
{ .name = "ringing", .epsig = EPSIG_RINGING },
{ .name = "callid_ringing", .epsig = EPSIG_CALLID_RINGING },
{ .name = "callid", .epsig = EPSIG_CALLID },
{ .name = "congestion", .epsig = EPSIG_NETBUSY },
{ .name = "dial2", .epsig = EPSIG_DIAL2 },
{ .name = "dtmf0", .epsig = EPSIG_DTMF0 },
{ .name = "dtmf1", .epsig = EPSIG_DTMF1 },
{ .name = "dtmf2", .epsig = EPSIG_DTMF2 },
{ .name = "dtmf3", .epsig = EPSIG_DTMF3 },
{ .name = "dtmf4", .epsig = EPSIG_DTMF4 },
{ .name = "dtmf5", .epsig = EPSIG_DTMF5 },
{ .name = "dtmf6", .epsig = EPSIG_DTMF6 },
{ .name = "dtmf7", .epsig = EPSIG_DTMF7 },
{ .name = "dtmf8", .epsig = EPSIG_DTMF8 },
{ .name = "dtmf9", .epsig = EPSIG_DTMF9 },
{ .name = "dtmf#", .epsig = EPSIG_DTMFH },
{ .name = "dtmf*", .epsig = EPSIG_DTMFS },
{ .name = "dtmfA", .epsig = EPSIG_DTMFA },
{ .name = "dtmfB", .epsig = EPSIG_DTMFB },
{ .name = "dtmfC", .epsig = EPSIG_DTMFC },
{ .name = "dtmfD", .epsig = EPSIG_DTMFD },
{ .name = "keypad", .epsig = EPSIG_INGRESS_DTMF },
{ .name = "", .epsig = EPSIG_LAST },
};
static int send_dect_event_to_asterisk(int line, struct dect_event_t dectEvnt) {
struct line_event_t *msg;
msg = malloc(sizeof(struct line_event_t));
msg->name = dectEvnt.name;
msg->data = 0;
msg->line = line;
ubus_call_asterisk(msg);
ubus_broadcast_event(msg);
return 0;
}
//-------------------------------------------------------------
// If a line has been disabled in run time we simulate
// it as always being busy by going off-hook forever. This
// is used by DECT when the HW is unpopulated.
static int perhaps_simulate_busy(int line, struct voice_ubus_req_t *ubus_req) {
const struct voice_event_t *ev;
struct line_event_t *msg;
if(!lines[line].simulated_busy)
return 0;
// Inform the PBX only once per UBUS session or we get a loop.
assert(ubus_req && ubus_req->reqIn);
if(lines[line].simulated_busy_peer_id == ubus_req->reqIn->peer) {
lines[line].simulated_busy_peer_id = ubus_req->reqIn->peer;
for(ev = event_map; ev->event != VOICE_EVT_OFFHOOK; ev++);
msg = malloc(sizeof(struct line_event_t));
msg->name = ev->name;
msg->data = 0;
msg->line = line;
send_event_main(msg, EVENT_MAIN_LINE);
return 1;
}
//----------------------------------------------------------------------------------
// Asterisk wants to make a FXS phone or DECT handset ring probably with a caller ID
static EPSTATUS line_signal_ring(int line, int pcm, EPSIG epsig, const char *data, struct voice_ubus_req_t *ubus_req) {
const unsigned int CLID_MIN_LEN = 14; // Minimum string length to be valid.
const unsigned int CLID_TIME_DELIM = 8; // String index where time record ends.
const unsigned int CLID_NUMB_REC = CLID_TIME_DELIM + 2; // String index where number starts.

Yalu Zhang
committed
struct line_req_t *line_req = NULL;
int start_ring = data && strcmp(data, "0") != 0;

Yalu Zhang
committed
ENDPT_DBG("%s: line %d pcm: %d data: %s\n", __func__, line, pcm, data);
ENDPT_DBG("%s: pcm_state[%d]: %d, pcm_state[%d]: %d\n", __func__, PCM_0, lines[line].pcm_state[PCM_0],
PCM_1, lines[line].pcm_state[PCM_1]);
// Relay the request to dectmngr if the line is DECT
if(lines[line].type == VOICE_LINE_DECT) {

Yalu Zhang
committed
line_req = calloc(1, sizeof(struct line_req_t));
if(!line_req) {
ENDPT_DBG("%s: out of memory\n", __func__);
return EPSTATUS_ERROR;
}
line_req->line = line;
line_req->connection_id = -1;
line_req->pcm_id = pcm;
ENDPT_DBG("%s: line %d set pcm to %d\n", __func__, line, line_req->pcm_id);
memcpy(&line_req->ubus, ubus_req, sizeof(struct voice_ubus_req_t));
// Parse the called ID string generated by Asterisk
if(data && strlen(data) >= CLID_MIN_LEN && strlen(data) <= MAX_CALLER_ID_LEN &&
data[CLID_TIME_DELIM] == ',' && data[CLID_NUMB_REC + 1] != ',') {
char callIdTmp[strlen(data) + 1];
strcpy(callIdTmp, data); // Copy into a temp buffer.
*strchrnul(callIdTmp + CLID_NUMB_REC, ',') = 0; // Find comma after digits and null it.

Yalu Zhang
committed
strcpy(line_req->caller_id, callIdTmp + CLID_NUMB_REC); // Extract the number.
}
}
// What type of ring signal?
switch(epsig) {
case EPSIG_CALLID:

Yalu Zhang
committed
if(line_req) {
line_req->action = start_ring ? ACTION_SIG_RING : ACTION_CONN_CLOSE;
} else {
return vrgEndptSignal(&lines[line].epHandle, -1, epsig, (unsigned int)data, -1, -1, -1);
}
break;
case EPSIG_RINGING:
case EPSIG_CALLID_RINGING:

Yalu Zhang
committed
if(line_req) {
if(start_ring) {
if(epsig == EPSIG_CALLID_RINGING) {
// Dect ignore this enable signal

Yalu Zhang
committed
free(line_req);
return EPSTATUS_SUCCESS;
}

Yalu Zhang
committed
line_req->action = ACTION_SIG_RING;
} else {
line_req->action = ACTION_CONN_CLOSE;

Yalu Zhang
committed
line_req->caller_id[0] = 0; // Discard enable/disable char or it will become the caller ID
} else {
return vrgEndptSignal(&lines[line].epHandle, -1, epsig, start_ring, -1, -1, -1);
}
break;
default:

Yalu Zhang
committed
free(line_req);
return EPSTATUS_ERROR;
}

Yalu Zhang
committed
// If getting here the request is aimed for DECT
assert(lines[line].type == VOICE_LINE_DECT);

Yalu Zhang
committed
assert(line_req);
if(ubus_queue_req_to_dectmngr(line_req) || ubus_process_queued_reqs_to_dectmngr())
return EPSTATUS_ERROR;

Yalu Zhang
committed
ubus_defer_request(line_req->ubus.ctx, line_req->ubus.reqIn, &line_req->ubus.reqOut);
line_req->ubus.reqIn = NULL;
return EPSTATUS_SUCCESS;
}
//-------------------------------------------------------------
// Generate a signal to the phone, such as DTMF tones or ringing
int line_signal(int line, const char *signame, const char *data, struct voice_ubus_req_t *ubus_req) {
const struct epsig *sig;
EPCMD_PARMS sigArg;
EPSTATUS status;
int i;

Yalu Zhang
committed
ENDPT_DBG("%s: line: %d, signame: %s, data: %s\n", __func__, line, signame, data);
for(sig = epsig_map; sig->epsig != EPSIG_LAST && strcmp(signame, sig->name) != 0; sig++)
continue;
if(sig->epsig == EPSIG_LAST) {
ENDPT_DBG("%s: signal %s is not supported\n", __func__, signame);
return -1;
}
// Is line disabled?
if(perhaps_simulate_busy(line, ubus_req))
switch(sig->epsig) {
case EPSIG_CALLID_RINGING:
case EPSIG_CALLID:
case EPSIG_RINGING:
if(atoi(data) == 0) {
status = line_signal_ring(line, lines[line].pcm_state[PCM_0] ==
LINE_PCM_STATE_RINGING ? PCM_0 : PCM_1, sig->epsig, data, ubus_req);
lines[line].signaled_call_waiting = 0;
status = line_signal_ring(line, lines[line].pcm_state[PCM_0] ==
LINE_PCM_STATE_NOT_USED ? PCM_0 : PCM_1, sig->epsig, data, ubus_req);

Yalu Zhang
committed
case EPSIG_INGRESS_DTMF: // Simulate phone keypad button presses
status = (data ? EPSTATUS_SUCCESS : EPSTATUS_SIGNAL_UNKNOWN);
/* Split user arg ASCII phone number string into (max 100)
* individual libvoip DTMF generation events. */
for(i = 0; i < MAX_KEYPAD_DIGITS && data[i] && status == EPSTATUS_SUCCESS; i++) {
if(!isascii(data[i])) {
sigArg.arg[0] = HAPI_PTE_DTMFDDGTERROR;

Yalu Zhang
committed
} else if(isdigit(data[i])) {
sigArg.arg[0] = (int)(data[i] - '0') + HAPI_PTE_DTMFDDGT0;
if(sigArg.arg[0] > HAPI_PTE_DTMFDDGT9) {
sigArg.arg[0] = HAPI_PTE_DTMFDDGTERROR;
}

Yalu Zhang
committed
} else if(isxdigit(data[i])) {
sigArg.arg[0] = tolower((int) data[i]) - (int) 'a' + HAPI_PTE_DTMFDDGTA;
if(sigArg.arg[0] < HAPI_PTE_DTMFDDGTA || sigArg.arg[0] > HAPI_PTE_DTMFDDGTD) {
sigArg.arg[0] = HAPI_PTE_DTMFDDGTERROR;
}

Yalu Zhang
committed
} else if(data[i] == '*') {

Yalu Zhang
committed
} else if(data[i] == '#') {

Yalu Zhang
committed
} else if(data[i] == 'R') {
sigArg.arg[0] = brcm_simulate_hook(line, VOICE_EVT_FLASH) ? HAPI_PTE_DTMFDDGTERROR : 0;
} else {
sigArg.arg[0] = HAPI_PTE_DTMFDDGTERROR;
}
if(sigArg.arg[0] == HAPI_PTE_DTMFDDGTERROR) {

Yalu Zhang
committed
ENDPT_DBG("Warning, invalid keypad char %d %c\n", (int)data[i], data[i]);

Yalu Zhang
committed
} else if(sigArg.arg[0] || data[i] == '0') { // Accept digit 0 also when it calculates to integer 0.
status = vrgEndptConsoleCmd(&lines[line].epHandle, EPCMD_INDTMF_GENERATE, &sigArg);
}
}
break;
case EPSIG_CALLWT:
if (lines[line].type == VOICE_LINE_DECT) {
ENDPT_DBG("lines[%d].signaled_call_waiting: %d\n", line, lines[line].signaled_call_waiting);
if((data[0] == '1') && (lines[line].signaled_call_waiting == 0)) {
status = line_signal_ring(line, lines[line].pcm_state[PCM_1] ==
LINE_PCM_STATE_NOT_USED ? PCM_1 : PCM_0, EPSIG_RINGING, data, ubus_req);
lines[line].signaled_call_waiting = 1;
} else if((data[0] == '0')) {
// stop call waiting
status = line_signal_ring(line, lines[line].pcm_state[PCM_1] ==
LINE_PCM_STATE_RINGING ? PCM_1 : PCM_0, EPSIG_RINGING, data, ubus_req);
lines[line].signaled_call_waiting = 0;

Yalu Zhang
committed
status = vrgEndptSignal(&lines[line].epHandle, -1, sig->epsig, atoi(data), -1, -1, -1);

Yalu Zhang
committed
case EPSIG_RINGBACK_CUST1:
case EPSIG_BUSY:
if (lines[line].type == VOICE_LINE_DECT) {
send_dect_event_to_asterisk(line, dect_event_map[DECT_EVT_RELEASE]);

Yalu Zhang
committed
status = vrgEndptSignal(&lines[line].epHandle, -1, sig->epsig, atoi(data), -1, -1, -1);

Yalu Zhang
committed
if (lines[line].type == VOICE_LINE_DECT) {
send_dect_event_to_asterisk(line, dect_event_map[DECT_EVT_RELEASE]);

Yalu Zhang
committed

Yalu Zhang
committed
status = vrgEndptSignal(&lines[line].epHandle, -1, sig->epsig, atoi(data), -1, -1, -1);
break;
}
if (status == EPSTATUS_SUCCESS) {

Yalu Zhang
committed
ENDPT_DBG("%s: signal %s(%s) was set for line %d\n", __func__, sig->name, data, line);
} else {
ENDPT_DBG("%s: error setting signal %s(%s)\n", __func__, sig->name, data);
return -1;
}
return 0;
}
//-------------------------------------------------------------
// Reception of a create connection request from Asterisk. If
// line type is Dect we need to relay the requets to the dectmngr.
int line_new_connection_by_asterisk(int line, int connection, struct voice_ubus_req_t *ubus_req) {

Yalu Zhang
committed
struct line_req_t *line_req;
if(line < 0 || line >= terminal_info.num_terminals) return -1;
epIntern = GetEndptState(line);
if(!epIntern) return -1;
ENDPT_DBG("%s() line: %d, connection: %d\n", __func__, line, connection);
ENDPT_DBG("%s lines[%d].pcm_state[%d]: %d, lines[%d].pcm_state[%d]: %d\n", __func__, line, PCM_0, lines[line].pcm_state[PCM_0],
line, PCM_1, lines[line].pcm_state[PCM_1]);
if (lines[line].pcm_state[PCM_0] == LINE_PCM_STATE_RINGING) {
lines[line].pcm_state[PCM_0] = connection;
ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_0] to %d\n", __func__, line, lines[line].pcm_state[PCM_0]);
}
else if (lines[line].pcm_state[PCM_1] == LINE_PCM_STATE_RINGING) {
lines[line].pcm_state[PCM_1] = connection;
ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_1] to %d\n", __func__, line, lines[line].pcm_state[PCM_1]);
}
res = 0;
if(lines[line].type == VOICE_LINE_DECT) {
if(voice_line_is_offhook(line) || epIntern->cnxCnt > 0) {
/* dectmngr alreay has audio streaming, now
* libvoip and Asterisk should do the same. */
res = voice_connection_create(line, line);
}
else {
/* Relay request to dectmngr by putting the request
* in a queue, where it will wait until we get a
* chanse to relay it to dectmngr. */

Yalu Zhang
committed
line_req = calloc(1, sizeof(struct line_req_t));
if(!line_req) return -1;
line_req->line = line;
line_req->connection_id = line;
line_req->pcm_id = lines[line].pcm_state[PCM_0] == connection ? PCM_0 : PCM_1;
line_req->action = ACTION_CONN_CREATE;
memcpy(&line_req->ubus, ubus_req, sizeof(struct voice_ubus_req_t));
if(ubus_queue_req_to_dectmngr(line_req) || ubus_process_queued_reqs_to_dectmngr()) return -1;
ubus_defer_request(line_req->ubus.ctx, line_req->ubus.reqIn,
&line_req->ubus.reqOut);
line_req->ubus.reqIn = NULL; // Deny further use of input request
}
}
else {
res = voice_connection_create(line, line);
}
return res;
}
//-------------------------------------------------------------
// Reception of a close connection request from Asterisk. If
// line type is Dect we need to relay the requets to the dectmngr.
int line_close_connection_by_asterisk(int line, int connection, struct voice_ubus_req_t *ubus_req) {

Yalu Zhang
committed
struct line_req_t *line_req;
ENDPT_DBG("%s() line: %d, connection: %d\n", __func__, line, connection);
ENDPT_DBG("%s lines[%d].pcm_state[%d]: %d, lines[%d].pcm_state[%d]: %d\n", __func__, line, PCM_0, lines[line].pcm_state[PCM_0],
line, PCM_1, lines[line].pcm_state[PCM_1]);
if (lines[line].pcm_state[PCM_0] == LINE_PCM_STATE_NOT_USED && lines[line].pcm_state[PCM_1] == LINE_PCM_STATE_NOT_USED) {
return voice_connection_close(line, line);
}
if(line < 0 || line >= terminal_info.num_terminals) return -1;
switch(lines[line].type) {
case VOICE_LINE_DECT:
/* Put the request in a queue, where it will wait
* until we get a chanse to relay it to dectmngr. */

Yalu Zhang
committed
line_req = calloc(1, sizeof(struct line_req_t));
if(!line_req) return -1;
line_req->line = line;
line_req->connection_id = line;
if (lines[line].pcm_state[PCM_0] >= LINE_PCM_STATE_CONNECTED && lines[line].pcm_state[PCM_1] == LINE_PCM_STATE_NOT_USED) {

Yalu Zhang
committed
line_req->pcm_id = PCM_0;
lines[line].pcm_state[PCM_0] = LINE_PCM_STATE_NOT_USED;
ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_0] to %d\n", __func__, line, lines[line].pcm_state[PCM_0]);
} else if (lines[line].pcm_state[PCM_1] >= LINE_PCM_STATE_CONNECTED && lines[line].pcm_state[PCM_0] == LINE_PCM_STATE_NOT_USED) {

Yalu Zhang
committed
line_req->pcm_id = PCM_1;
lines[line].pcm_state[PCM_1] = LINE_PCM_STATE_NOT_USED;
ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_1] to %d\n", __func__, line, lines[line].pcm_state[PCM_1]);
}

Yalu Zhang
committed
line_req->action = ACTION_CONN_CLOSE;
memcpy(&line_req->ubus, ubus_req, sizeof(struct voice_ubus_req_t));
if(ubus_queue_req_to_dectmngr(line_req) || ubus_process_queued_reqs_to_dectmngr())

Yalu Zhang
committed
ubus_defer_request(line_req->ubus.ctx, line_req->ubus.reqIn, &line_req->ubus.reqOut);
line_req->ubus.reqIn = NULL; // Deny further use of input request
break;
default:
if (lines[line].pcm_state[PCM_0] >= LINE_PCM_STATE_CONNECTED) {
lines[line].pcm_state[PCM_0] = LINE_PCM_STATE_NOT_USED;
ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_0] to %d\n", line, lines[line].pcm_state[PCM_0]);
} else if (lines[line].pcm_state[PCM_1] >= LINE_PCM_STATE_CONNECTED) {
lines[line].pcm_state[PCM_1] = LINE_PCM_STATE_NOT_USED;
ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_1] to %d\n", line, lines[line].pcm_state[PCM_1]);
}
return voice_connection_close(line, line);
}
return 0;
}
int line_release_connection_by_asterisk(int line, int connection, struct voice_ubus_req_t *ubus_req) {

Yalu Zhang
committed
struct line_req_t *line_req;
if(line < 0 || line >= terminal_info.num_terminals) return -1;
ENDPT_DBG("%s() line: %d connection: %d\n", __func__, line, connection);
ENDPT_DBG("%s lines[%d].pcm_state[%d]: %d, lines[%d].pcm_state[%d]: %d\n", __func__, line, PCM_0, lines[line].pcm_state[PCM_0],
line, PCM_1, lines[line].pcm_state[PCM_1]);
// during start of call conference asterisk removes 1 of connection, we skip
// it because voicemngr<->dectmngr needs to keep it active
if (lines[line].conference_started == 1) {
lines[line].conference_started = 0;
return 0;
}
if (lines[line].pcm_state[PCM_0] < LINE_PCM_STATE_CONNECTED && lines[line].pcm_state[PCM_1] < LINE_PCM_STATE_CONNECTED) {
return 0;
}
if (lines[line].pcm_state[PCM_0] != connection && lines[line].pcm_state[PCM_1] != connection) {
switch(lines[line].type) {
case VOICE_LINE_DECT:
/* Put the request in a queue, where it will wait
* until we get a chanse to relay it to dectmngr. */

Yalu Zhang
committed
line_req = calloc(1, sizeof(struct line_req_t));
if(!line_req) return -1;
line_req->line = line;
line_req->connection_id = line;
if (lines[line].pcm_state[PCM_0] == connection) {

Yalu Zhang
committed
line_req->pcm_id = PCM_0;
lines[line].pcm_state[PCM_0] = LINE_PCM_STATE_NOT_USED;
ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_0] to %d\n", __func__, line, lines[line].pcm_state[PCM_0]);
} else if (lines[line].pcm_state[PCM_1] == connection) {

Yalu Zhang
committed
line_req->pcm_id = PCM_1;
lines[line].pcm_state[PCM_1] = LINE_PCM_STATE_NOT_USED;
ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_1] to %d\n", __func__, line, lines[line].pcm_state[PCM_1]);
}

Yalu Zhang
committed
line_req->action = ACTION_CONN_CLOSE;
memcpy(&line_req->ubus, ubus_req, sizeof(struct voice_ubus_req_t));
if(ubus_queue_req_to_dectmngr(line_req) || ubus_process_queued_reqs_to_dectmngr())

Yalu Zhang
committed
ubus_defer_request(line_req->ubus.ctx, line_req->ubus.reqIn, &line_req->ubus.reqOut);
line_req->ubus.reqIn = NULL; // Deny further use of input request
if (lines[line].pcm_state[PCM_0] == connection) {
lines[line].pcm_state[PCM_0] = LINE_PCM_STATE_NOT_USED;
ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_0] to %d\n", __func__, line, lines[line].pcm_state[PCM_0]);
} else if (lines[line].pcm_state[PCM_1] == connection) {
lines[line].pcm_state[PCM_1] = LINE_PCM_STATE_NOT_USED;
ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_1] to %d\n", __func__, line, lines[line].pcm_state[PCM_1]);
}
return voice_connection_close(line, line);
}
return 0;
}
int line_update_connection_by_pbx(int line, int pcm_state) {
ENDPT_DBG("%s Received update connection for line: %d with pcm_state: %d\n",
__func__, line, pcm_state);
ENDPT_DBG("%s lines[%d].pcm_state[%d]: %d, lines[%d].pcm_state[%d]: %d\n", __func__, line, PCM_0, lines[line].pcm_state[PCM_0],
line, PCM_1, lines[line].pcm_state[PCM_1]);
if(lines[line].type != VOICE_LINE_DECT)
return 0;
if (lines[line].pcm_state[PCM_0] == LINE_PCM_STATE_RINGING) {
lines[line].pcm_state[PCM_0] = pcm_state;
ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_0] to %d\n", __func__, line, lines[line].pcm_state[PCM_0]);
} else if(lines[line].pcm_state[PCM_1] == LINE_PCM_STATE_RINGING) {
lines[line].pcm_state[PCM_1] = pcm_state;
ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_1] to %d\n", __func__, line, lines[line].pcm_state[PCM_1]);
}
return 0;
}
//-------------------------------------------------------------
// Reception of a create connection request from dectmngr.
// Generate a off-hook event and queue the request
// until Asterisk acknowledge the offh-ook event.
int line_new_connection_by_dect(int line, const char *cid, int pcm, struct voice_ubus_req_t *ubus_req) {

Yalu Zhang
committed
struct line_req_t *line_req;
if(line < 0 || line >= terminal_info.num_terminals)
return -1;
if(lines[line].type != VOICE_LINE_DECT)
return -1;
ENDPT_DBG("%s() for line %d pcm %d\n", __func__, line, pcm);
ENDPT_DBG("%s lines[%d].pcm_state[%d]: %d, lines[%d].pcm_state[%d]: %d\n", __func__, line, PCM_0,
lines[line].pcm_state[PCM_0], line, PCM_1, lines[line].pcm_state[PCM_1]);
if(pcm <= PCM_1) {
lines[line].pcm_state[pcm] = LINE_PCM_STATE_RINGING;
lines[line].signaled_call_waiting = 0;
ENDPT_DBG("%s changing value of lines[%d].pcm_state[%d] to %d\n", __func__, line, pcm, lines[line].pcm_state[pcm]);
if(!voice_line_is_offhook(line) && brcm_simulate_hook(line, VOICE_EVT_OFFHOOK))
if (brcm_simulate_hook(line, VOICE_EVT_FLASH))
return -1;
break;
case CALL_DIGIT_PRESSED:
break;
case CALL_TOGGLE:
if (send_dect_event_to_asterisk(line, dect_event_map[DECT_EVT_SWITCH]))
if (send_dect_event_to_asterisk(line, dect_event_map[DECT_EVT_JOIN]))
if (simulate_digits_pressing(line, cid) == -1)
/* Store the ubus request in a queue. It will be picked up
* later, via the Asterisk ubus answer handler. */

Yalu Zhang
committed
line_req = calloc(1, sizeof(struct line_req_t));
if(!line_req) return -1;
line_req->line = line;
line_req->connection_id = -1;
line_req->action = ACTION_CONN_CREATE;
memcpy(&line_req->ubus, ubus_req, sizeof(struct voice_ubus_req_t));
if(ubus_queue_req_to_asterisk(line_req)) {
free(line_req);

Yalu Zhang
committed
ubus_defer_request(line_req->ubus.ctx, line_req->ubus.reqIn, &line_req->ubus.reqOut);
line_req->ubus.reqIn = NULL; // Deny further use of input request
return 0;
}
//-------------------------------------------------------------
// Reception of a close connection request from dectmngr.
// Generate a libvoip onhook event and queue the request
// until Asterisk acknowledge the onhook event.
int line_close_connection_by_dect(int line, int pcm, struct voice_ubus_req_t *ubus_req) {

Yalu Zhang
committed
struct line_req_t *line_req;
if(line < 0 || line >= terminal_info.num_terminals) {
ENDPT_DBG("%s: wrong parameter\n", __func__);
return -1;
}
if(lines[line].type != VOICE_LINE_DECT) {
ENDPT_DBG("%s: lines[%d].type != VOICE_LINE_DECT\n", __func__, line);
ENDPT_DBG("%s() for line %d, pcm: %d\n", __func__, line, pcm);
ENDPT_DBG("%s lines[%d].pcm_state[%d]: %d, lines[%d].pcm_state[%d]: %d\n", __func__, line, PCM_0, lines[line].pcm_state[PCM_0],
line, PCM_1, lines[line].pcm_state[PCM_1]);
epIntern = GetEndptState(line);
if(!epIntern) {
ENDPT_DBG("%s: GetEndptState() failed\n", __func__);
return -1;
}
struct line_event_t *msg;
ENDPT_DBG("%s: There is no available DECT handsets for the call. "
"Send DECT_UNAVAILABLE event to Asterisk\n", __func__);
msg = malloc(sizeof(struct line_event_t));
if (msg) {
msg->name = "DECT_UNAVAILABLE";
msg->data = 0;
msg->line = line;
send_event_main(msg, EVENT_MAIN_LINE);
}
return send_reply_dectmngr(ubus_req, line + 1, // +1 Dectmngr lines starting from 1
pcm, UBUS_STATUS_OK);
if (lines[line].pcm_state[pcm] == LINE_PCM_STATE_RINGING) {
struct line_event_t *msg;
ENDPT_DBG("%s: DECT handsets may have not answered the call yet. "
"Send CALL_REJECT event to Asterisk\n", __func__);
msg = malloc(sizeof(struct line_event_t));
if (msg) {
msg->name = "CALL_REJECT";
msg->data = 0;
msg->line = line;
send_event_main(msg, EVENT_MAIN_LINE);
}
return send_reply_dectmngr(ubus_req, line + 1, // +1 Dectmngr lines starting from 1
pcm, UBUS_STATUS_OK);
}
if(lines[line].pcm_state[PCM_0] <= LINE_PCM_STATE_RINGING || lines[line].pcm_state[PCM_1] <= LINE_PCM_STATE_RINGING) {
brcm_simulate_hook(line, VOICE_EVT_ONHOOK);
lines[line].pcm_state[pcm] = LINE_PCM_STATE_NOT_USED;
ENDPT_DBG("%s changing value of lines[%d].pcm_state[%d] to %d\n", __func__, line, pcm, lines[line].pcm_state[pcm]);
if(send_dect_event_to_asterisk(line, dect_event_map[DECT_EVT_RELEASE]))
return -1;
/* Store the request in a queue. It will be picked up
* later, via the Asterisk ubus answer handler. */

Yalu Zhang
committed
line_req = calloc(1, sizeof(struct line_req_t));
if(!line_req) return -1;
line_req->line = line;
line_req->connection_id = -1;
line_req->action = ACTION_CONN_CLOSE;
memcpy(&line_req->ubus, ubus_req, sizeof(struct voice_ubus_req_t));
if(ubus_queue_req_to_asterisk(line_req)) {
free(line_req);

Yalu Zhang
committed
ubus_defer_request(line_req->ubus.ctx, line_req->ubus.reqIn, &line_req->ubus.reqOut);
line_req->ubus.reqIn = NULL;