more sip fixes
[lcr.git] / dov.cpp
1 /*****************************************************************************\
2 **                                                                           **
3 ** Linux-Call-Router                                                         **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** data-over-voice                                                           **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 /*
13
14 Protocol description:
15
16 PCM: A bit is defined as sample value. A 1 is positive level, a 0 negative.
17 The bit rate is 8000 Hz.
18
19 PWM: A bit is defined by a duration between polarity change of signal. 4
20 samples duration is 0, 12 samples duration is 1.
21
22 GGGGGGGGGGGGG....
23 0LLLLLLLL
24 0DDDDDDDD
25 0DDDDDDDD
26 ....
27 0CCCCCCCC
28 0CCCCCCCC
29 0CCCCCCCC
30 0CCCCCCCC
31 GGGGGGGGGGGGG....
32
33 G=guard / sync sequnce (bit=1)
34 L=length information (lsb first)
35 D=data (lsb first)
36 C=CRC (lsb first, network byte order)
37
38 */
39
40 #include "main.h"
41
42 //#define DEBUG_DOV
43
44 #define DOV_PWM_LEVEL 819
45 #define DOV_PCM_LEVEL 100
46 #define DOV_PCM_GUARD 400
47 #define DOV_PWM_GUARD 34
48
49 #define DOV_TX_SEND_DELAY       3, 0
50 #define DOV_RX_LISTEN_TIMEOUT   30, 0
51
52 static unsigned int dov_crc32_table[256];
53
54 inline unsigned int dov_crc_reflect(unsigned int ref, unsigned char ch)
55 {
56         unsigned int value = 0;
57         int i;
58
59         for (i = 1; i < ch + 1; i++) {
60                 if ((ref & 1))
61                         value |= 1 << (ch - i);
62                 ref >>= 1;
63         }
64         return value;
65 }
66
67
68 /*
69  * initialize CRC table
70  */
71 void dov_crc_init(void)
72 {
73         unsigned int ulPolynomial = 0x04c11db7;
74         int i, j;
75
76         for (i = 0; i < 256; i++) {
77                 dov_crc32_table[i] = dov_crc_reflect(i, 8) << 24;
78                 for (j = 0; j < 8; j++)
79                         dov_crc32_table[i] = (dov_crc32_table[i] << 1) ^
80                                 (dov_crc32_table[i] & (1 << 31) ?
81                                         ulPolynomial : 0);
82                 dov_crc32_table[i] =
83                         dov_crc_reflect(dov_crc32_table[i], 32);
84         }
85 }
86
87
88 /*
89  * calculate CRC 32 of given data
90  *
91  * data: pointer to data
92  * length: length of data
93  * return: CRC 32
94  */
95 unsigned int dov_crc32(unsigned char *data, int length)
96 {
97         unsigned int crc = 0xffffffff;
98
99         while (length--)
100                 crc = (crc >> 8) ^ dov_crc32_table[(crc & 0xff) ^ *data++];
101
102         return crc ^ 0xffffffff;
103 }
104
105 int dov_tx_timer(struct lcr_timer *timer, void *instance, int index);
106 int dov_rx_timer(struct lcr_timer *timer, void *instance, int index);
107
108 void Port::dov_init(void)
109 {
110 #ifdef DEBUG_DOV
111         printf("DOV: init\n");
112 #endif
113
114         dov_crc_init();
115         p_dov_tx = 0;
116         p_dov_rx = 0;
117         p_dov_tx_data = NULL;
118         p_dov_rx_data = NULL;
119         memset(&p_dov_tx_timer, 0, sizeof(p_dov_tx_timer));
120         add_timer(&p_dov_tx_timer, dov_tx_timer, this, 0);
121         memset(&p_dov_rx_timer, 0, sizeof(p_dov_rx_timer));
122         add_timer(&p_dov_rx_timer, dov_rx_timer, this, 0);
123 }
124
125
126 void Port::dov_reset_tx(void)
127 {
128 #ifdef DEBUG_DOV
129         printf("DOV: reset TX\n");
130 #endif
131
132         if (p_dov_tx_data)
133                 FREE(p_dov_tx_data, p_dov_tx_data_length);
134         p_dov_tx_data = NULL;
135         p_dov_tx = 0;
136         unsched_timer(&p_dov_tx_timer);
137 }
138
139 void Port::dov_reset_rx(void)
140 {
141 #ifdef DEBUG_DOV
142         printf("DOV: reset RX\n");
143 #endif
144
145         if (p_dov_rx_data)
146                 FREE(p_dov_rx_data, 255 + 5);
147         p_dov_rx_data = NULL;
148         p_dov_rx = 0;
149         update_rxoff();
150         unsched_timer(&p_dov_rx_timer);
151 }
152
153 void Port::dov_exit(void)
154 {
155 #ifdef DEBUG_DOV
156         printf("DOV: exit\n");
157 #endif
158
159         dov_reset_tx();
160         del_timer(&p_dov_tx_timer);
161         dov_reset_rx();
162         del_timer(&p_dov_rx_timer);
163 }
164
165 void Port::dov_sendmsg(unsigned char *data, int length, enum dov_type type, int level)
166 {
167         unsigned int crc;
168
169 #ifdef DEBUG_DOV
170         printf("DOV: send message, start timer\n");
171 #endif
172
173         dov_reset_tx();
174
175         if (!length)
176                 return;
177         p_dov_tx_data = (unsigned char *)MALLOC(length + 5);
178         p_dov_tx_data[0] = length;
179         memcpy(p_dov_tx_data + 1, data, length);
180         crc = dov_crc32(data, length);
181         p_dov_tx_data[length+1] = crc >> 24;
182         p_dov_tx_data[length+2] = crc >> 16;
183         p_dov_tx_data[length+3] = crc >> 8;
184         p_dov_tx_data[length+4] = crc;
185         p_dov_tx_data_length = length + 5;
186         p_dov_tx_data_pos = 0;
187         p_dov_tx_sync = 1;
188         p_dov_tx_bit_pos = 0;
189         p_dov_tx_pwm_pos = 0;
190
191         p_dov_tx_type = type;
192         if (level) {
193                 p_dov_up = audio_s16_to_law[(level) & 0xffff];
194                 p_dov_down = audio_s16_to_law[(-level) & 0xffff];
195         } else if (type == DOV_TYPE_PWM) {
196                 p_dov_up = audio_s16_to_law[(DOV_PWM_LEVEL) & 0xffff];
197                 p_dov_down = audio_s16_to_law[(-DOV_PWM_LEVEL) & 0xffff];
198         } else {
199                 p_dov_up = audio_s16_to_law[(DOV_PCM_LEVEL) & 0xffff];
200                 p_dov_down = audio_s16_to_law[(-DOV_PCM_LEVEL) & 0xffff];
201         }
202
203         schedule_timer(&p_dov_tx_timer, DOV_TX_SEND_DELAY);
204 }
205
206 int dov_tx_timer(struct lcr_timer *timer, void *instance, int index)
207 {
208         class Port *port = (class Port *)instance;
209
210 #ifdef DEBUG_DOV
211         printf("DOV: timer fires, now sending\n");
212 #endif
213
214         port->p_dov_tx = 1;
215
216         return 0;
217 }
218
219 int Port::dov_tx(unsigned char *data, int length)
220 {
221         int left = 0;
222
223         if (!p_dov_tx)
224                 return 0;
225
226         switch (p_dov_tx_type) {
227         case DOV_TYPE_PWM:
228 #ifdef DEBUG_DOV
229                 printf("DOV: prepare %d bytes of PWM data\n", length);
230 #endif
231                 left = dov_tx_pwm(data, length);
232                 break;
233         case DOV_TYPE_PCM:
234 #ifdef DEBUG_DOV
235                 printf("DOV: prepare %d bytes of PCM data\n", length);
236 #endif
237                 left = dov_tx_pcm(data, length);
238                 break;
239         }
240
241         return length - left;
242 }
243
244 int Port::dov_tx_pwm(unsigned char *data, int length)
245 {
246         while (length) {
247                 /* send sync / guard sequence */
248                 if (p_dov_tx_sync) {
249                         if (p_dov_tx_up) {
250                                 while (p_dov_tx_pwm_pos < 12) {
251                                         *data++ = p_dov_up;
252                                         p_dov_tx_pwm_pos++;
253                                         if (--length == 0)
254                                                 return 0;
255                                 }
256                                 p_dov_tx_up = 0;
257                         } else {
258                                 while (p_dov_tx_pwm_pos < 12) {
259                                         *data++ = p_dov_down;
260                                         p_dov_tx_pwm_pos++;
261                                         if (--length == 0)
262                                                 return 0;
263                                 }
264                                 p_dov_tx_up = 1;
265                         }
266                         p_dov_tx_pwm_pos = 0;
267                         if (++p_dov_tx_bit_pos == DOV_PWM_GUARD) {
268 #ifdef DEBUG_DOV
269                                 printf("DOV: TX, done with guard\n");
270 #endif
271                                 p_dov_tx_bit_pos = -1;
272                                 if (p_dov_tx_sync == 2) {
273                                         dov_reset_tx();
274                                         return length;
275                                 }
276                                 p_dov_tx_sync = 0;
277                         }
278                         continue;
279                 }
280
281                 /* send start of byte */
282                 if (p_dov_tx_data_length == -1) {
283                         if (p_dov_tx_up) {
284                                 while (p_dov_tx_pwm_pos < 4) {
285                                         *data++ = p_dov_up;
286                                         p_dov_tx_pwm_pos++;
287                                         if (--length == 0)
288                                                 return 0;
289                                 }
290                                 p_dov_tx_up = 0;
291                         } else {
292                                 while (p_dov_tx_pwm_pos < 4) {
293                                         *data++ = p_dov_down;
294                                         p_dov_tx_pwm_pos++;
295                                         if (--length == 0)
296                                                 return 0;
297                                 }
298                                 p_dov_tx_up = 1;
299                         }
300                         p_dov_tx_pwm_pos = 0;
301                         p_dov_tx_bit_pos = 0;
302                         continue;
303                 }
304
305                 /* send data */
306                 if ((p_dov_tx_data[p_dov_tx_data_pos] >> p_dov_tx_bit_pos) & 1) {
307                         if (p_dov_tx_up) {
308                                 while (p_dov_tx_pwm_pos < 12) {
309                                         *data++ = p_dov_up;
310                                         p_dov_tx_pwm_pos++;
311                                         if (--length == 0)
312                                                 return 0;
313                                 }
314                                 p_dov_tx_up = 0;
315                         } else {
316                                 while (p_dov_tx_pwm_pos < 12) {
317                                         *data++ = p_dov_down;
318                                         p_dov_tx_pwm_pos++;
319                                         if (--length == 0)
320                                                 return 0;
321                                 }
322                                 p_dov_tx_up = 1;
323                         }
324                 } else {
325                         if (p_dov_tx_up) {
326                                 while (p_dov_tx_pwm_pos < 4) {
327                                         *data++ = p_dov_up;
328                                         p_dov_tx_pwm_pos++;
329                                         if (--length == 0)
330                                                 return 0;
331                                 }
332                                 p_dov_tx_up = 0;
333                         } else {
334                                 while (p_dov_tx_pwm_pos < 4) {
335                                         *data++ = p_dov_down;
336                                         p_dov_tx_pwm_pos++;
337                                         if (--length == 0)
338                                                 return 0;
339                                 }
340                                 p_dov_tx_up = 1;
341                         }
342                 }
343                 p_dov_tx_pwm_pos = 0;
344                 if (++p_dov_tx_bit_pos == 8) {
345                         p_dov_tx_bit_pos = -1;
346 #ifdef DEBUG_DOV
347                         printf("DOV: TX, done with byte %d\n", p_dov_tx_data[p_dov_tx_data_pos]);
348 #endif
349                         if (p_dov_tx_data_pos++ == p_dov_tx_data_length) {
350                                 p_dov_tx_sync = 2;
351                         }
352                 }
353         }
354
355         return 0;
356 }
357
358 int Port::dov_tx_pcm(unsigned char *data, int length)
359 {
360         while (length--) {
361                 /* send sync / guard sequence */
362                 if (p_dov_tx_sync) {
363                         *data++ = p_dov_up;
364                         if (++p_dov_tx_bit_pos == DOV_PCM_GUARD) {
365 #ifdef DEBUG_DOV
366                                 printf("DOV: TX, done with guard\n");
367 #endif
368                                 p_dov_tx_bit_pos = -1;
369                                 if (p_dov_tx_sync == 2) {
370                                         dov_reset_tx();
371                                         return length;
372                                 }
373                                 p_dov_tx_sync = 0;
374                         }
375                         continue;
376                 }
377
378                 /* send start of byte */
379                 if (p_dov_tx_data_length == -1) {
380                         *data++ = p_dov_down;
381                         p_dov_tx_bit_pos = 0;
382                         continue;
383                 }
384
385                 /* send data */
386                 *data++ = (((p_dov_tx_data[p_dov_tx_data_pos] >> p_dov_tx_bit_pos) & 1)) ? p_dov_up : p_dov_down;
387                 if (++p_dov_tx_bit_pos == 8) {
388                         p_dov_tx_bit_pos = -1;
389 #ifdef DEBUG_DOV
390                         printf("DOV: TX, done with byte %d\n", p_dov_tx_data[p_dov_tx_data_pos]);
391 #endif
392                         if (p_dov_tx_data_pos++ == p_dov_tx_data_length) {
393                                 p_dov_tx_sync = 2;
394                         }
395                 }
396         }
397
398         return 0;
399 }
400
401 void Port::dov_listen(enum dov_type type)
402 {
403 #ifdef DEBUG_DOV
404         printf("DOV: start listening, start timer\n");
405 #endif
406
407         dov_reset_rx();
408
409         p_dov_rx_data = (unsigned char *)MALLOC(255 + 5);
410         p_dov_rx_data_pos = 0;
411         p_dov_rx_sync = 1;
412         p_dov_rx_bit_pos = 0;
413         p_dov_rx_pwm_pos = 0;
414         p_dov_rx_pwm_duration = 0;
415         p_dov_rx_pwm_polarity = 0;
416         p_dov_rx_sync_word = 0;
417
418         p_dov_rx_type = type;
419
420         p_dov_rx = 1;
421         update_rxoff();
422
423         schedule_timer(&p_dov_rx_timer, DOV_RX_LISTEN_TIMEOUT);
424 }
425
426 int dov_rx_timer(struct lcr_timer *timer, void *instance, int index)
427 {
428         class Port *port = (class Port *)instance;
429
430 #ifdef DEBUG_DOV
431         printf("DOV: timer fires, now stop listening\n");
432 #endif
433
434         port->dov_reset_rx();
435
436         return 0;
437 }
438
439 void Port::dov_rx(unsigned char *data, int length)
440 {
441         if (!p_dov_rx)
442                 return;
443
444         switch (p_dov_rx_type) {
445         case DOV_TYPE_PWM:
446 #ifdef DEBUG_DOV
447                 printf("DOV: received %d bytes of PWM data\n", length);
448 #endif
449                 dov_rx_pwm(data, length);
450                 break;
451         case DOV_TYPE_PCM:
452 #ifdef DEBUG_DOV
453                 printf("DOV: received %d bytes of PCM data\n", length);
454 #endif
455                 dov_rx_pcm(data, length);
456                 break;
457         }
458 }
459
460 void Port::dov_rx_pwm(unsigned char *data, int length)
461 {
462         signed int sample;
463         signed int level;
464
465         while (length--) {
466                 sample = audio_law_to_s32[*data++];
467                 p_dov_rx_pwm_duration++;
468                 if (p_dov_rx_pwm_polarity == 1) {
469                         if (sample > 0)
470                                 continue;
471                         p_dov_rx_pwm_polarity = 0;
472                         if (p_dov_rx_pwm_duration < 8)
473                                 level = 0;
474                         else
475                                 level = 1;
476                         p_dov_rx_pwm_duration = 0;
477                 } else {
478                         if (sample <= 0)
479                                 continue;
480                         p_dov_rx_pwm_polarity = 1;
481                         if (p_dov_rx_pwm_duration < 8)
482                                 level = 0;
483                         else
484                                 level = 1;
485                         p_dov_rx_pwm_duration = 0;
486                 }
487
488                 /* catch sync */
489                 p_dov_rx_sync_word <<= 1;
490                 if (level > 0)
491                         p_dov_rx_sync_word |= 1;
492                 if ((p_dov_rx_sync_word & 0x1ff) == 0x1ff) {
493                         p_dov_rx_bit_pos = -1;
494                         p_dov_rx_sync = 1;
495                         p_dov_rx_data_pos = 0;
496                         continue;
497                 }
498                 /* wait for sync */
499                 if (!p_dov_rx_sync) {
500                         continue;
501                 }
502                 /* read start bit */
503                 if (p_dov_rx_bit_pos == -1) {
504                         /* check violation of start bit */
505                         if (level > 0) {
506                                 p_dov_rx_sync = 0;
507                                 continue;
508                         }
509                         p_dov_rx_bit_pos = 0;
510                         continue;
511                 }
512                 /* read data */
513                 p_dov_rx_data[p_dov_rx_data_pos] >>= 1;
514                 if (level > 0)
515                         p_dov_rx_data[p_dov_rx_data_pos] |= 128;
516                 if (++p_dov_rx_bit_pos == 8) {
517 #ifdef DEBUG_DOV
518                         printf("DOV: RX byte %d\n", p_dov_rx_data[p_dov_rx_data_pos]);
519 #endif
520                         p_dov_rx_bit_pos = -1;
521                         /* check for length,data,crc32 */
522                         if (++p_dov_rx_data_pos == p_dov_rx_data[0] + 5) {
523                                 dov_message(p_dov_rx_data + 1, p_dov_rx_data[0]);
524                                 p_dov_rx_sync = 0;
525                         }
526                 }
527         }
528
529 }
530
531 void Port::dov_rx_pcm(unsigned char *data, int length)
532 {
533         signed int level;
534
535         while (length--) {
536                 level = audio_law_to_s32[*data++];
537                 /* catch sync */
538                 p_dov_rx_sync_word <<= 1;
539                 if (level > 0)
540                         p_dov_rx_sync_word |= 1;
541                 if ((p_dov_rx_sync_word & 0x1ff) == 0x1ff) {
542                         p_dov_rx_bit_pos = -1;
543                         p_dov_rx_sync = 1;
544                         p_dov_rx_data_pos = 0;
545                         continue;
546                 }
547                 /* wait for sync */
548                 if (!p_dov_rx_sync) {
549                         continue;
550                 }
551                 /* read start bit */
552                 if (p_dov_rx_bit_pos == -1) {
553                         /* check violation of start bit */
554                         if (level > 0) {
555                                 p_dov_rx_sync = 0;
556                                 continue;
557                         }
558                         p_dov_rx_bit_pos = 0;
559                         continue;
560                 }
561                 /* read data */
562                 p_dov_rx_data[p_dov_rx_data_pos] >>= 1;
563                 if (level > 0)
564                         p_dov_rx_data[p_dov_rx_data_pos] |= 128;
565                 if (++p_dov_rx_bit_pos == 8) {
566 #ifdef DEBUG_DOV
567                         printf("DOV: RX byte %d\n", p_dov_rx_data[p_dov_rx_data_pos]);
568 #endif
569                         p_dov_rx_bit_pos = -1;
570                         /* check for length,data,crc32 */
571                         if (++p_dov_rx_data_pos == p_dov_rx_data[0] + 5) {
572                                 dov_message(p_dov_rx_data + 1, p_dov_rx_data[0]);
573                                 p_dov_rx_sync = 0;
574                         }
575                 }
576         }
577 }
578
579 void Port::dov_message(unsigned char *data, int length)
580 {
581         unsigned int crc;
582         struct lcr_msg *message;
583
584         /* prevent receiving zeroes (due to line noise). this would cause 0 crc, which seems correct. */
585         if (length == 0)
586                 return;
587
588 #ifdef DEBUG_DOV
589         printf("DOV: received message\n");
590 #endif
591
592         crc = dov_crc32(p_dov_rx_data + 1, p_dov_rx_data[0]);
593         if (crc != (unsigned int) (     ((p_dov_rx_data[length+1]) << 24) |
594                                         ((p_dov_rx_data[length+2]) << 16) |
595                                         ((p_dov_rx_data[length+3]) << 8) |
596                                         (p_dov_rx_data[length+4]) ))
597                 return;
598
599 #ifdef DEBUG_DOV
600         printf("DOV: crc OK\n");
601 #endif
602
603         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_DOV_INDICATION);
604         message->param.dov.type = p_dov_rx_type;
605         message->param.dov.length = p_dov_rx_data[0];
606         memcpy(message->param.dov.data, p_dov_rx_data + 1, p_dov_rx_data[0]);
607         PDEBUG(DEBUG_PORT, "PmISDN(%s) Data-Over-Voice message received (len=%d)\n", p_name, message->param.dov.length);
608         message_put(message);
609
610         dov_reset_rx();
611 }
612