[ifxmips]
[openwrt/svn-archive/archive.git] / package / tapi_sip / src / dialdetector.c
1 #include <linux/input.h>
2 #include <sys/epoll.h>
3 #include <stdint.h>
4 #include <stdbool.h>
5
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <unistd.h>
10
11 #include <events.h>
12 #include "timerfd.h"
13
14 #include "tapi-port.h"
15 #include "dialdetector.h"
16
17 static const struct itimerspec dialdetector_timeout = {
18 .it_value.tv_sec = 3,
19 };
20
21 static const struct itimerspec dialdetector_impulse_timeout = {
22 .it_value.tv_nsec = 200000000,
23 };
24
25 static void dialdetector_note_digit(struct dialdetector *d, unsigned char digit)
26 {
27 printf("note digit: %d\n", d->num_digits);
28
29 d->digits[d->num_digits] = digit;
30 ++d->num_digits;
31
32 timerfd_settime(d->timer_fd, 0, &dialdetector_timeout, NULL);
33 d->dial_state = DIALDETECTOR_DIAL_WAIT_TIMEOUT;
34 }
35
36 static void dialdetector_reset(struct dialdetector *d)
37 {
38 d->num_digits = 0;
39 d->impulses = 0;
40 d->dial_state = DIALDETECTOR_DIAL_WAIT;
41 d->port_state = DIALDETECTOR_PORT_INACTIVE;
42 }
43
44 static bool dialdetector_timeout_event(int events, void *data)
45 {
46 char num[20];
47 struct dialdetector *dialdetector = data;
48 int i;
49 uint64_t tmp;
50
51 read(dialdetector->timer_fd, &tmp, sizeof(tmp));
52
53 for (i = 0; i < dialdetector->num_digits; ++i) {
54 num[i] = '0' + dialdetector->digits[i];
55 }
56 num[i] = '\0';
57
58 dialdetector->dial_callback(dialdetector->port, dialdetector->num_digits,
59 dialdetector->digits);
60
61 dialdetector_reset(dialdetector);
62
63 return true;
64 }
65
66 static bool dialdetector_impulse_timeout_cb(int events, void *data)
67 {
68 struct dialdetector *d = data;
69 uint64_t tmp;
70
71 read(d->impulse_timer_fd, &tmp, sizeof(tmp));
72
73 if (d->port_state == DIALDETECTOR_PORT_ACTIVE_DOWN) {
74 d->port_state = DIALDETECTOR_PORT_INACTIVE;
75 } else {
76 printf("impulse: %d\n", d->impulses);
77 if (d->impulses > 0)
78 dialdetector_note_digit(d, d->impulses < 10 ? d->impulses : 0);
79 d->impulses = 0;
80 }
81
82 return true;
83 }
84
85 static void dialdetector_port_event(struct tapi_port *port,
86 struct tapi_event *event, void *data)
87 {
88 struct dialdetector *d = data;
89
90 printf("port event: %d %d\n", d->port_state, event->hook.on);
91
92 switch (d->port_state) {
93 case DIALDETECTOR_PORT_INACTIVE:
94 if (event->type == TAPI_EVENT_TYPE_HOOK && event->hook.on == false)
95 d->port_state = DIALDETECTOR_PORT_ACTIVE;
96 break;
97 case DIALDETECTOR_PORT_ACTIVE:
98 switch (event->type) {
99 case TAPI_EVENT_TYPE_HOOK:
100 if (event->hook.on == true) {
101 d->port_state = DIALDETECTOR_PORT_ACTIVE_DOWN;
102 timerfd_settime(d->impulse_timer_fd, 0, &dialdetector_impulse_timeout, NULL);
103 }
104 break;
105 case TAPI_EVENT_TYPE_DTMF:
106 dialdetector_note_digit(d, event->dtmf.code);
107 break;
108 }
109 break;
110 case DIALDETECTOR_PORT_ACTIVE_DOWN:
111 if (event->type == TAPI_EVENT_TYPE_HOOK && event->hook.on == false) {
112 timerfd_settime(d->timer_fd, 0, &dialdetector_timeout, NULL);
113 ++d->impulses;
114 d->port_state = DIALDETECTOR_PORT_ACTIVE;
115 }
116 break;
117 }
118 }
119
120 struct dialdetector *dialdetector_alloc(struct tapi_port *port)
121 {
122 struct dialdetector *dialdetector;
123 dialdetector = malloc(sizeof(*dialdetector));
124
125 dialdetector->timer_fd = timerfd_create(CLOCK_MONOTONIC, 0);
126 dialdetector->impulse_timer_fd = timerfd_create(CLOCK_MONOTONIC, 0);
127 dialdetector->port = port;
128 dialdetector->num_digits = 0;
129 dialdetector->impulses = 0;
130 dialdetector->dial_state = DIALDETECTOR_DIAL_WAIT;
131 dialdetector->port_state = DIALDETECTOR_PORT_INACTIVE;
132
133 dialdetector->timeout_cb.callback = dialdetector_timeout_event;
134 dialdetector->timeout_cb.data = dialdetector;
135 dialdetector->impulse_cb.callback = dialdetector_impulse_timeout_cb;
136 dialdetector->impulse_cb.data = dialdetector;
137
138 dialdetector->port_listener.callback = dialdetector_port_event;
139 dialdetector->port_listener.data = dialdetector;
140
141 tapi_port_register_event(port, &dialdetector->port_listener);
142
143 event_register(dialdetector->impulse_timer_fd, EPOLLIN,
144 &dialdetector->impulse_cb);
145 event_register(dialdetector->timer_fd, EPOLLIN, &dialdetector->timeout_cb);
146
147 return dialdetector;
148 }