[ifxmips]
[openwrt.git] / package / libtapi / 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
10 #include "events.h"
11 #include "timerfd.h"
12
13 #include "tapi-port.h"
14 #include "dialdetector.h"
15
16 static const struct itimerspec dialdetector_timeout = {
17         .it_value.tv_sec = 3,
18 };
19
20 static void dialdetector_note_digit(struct dialdetector *d, unsigned char digit)
21 {
22         printf("note digit: %d\n", d->num_digits);
23         d->digits[d->num_digits] = digit;
24         ++d->num_digits;
25 }
26
27 static void dialdetector_reset(struct dialdetector *d)
28 {
29         event_unregister(d->timer_fd);
30         d->num_digits = 0;
31         d->state = DIALDETECTOR_IDLE;
32 }
33
34 static bool dialdetector_timeout_event(int events, void *data)
35 {
36         char num[20];
37         struct dialdetector *dialdetector = data;
38         int i;
39
40         for (i = 0; i < dialdetector->num_digits; ++i) {
41                 num[i] = '0' + dialdetector->digits[i];
42         }
43         num[i] = '\0';
44
45         printf("Dialing: %s\n", num);
46         dialdetector->dial_callback(dialdetector->port, dialdetector->num_digits,
47         dialdetector->digits);
48
49         dialdetector_reset(dialdetector);
50
51         return false;
52 }
53
54 static void dialdetector_port_event(struct tapi_port *port,
55         struct tapi_event *event, void *data)
56 {
57         struct dialdetector *d = data;
58
59         printf("port event: %d %d\n", d->state, event->hook.on);
60
61         switch (d->state) {
62         case DIALDETECTOR_IDLE:
63                 if (event->type == TAPI_EVENT_TYPE_HOOK && event->hook.on == false) {
64                         d->state = DIALDETECTOR_WAIT_FOR_NUMBER;
65                         event_register(d->timer_fd, EPOLLIN, &d->timeout_cb);
66                         timerfd_settime(d->timer_fd, 0, &dialdetector_timeout, NULL);
67                 }
68                 break;
69         case DIALDETECTOR_WAIT_FOR_NUMBER:
70         case DIALDETECTOR_WAIT_FOR_NUMBER_TIMEOUT:
71                 switch (event->type) {
72                 case TAPI_EVENT_TYPE_HOOK:
73                         if (event->hook.on == true)
74                                 dialdetector_reset(d);
75                         break;
76                 case TAPI_EVENT_TYPE_DTMF:
77                         if (d->state == DIALDETECTOR_WAIT_FOR_NUMBER)
78                                 event_register(d->timer_fd, EPOLLIN, &d->timeout_cb);
79                         timerfd_settime(d->timer_fd, 0, &dialdetector_timeout, NULL);
80                         d->state = DIALDETECTOR_WAIT_FOR_NUMBER_TIMEOUT;
81                         dialdetector_note_digit(d, event->dtmf.code);
82                         break;
83                 default:
84                         break;
85                 }
86         }
87 }
88
89 struct dialdetector *dialdetector_alloc(struct tapi_port *port)
90 {
91         struct dialdetector *dialdetector;
92         dialdetector = malloc(sizeof(*dialdetector));
93
94         dialdetector->timer_fd = timerfd_create(CLOCK_MONOTONIC, 0);
95         dialdetector->port = port;
96         dialdetector->num_digits = 0;
97         dialdetector->state = DIALDETECTOR_IDLE;
98
99         dialdetector->timeout_cb.callback = dialdetector_timeout_event;
100         dialdetector->timeout_cb.data = dialdetector;
101
102         dialdetector->port_listener.callback = dialdetector_port_event;
103         dialdetector->port_listener.data = dialdetector;
104
105         tapi_port_register_event(port, &dialdetector->port_listener);
106
107
108         return dialdetector;
109 }