]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Changes to allow receiving japanese callerid (Bug #5928)
authorMatthew Fredrickson <creslin@digium.com>
Fri, 6 Jan 2006 20:03:20 +0000 (20:03 +0000)
committerMatthew Fredrickson <creslin@digium.com>
Fri, 6 Jan 2006 20:03:20 +0000 (20:03 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@7842 65c4cc65-6c06-0410-ace0-fbb531ad65f3

callerid.c
channels/chan_zap.c
include/asterisk/callerid.h

index d1a29d4ed0e0fbb475f1889b1919d237370da382..0f382fcc9a1edc474565e37449f36b273f855bec 100644 (file)
@@ -57,6 +57,9 @@ struct callerid_state {
        int flags;
        int sawflag;
        int len;
+
+       int skipflag; 
+       unsigned short crc;
 };
 
 
@@ -252,6 +255,278 @@ int ast_gen_cas(unsigned char *outbuf, int sendsas, int len, int codec)
        return 0;
 }
 
+static unsigned short calc_crc(unsigned short crc, unsigned char data)
+{
+       unsigned int i, j, org, dst;
+       org = data;
+       dst = 0;
+       for (i=0; i<CHAR_BIT; i++) {
+               org <<= 1;
+               dst >>= 1;
+               if (org & 0x100) {
+               dst |= 0x80;
+               }
+       }
+       data = (unsigned char)dst;
+       crc ^= (unsigned int)data << (16 - CHAR_BIT);
+       for ( j=0; j<CHAR_BIT; j++ ) {
+               if ( crc & 0x8000U ) crc = (crc << 1) ^ 0x1021U ;
+               else crc <<= 1 ;
+       }
+       return crc;
+}
+
+int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, int codec)
+{
+       int mylen = len;
+       int olen;
+       int b = 'X';
+       int b2 ;
+       int res;
+       int x;
+       short *buf = malloc(2 * len + cid->oldlen);
+       short *obuf = buf;
+
+       if (!buf) {
+               ast_log(LOG_WARNING, "Out of memory\n");
+               return -1;
+       }
+
+       memset(buf, 0, 2 * len + cid->oldlen);
+       memcpy(buf, cid->oldstuff, cid->oldlen);
+       mylen += cid->oldlen/2;
+
+       for (x=0;x<len;x++) 
+               buf[x+cid->oldlen/2] = AST_XLAW(ubuf[x]);
+
+       while (mylen >= 160) {
+        b = b2 = 0 ;
+               olen = mylen;
+               res = fsk_serie(&cid->fskd, buf, &mylen, &b);
+
+               if (mylen < 0) {
+                       ast_log(LOG_ERROR, "fsk_serie made mylen < 0 (%d)\n", mylen);
+                       return -1;
+               }
+
+               buf += (olen - mylen);
+
+               if (res < 0) {
+                       ast_log(LOG_NOTICE, "fsk_serie failed\n");
+                       return -1;
+               }
+
+               if (res == 1) {
+
+                       b2 = b ;
+                       b  = b & 0x7f ;
+
+                       /* crc checksum calculation */
+                       if ( cid->sawflag > 1 ) {
+                               cid->crc = calc_crc(cid->crc, (unsigned char)b2);
+                       }
+
+                       /* Ignore invalid bytes */
+                       if (b > 0xff) {
+                               continue;
+                       }
+
+                       /* skip DLE if needed */
+                       if ( cid->sawflag > 0 ) {
+                               if ( cid->sawflag != 5 && cid->skipflag == 0 && b == 0x10 ) {
+                                       cid->skipflag = 1 ;
+                                       continue ;
+                               }
+                       }
+                       if ( cid->skipflag == 1 ) {
+                               cid->skipflag = 0 ;
+                       }
+
+                       /* caller id retrieval */
+                       switch(cid->sawflag) {
+                               case 0: /* DLE */
+                                       if (b == 0x10) {
+                                               cid->sawflag = 1;
+                                               cid->skipflag = 0;
+                                               cid->crc = 0;
+                                       }
+                                       break;
+                               case 1: /* SOH */
+                                       if (b == 0x01) {
+                                               cid->sawflag = 2;
+                                       }
+                                       break ;
+                               case 2: /* HEADER */
+                                       if (b == 0x07) {
+                                               cid->sawflag = 3;
+                                       }
+                                       break;
+                               case 3: /* STX */
+                                       if (b == 0x02) {
+                                               cid->sawflag = 4;
+                                       }
+                                       break;
+                               case 4: /* SERVICE TYPE */
+                                       if (b == 0x40) {
+                                               cid->sawflag = 5;
+                                       }
+                                       break;
+                               case 5: /* Frame Length */
+                                       cid->sawflag = 6;
+                                       break;  
+                               case 6: /* NUMBER TYPE */
+                                       cid->sawflag = 7;
+                                       cid->pos = 0;
+                                       cid->rawdata[cid->pos++] = b;
+                                       break;
+                               case 7: /* NUMBER LENGTH */
+                                       cid->sawflag = 8;
+                                       cid->len = b;
+                                       if ( (cid->len+2) >= sizeof( cid->rawdata ) ) {
+                                               ast_log(LOG_WARNING, "too long caller id string\n" ) ;
+                                               return -1;
+                                       }
+                                       cid->rawdata[cid->pos++] = b;
+                                       break;
+                               case 8: /* Retrieve message */
+                                       cid->rawdata[cid->pos++] = b;
+                                       cid->len--;
+                                       if (cid->len<=0) {
+                                               cid->rawdata[cid->pos] = '\0';
+                                               cid->sawflag = 9;
+                                       }
+                                       break;
+                               case 9: /* ETX */
+                                       cid->sawflag = 10;
+                                       break;
+                               case 10: /* CRC Checksum 1 */
+                                       cid->sawflag = 11;
+                                       break;
+                               case 11: /* CRC Checksum 2 */
+                                       cid->sawflag = 12;
+                                       if ( cid->crc != 0 ) {
+                                               ast_log(LOG_WARNING, "crc checksum error\n" ) ;
+                                               return -1;
+                                       } 
+                                       /* extract caller id data */
+                                       for (x=0; x<cid->pos; ) {
+                                               switch (cid->rawdata[x++]) {
+                                                       case 0x02: /* caller id  number */
+                                                               cid->number[0] = '\0';
+                                                               cid->name[0] = '\0';
+                                                               cid->flags = 0;
+                                                               res = cid->rawdata[x++];
+                                                               ast_copy_string(cid->number, &cid->rawdata[x], res+1 );
+                                x += res;
+                                                               break;
+                                                       case 0x21: /* additional information */
+                                                               /* length */
+                                x++; 
+                                                               /* number type */
+                                       switch (cid->rawdata[x]) { 
+                                                                       case 0x00: /* unknown */
+                                                                       case 0x01: /* international number */
+                                                                       case 0x02: /* domestic number */
+                                                                       case 0x03: /* network */
+                                                                       case 0x04: /* local call */
+                                                                       case 0x06: /* short dial number */
+                                                                       case 0x07: /* reserved */
+                                                                       default:   /* reserved */
+                                                                               ast_log(LOG_NOTICE, "cid info:#1=%X\n", cid->rawdata[x]);
+                                                                               break ;
+                                                               }
+                                x++; 
+                                                               /* numbering plan octed 4 */
+                                x++; 
+                                                               /* numbering plan octed 5 */
+                                       switch (cid->rawdata[x]) { 
+                                                                       case 0x00: /* unknown */
+                                                                       case 0x01: /* recommendation E.164 ISDN */
+                                                                       case 0x03: /* recommendation X.121 */
+                                                                       case 0x04: /* telex dial plan */
+                                                                       case 0x08: /* domestic dial plan */
+                                                                       case 0x09: /* private dial plan */
+                                                                       case 0x05: /* reserved */
+                                                                       default:   /* reserved */
+                                                                               ast_log(LOG_NOTICE, "cid info:#2=%X\n", cid->rawdata[x]);
+                                                                               break ;
+                                                               }
+                                x++; 
+                                                               break ;
+                                                       case 0x04: /* no callerid reason */
+                                                               /* length */
+                                x++; 
+                                                               /* no callerid reason code */
+                               switch (cid->rawdata[x]) {
+                                                                       case 'P': /* caller id denied by user */
+                                                                       case 'O': /* service not available */
+                                                                       case 'C': /* pay phone */
+                                                                       case 'S': /* service congested */
+                                                       cid->flags |= CID_UNKNOWN_NUMBER;
+                                                                               ast_log(LOG_NOTICE, "no cid reason:%c\n",cid->rawdata[x]);
+                                                                               break ;
+                                                               }
+                                x++; 
+                                                               break ;
+                                                       case 0x09: /* dialed number */
+                                                               /* length */
+                                                               res = cid->rawdata[x++];
+                                                               /* dialed number */
+                                                               x += res;
+                                                               break ;
+                                                       case 0x22: /* dialed number additional information */
+                                /* length */
+                                x++;
+                                /* number type */
+                                switch (cid->rawdata[x]) {
+                                    case 0x00: /* unknown */
+                                    case 0x01: /* international number */
+                                    case 0x02: /* domestic number */
+                                    case 0x03: /* network */
+                                    case 0x04: /* local call */
+                                    case 0x06: /* short dial number */
+                                    case 0x07: /* reserved */
+                                    default:   /* reserved */
+                                        ast_log(LOG_NOTICE, "did info:#1=%X\n", cid->rawdata[x]);
+                                        break ;
+                                }
+                                x++;
+                                /* numbering plan octed 4 */
+                                x++;
+                                /* numbering plan octed 5 */
+                                switch (cid->rawdata[x]) {
+                                    case 0x00: /* unknown */
+                                    case 0x01: /* recommendation E.164 ISDN */
+                                    case 0x03: /* recommendation X.121 */
+                                    case 0x04: /* telex dial plan */
+                                    case 0x08: /* domestic dial plan */
+                                    case 0x09: /* private dial plan */
+                                    case 0x05: /* reserved */
+                                    default:   /* reserved */
+                                        ast_log(LOG_NOTICE, "did info:#2=%X\n", cid->rawdata[x]);
+                                        break ;
+                                }
+                                x++;
+                                break ;
+                                               }
+                                       }
+                                       return 1;
+                                       break;
+                               default:
+                                       ast_log(LOG_ERROR, "invalid value in sawflag %d\n", cid->sawflag);
+                       }
+               }
+       }
+       if (mylen) {
+               memcpy(cid->oldstuff, buf, mylen * 2);
+               cid->oldlen = mylen * 2;
+       } else
+               cid->oldlen = 0;
+       free(obuf);
+       return 0;
+}
+
+
 int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, int codec)
 {
        int mylen = len;
index 9c52cc5b676733afcaf151737a4952637a2bc622..244ea33ccd9ae6242d8fe3d012571d21263bf57a 100644 (file)
@@ -5266,6 +5266,7 @@ static void *ss_thread(void *data)
        int len = 0;
        int res;
        int index;
+
        if (option_verbose > 2) 
                ast_verbose( VERBOSE_PREFIX_3 "Starting simple switch on '%s'\n", chan->name);
        index = zt_get_index(chan, p, 1);
@@ -5947,8 +5948,9 @@ lax);
                                else
                                        number = 0;
                        /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
