diff --git a/callerid.c b/callerid.c index d1a29d4ed0e0fbb475f1889b1919d237370da382..0f382fcc9a1edc474565e37449f36b273f855bec 100644 --- a/callerid.c +++ b/callerid.c @@ -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; diff --git a/channels/chan_zap.c b/channels/chan_zap.c index 9c52cc5b676733afcaf151737a4952637a2bc622..244ea33ccd9ae6242d8fe3d012571d21263bf57a 100644 --- a/channels/chan_zap.c +++ b/channels/chan_zap.c @@ -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")) { diff --git a/include/asterisk/callerid.h b/include/asterisk/callerid.h index 72f5f4276cb4d82bdbf453d2e7b826c5fa1f3d0c..7daa1a8f9f0ae5f17e5155c99b61cc828c43d9a7 100644 --- a/include/asterisk/callerid.h +++ b/include/asterisk/callerid.h @@ -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)