Skip to content

Commit cf26500

Browse files
committed
res_smdr_whozz: Add function to provide line state.
Add WHOZZ_LINE_STATE function, which returns whether a line is currently off-hook, on-hook, or ringing. This is useful since the DAHDI drivers do not provide a mechanism to distinguish between off-hook and on-hook without disturbing the line (none of the analog card registers provides this information). Thus, the function can return information from the WHOZZ Calling? hardware to provide this information within Asterisk.
1 parent e7d5bab commit cf26500

File tree

1 file changed

+205
-5
lines changed

1 file changed

+205
-5
lines changed

res/res_smdr_whozz.c

Lines changed: 205 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,26 @@
9292
</configObject>
9393
</configFile>
9494
</configInfo>
95+
<function name="WHOZZ_LINE_STATE" language="en_US">
96+
<synopsis>
97+
Returns the line state of a WHOZZ Calling? line
98+
</synopsis>
99+
<syntax>
100+
<parameter name="line" required="true">
101+
<para>Line number</para>
102+
</parameter>
103+
</syntax>
104+
<description>
105+
<para>Returns the line state of the specified line.</para>
106+
<para>The possible values are:</para>
107+
<enumlist>
108+
<enum name="UNKNOWN"/>
109+
<enum name="ONHOOK"/>
110+
<enum name="OFFHOOK"/>
111+
<enum name="RINGING"/>
112+
</enumlist>
113+
</description>
114+
</function>
95115
***/
96116

97117
#define MODULE_NAME "res_smdr_whozz"
@@ -162,7 +182,7 @@ static int unloading = 0;
162182
ast_debug(3, "Received %ld bytes from serial port: %s\n", bufres, buf); \
163183
}
164184