-                       } else if (p->cid_signalling == CID_SIG_V23) {
-                               cs = callerid_new(cid_signalling);
+                       } else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
+
+                               cs = callerid_new(p->cid_signalling);
                                if (cs) {
                                        samples = 0;
 #if 1
@@ -5969,8 +5971,16 @@ lax);
                                                if (i & ZT_IOMUX_SIGEVENT) {
                                                        res = zt_get_event(p->subs[index].zfd);
                                                        ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
-                                                       res = 0;
-                                                       break;
+
+                                                       if (p->cid_signalling == CID_SIG_V23_JP) {
+                                                               if (res == ZT_EVENT_RINGBEGIN) {
+                                                                       res = zt_set_hook(p->subs[SUB_REAL].zfd, ZT_OFFHOOK);
+                                                                       usleep(1);
+                                                               }
+                                                       } else {
+                                                               res = 0;
+                                                               break;
+                                                       }
                                                } else if (i & ZT_IOMUX_READ) {
                                                        res = read(p->subs[index].zfd, buf, sizeof(buf));
                                                        if (res < 0) {
@@ -5983,7 +5993,13 @@ lax);
                                                                break;
                                                        }
                                                        samples += res;
-                                                       res = callerid_feed(cs, buf, res, AST_LAW(p));
+
+                                                       if  (p->cid_signalling == CID_SIG_V23_JP) {
+                                                               res = callerid_feed_jp(cs, buf, res, AST_LAW(p));
+                                                       } else {
+                                                               res = callerid_feed(cs, buf, res, AST_LAW(p));
+                                                       }
+
                                                        if (res < 0) {
                                                                ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
                                                                break;
@@ -5995,15 +6011,22 @@ lax);
                                        }
                                        if (res == 1) {
                                                callerid_get(cs, &name, &number, &flags);
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
+                                               ast_log(LOG_NOTICE, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
                                        }
                                        if (res < 0) {
                                                ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", chan->name);
                                        }
 
-                                       /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */ 
-                                       res = 2000;
+                                       if (p->cid_signalling == CID_SIG_V23_JP) {
+                                               res = zt_set_hook(p->subs[SUB_REAL].zfd, ZT_ONHOOK);
+                                               usleep(1);
+                                               res = 4000;
+                                       } else {
+
+                                               /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */ 
+                                               res = 2000;
+                                       }
+
                                        for (;;) {
                                                struct ast_frame *f;
                                                res = ast_waitfor(chan, res);
@@ -10414,6 +10437,8 @@ static int setup_zap(int reload)
                                cid_signalling = CID_SIG_V23;
                        else if (!strcasecmp(v->value, "dtmf"))
                                cid_signalling = CID_SIG_DTMF;
+                       else if (!strcasecmp(v->value, "v23_jp"))
+                               cid_signalling = CID_SIG_V23_JP;
                        else if (ast_true(v->value))
                                cid_signalling = CID_SIG_BELL;
                } else if (!strcasecmp(v->name, "cidstart")) {
index 72f5f4276cb4d82bdbf453d2e7b826c5fa1f3d0c..7daa1a8f9f0ae5f17e5155c99b61cc828c43d9a7 100644 (file)
@@ -41,6 +41,7 @@
 #define CID_SIG_BELL   1
 #define CID_SIG_V23    2
 #define CID_SIG_DTMF   3
+#define CID_SIG_V23_JP 4
 
 #define CID_START_RING 1
 #define CID_START_POLARITY 2
@@ -92,6 +93,18 @@ extern struct callerid_state *callerid_new(int cid_signalling);
  */
 extern int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int samples, int codec);
 
+/*! \brief Read samples into the state machine.
+ * \param cid Which state machine to act upon
+ * \param ubuf containing your samples
+ * \param samples number of samples contained within the buffer.
+ * \param codec which codec (AST_FORMAT_ALAW or AST_FORMAT_ULAW)
+ *
+ * Send received audio to the Caller*ID demodulator (for japanese style lines).
+ * \return Returns -1 on error, 0 for "needs more samples", 
+ * and 1 if the CallerID spill reception is complete.
+ */
+extern int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int samples, int codec);
+
 /*! \brief Extract info out of callerID state machine.  Flags are listed above 
  * \param cid Callerid state machine to act upon
  * \param number Pass the address of a pointer-to-char (will contain the phone number)