165-
static const char *state_str(enum line_state state)
185+
static const char *state_str_cli(enum line_state state)
166186
{
167187
switch (state) {
168188
case UNKNOWN:
@@ -177,6 +197,21 @@ static const char *state_str(enum line_state state)
177197
__builtin_unreachable();
178198
}
179199

200+
static const char *state_str_func(enum line_state state)
201+
{
202+
switch (state) {
203+
case UNKNOWN:
204+
return "UNKNOWN";
205+
case ONHOOK:
206+
return "ONHOOK";
207+
case OFFHOOK:
208+
return "OFFHOOK";
209+
case RINGING:
210+
return "RINGING";
211+
}
212+
__builtin_unreachable();
213+
}
214+
180215
static int serial_getline(struct pollfd *pfd, int pollfirst, char *restrict buf, size_t len)
181216
{
182217
size_t total = 0;
@@ -445,8 +480,92 @@ static int handle_hook(struct whozz_line *w, int outbound, int end, int duration
445480
return -1; \
446481
}
447482

483+
static void update_state(struct whozz_line *w, enum line_state newstate, enum line_state oldstate)
484+
{
485+
w->state = newstate;
486+
manager_event(EVENT_FLAG_CALL, "WHOZZLineStateChange",
487+
"LineNumber: %d\r\n"
488+
"CurrentState: %s\r\n"
489+
"OldState: %s\r\n",
490+
w->lineno,
491+
state_str_func(w->state),
492+
state_str_func(oldstate));
493+
}
494+
448495
static int __process_serial_read(struct whozz_line *w, int lineno, const char *action, char *buf, size_t len)
449496
{
497+
enum line_state oldstate = w->state;
498+
/*** DOCUMENTATION
499+
<managerEvent language="en_US" name="WHOZZLineStateChange">
500+
<managerEventInstance class="EVENT_FLAG_CALL">
501+
<synopsis>Raised when the state of a phone line connected to
502+
a WHOZZ Calling? device changes.</synopsis>
503+
<syntax>
504+
<channel_snapshot/>
505+
<parameter name="LineNumber">
506+
<para>The line number</para>
507+
</parameter>
508+
<parameter name="CurrentState">
509+
<para>The current state of the line.</para>
510+
<para>The possible values are:</para>
511+
<enumlist>
512+
<enum name="UNKNOWN"/>
513+
<enum name="ONHOOK"/>
514+
<enum name="OFFHOOK"/>
515+
<enum name="RINGING"/>
516+
</enumlist>
517+
</parameter>
518+
<parameter name="OldState">
519+
<para>The old state of the line.</para>
520+
<para>The possible values are:</para>
521+
<enumlist>
522+
<enum name="UNKNOWN"/>
523+
<enum name="ONHOOK"/>
524+
<enum name="OFFHOOK"/>
525+
<enum name="RINGING"/>
526+
</enumlist>
527+
</parameter>
528+
</syntax>
529+
<description>
530+
<para>This event is raised whenever the line state of a line changes.</para>
531+
</description>
532+
</managerEventInstance>
533+
</managerEvent>
534+
<managerEvent language="en_US" name="WHOZZLineCall">
535+
<managerEventInstance class="EVENT_FLAG_CALL">
536+
<synopsis>Raised when a call begins or ends on a phone line
537+
connected to a WHOZZ Calling? device.</synopsis>
538+
<syntax>
539+
<channel_snapshot/>
540+
<parameter name="LineNumber">
541+
<para>The line number</para>
542+
</parameter>
543+
<parameter name="Direction">
544+
<para>IN or OUT.</para>
545+
</parameter>
546+
<parameter name="Duration">
547+
<para>Call duration, in seconds.</para>
548+
<para>Only provided when a call ends.</para>
549+
</parameter>
550+
<parameter name="CalledNumber">
551+
<para>The called number.</para>
552+
<para>Only provided for outgoing calls.</para>
553+
</parameter>
554+
<parameter name="CallerNumber">
555+
<para>The calling number.</para>
556+
<para>Only provided for incoming calls.</para>
557+
</parameter>
558+
<parameter name="CallerName">
559+
<para>The calling name.</para>
560+
<para>Only provided for incoming calls.</para>
561+
</parameter>
562+
</syntax>
563+
<description>
564+
<para>This event is raised whenever the line state of a line changes.</para>
565+
</description>
566+
</managerEventInstance>
567+
</managerEvent>
568+
***/
450569
if (!strcasecmp(action, "F")) {
451570
ast_verb(5, "Off-hook on line %d\n", lineno);
452571
if (w->state == RINGING) {
@@ -458,13 +577,13 @@ static int __process_serial_read(struct whozz_line *w, int lineno, const char *a
458577
ast_log(LOG_WARNING, "No call in progress, ignoring call answer\n");
459578
}
460579
}
461-
w->state = OFFHOOK;
580+
update_state(w, OFFHOOK, oldstate);
462581
} else if (!strcasecmp(action, "N")) {
463582
ast_verb(5, "On-hook on line %d\n", lineno);
464-
w->state = ONHOOK;
583+
update_state(w, ONHOOK, oldstate);
465584
} else if (!strcasecmp(action, "R")) {
466585
ast_verb(5, "First ring on line %d\n", lineno);
467-
w->state = RINGING;
586+
update_state(w, RINGING, oldstate);
468587
/* This could be followed by I S: Incoming Call Start (whether or not the line has Caller ID, and even if call is answered before first ring ends)
469588
* That, in turn, is followed by F, for off hook if somebody answers it,
470589
* or I E (Incoming Call End), if ring no answer. */
@@ -498,11 +617,62 @@ static int __process_serial_read(struct whozz_line *w, int lineno, const char *a
498617
duration = atoi(durationstr);
499618
if (callend) {
500619
ast_log(LOG_NOTICE, "%s call %s on line %d to %s (%d s)\n", outbound ? "Outbound" : "Inbound", "ended", lineno, numberstr, duration);
620+
/* If we were previously ringing, and never went off-hook,
621+
* there won't be an on-hook event that will reset the line state,
622+
* do it here. */
623+
if (oldstate == RINGING) {
624+
update_state(w, ONHOOK, oldstate);
625+
}
501626
} else {
502627
ast_log(LOG_NOTICE, "%s call %s on line %d to %s\n", outbound ? "Outbound" : "Inbound", "began", lineno, numberstr);
503628
}
504629
/* Log/store the appropriate details */
505630
handle_hook(w, outbound, callend, duration, numberstr, cnam);
631+
if (callend) {
632+
if (outbound) {
633+
manager_event(EVENT_FLAG_CALL, "WHOZZLineCall",
634+
"LineNumber: %d\r\n"
635+
"Direction: %s\r\n"
636+
"Duration: %d\r\n"
637+
"CalledNumber: %s\r\n",
638+
w->lineno,
639+
outbound ? "OUT" : "IN",
640+
duration,
641+
numberstr);
642+
} else {
643+
manager_event(EVENT_FLAG_CALL, "WHOZZLineCall",
644+
"LineNumber: %d\r\n"
645+
"Direction: %s\r\n"
646+
"Duration: %d\r\n"
647+
"CallerNumber: %s\r\n"
648+
"CallerName: %s\r\n",
649+
w->lineno,
650+
outbound ? "OUT" : "IN",
651+
duration,
652+
numberstr,
653+
cnam);
654+
}
655+
} else {
656+
if (outbound) {
657+
manager_event(EVENT_FLAG_CALL, "WHOZZLineCall",
658+
"LineNumber: %d\r\n"
659+
"Direction: %s\r\n"
660+
"CalledNumber: %s\r\n",
661+
w->lineno,
662+
outbound ? "OUT" : "IN",
663+
numberstr);
664+
} else {
665+
manager_event(EVENT_FLAG_CALL, "WHOZZLineCall",
666+
"LineNumber: %d\r\n"
667+
"Direction: %s\r\n"
668+
"CallerNumber: %s\r\n"
669+
"CallerName: %s\r\n",
670+
w->lineno,
671+
outbound ? "OUT" : "IN",
672+
numberstr,
673+
cnam);
674+
}
675+
}
506676
}
507677
return 0;
508678
}
@@ -633,6 +803,34 @@ static void *__serial_monitor(void *varg)
633803
return NULL;
634804
}
635805

806+
static int whozz_line_state_read(struct ast_channel *chan, const char *cmd, char *parse, char *buffer, size_t buflen)
807+
{
808+
int lineno;
809+
struct whozz_line *w;
810+
811+
if (ast_strlen_zero(parse)) {
812+
ast_log(LOG_ERROR, "Line number required for %s\n", cmd);
813+
return -1;
814+
}
815+
816+
lineno = atoi(parse);
817+
AST_RWLIST_RDLOCK(&lines);
818+
AST_RWLIST_TRAVERSE(&lines, w, entry) {
819+
if (w->lineno == lineno) {
820+
ast_copy_string(buffer, state_str_func(w->state), buflen);
821+
break;
822+
}
823+
}
824+
AST_RWLIST_UNLOCK(&lines);
825+
826+
return w ? 0 : -1;
827+
}
828+
829+
static struct ast_custom_function acf_whozz = {
830+
.name = "WHOZZ_LINE_STATE",
831+
.read = whozz_line_state_read,
832+
};
833+
636834
static char *handle_show_whozz(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
637835
{
638836
struct whozz_line *w;
@@ -655,7 +853,7 @@ static char *handle_show_whozz(struct ast_cli_entry *e, int cmd, struct ast_cli_
655853
ast_cli(a->fd, "%4s %-8s %s\n", "Line", "State", "Associated Device");
656854
AST_RWLIST_RDLOCK(&lines);
657855
AST_RWLIST_TRAVERSE(&lines, w, entry) {
658-
ast_cli(a->fd, "%4d %-8s %s\n", w->lineno, state_str(w->state), S_OR(w->device, ""));
856+
ast_cli(a->fd, "%4d %-8s %s\n", w->lineno, state_str_cli(w->state), S_OR(w->device, ""));
659857
}
660858
AST_RWLIST_UNLOCK(&lines);
661859

@@ -763,6 +961,7 @@ static int unload_module(void)
763961

764962
unloading = 1;
765963
ast_cli_unregister_multiple(whozz_cli, ARRAY_LEN(whozz_cli));
964+
ast_custom_function_unregister(&acf_whozz);
766965
if (serial_fd != -1) {
767966
if (serial_thread != AST_PTHREADT_NULL) {
768967
/* Interrupt any system call */
@@ -826,6 +1025,7 @@ static int load_module(void)
8261025
return AST_MODULE_LOAD_DECLINE;
8271026
}
8281027

1028+
ast_custom_function_register(&acf_whozz);
8291029
ast_cli_register_multiple(whozz_cli, ARRAY_LEN(whozz_cli));
8301030
return res;
8311031
}

0 commit comments

Comments
 (0)