diff --git a/src/mod/applications/mod_fsk/Makefile b/src/mod/applications/mod_fsk/Makefile new file mode 100644 index 0000000000..620f3f751c --- /dev/null +++ b/src/mod/applications/mod_fsk/Makefile @@ -0,0 +1,6 @@ +BASE=../../../.. + +LOCAL_SOURCES=fsk.c uart.c fsk_callerid.c +LOCAL_OBJS=fsk.o uart.o fsk_callerid.o +include $(BASE)/build/modmake.rules + diff --git a/src/mod/applications/mod_fsk/fsk.c b/src/mod/applications/mod_fsk/fsk.c new file mode 100644 index 0000000000..773b0deaae --- /dev/null +++ b/src/mod/applications/mod_fsk/fsk.c @@ -0,0 +1,351 @@ + +/* + * bell202.c + * + * Copyright (c) 2005 Robert Krten. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This module contains a Bell-202 1200-baud FSK decoder, suitable for + * use in a library. The general style of the library calls is modeled + * after the POSIX pthread_*() functions. + * + * 2005 03 20 R. Krten created +*/ + +#include +#include +#include +#include +#include + +#include "fsk.h" +#include "uart.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +fsk_modem_definition_t fsk_modem_definitions[] = +{ + { /* FSK_V23_FORWARD_MODE1 */ 1700, 1300, 600 }, + { /* FSK_V23_FORWARD_MODE2 */ 2100, 1300, 1200 }, + { /* FSK_V23_BACKWARD */ 450, 390, 75 }, + { /* FSK_BELL202 */ 2200, 1200, 1200 }, +}; + +/* + * dsp_fsk_attr_init + * + * Initializes the attributes structure; this must be done before the + * attributes structure is used. +*/ + +void dsp_fsk_attr_init (dsp_fsk_attr_t *attr) +{ + memset(attr, 0, sizeof(*attr)); +} + +/* + * dsp_fsk_attr_get_bithandler + * dsp_fsk_attr_set_bithandler + * dsp_fsk_attr_get_bytehandler + * dsp_fsk_attr_set_bytehandler + * dsp_fsk_attr_getsamplerate + * dsp_fsk_attr_setsamplerate + * + * These functions get and set their respective elements from the + * attributes structure. If an error code is returned, it is just + * zero == ok, -1 == fail. +*/ + +bithandler_func_t dsp_fsk_attr_get_bithandler(dsp_fsk_attr_t *attr, void **bithandler_arg) +{ + *bithandler_arg = attr->bithandler_arg; + return attr->bithandler; +} + +void dsp_fsk_attr_set_bithandler(dsp_fsk_attr_t *attr, bithandler_func_t bithandler, void *bithandler_arg) +{ + attr->bithandler = bithandler; + attr->bithandler_arg = bithandler_arg; +} + +bytehandler_func_t dsp_fsk_attr_get_bytehandler(dsp_fsk_attr_t *attr, void **bytehandler_arg) +{ + *bytehandler_arg = attr->bytehandler_arg; + return attr->bytehandler; +} + +void dsp_fsk_attr_set_bytehandler(dsp_fsk_attr_t *attr, bytehandler_func_t bytehandler, void *bytehandler_arg) +{ + attr->bytehandler = bytehandler; + attr->bytehandler_arg = bytehandler_arg; +} + +int dsp_fsk_attr_get_samplerate (dsp_fsk_attr_t *attr) +{ + return attr->sample_rate; +} + +int dsp_fsk_attr_set_samplerate (dsp_fsk_attr_t *attr, int samplerate) +{ + if (samplerate <= 0) { + return -1; + } + attr->sample_rate = samplerate; + return 0; +} + +/* + * dsp_fsk_create + * + * Creates a handle for subsequent use. The handle is created to contain + * a context data structure for use by the sample handler function. The + * function expects an initialized attributes structure, and returns the + * handle or a NULL if there were errors. + * + * Once created, the handle can be used until it is destroyed. +*/ + +dsp_fsk_handle_t *dsp_fsk_create(dsp_fsk_attr_t *attr) +{ + int i; + double phi_mark, phi_space; + dsp_fsk_handle_t *handle; + + handle = malloc(sizeof(*handle)); + if (!handle) { + return NULL; + } + + memset(handle, 0, sizeof(*handle)); + + /* fill the attributes member */ + memcpy(&handle->attr, attr, sizeof(*attr)); + + /* see if we can do downsampling. We only really need 6 samples to "match" */ + if (attr->sample_rate / fsk_modem_definitions[FSK_BELL202].freq_mark > 6) { + handle->downsampling_count = attr->sample_rate / fsk_modem_definitions[FSK_BELL202].freq_mark / 6; + } else { + handle->downsampling_count = 1; + } + handle->current_downsample = 1; + + /* calculate the correlate size (number of samples required for slowest wave) */ + handle->corrsize = attr->sample_rate / handle->downsampling_count / fsk_modem_definitions[FSK_BELL202].freq_mark; + + /* allocate the correlation sin/cos arrays and initialize */ + for (i = 0; i < 4; i++) { + handle->correlates[i] = malloc(sizeof(double) * handle->corrsize); + if (handle->correlates[i] == NULL) { + /* some failed, back out memory allocations */ + dsp_fsk_destroy(&handle); + return NULL; + } + } + + /* now initialize them */ + phi_mark = 2. * M_PI / ((double) attr->sample_rate / (double) handle->downsampling_count / (double) fsk_modem_definitions[FSK_BELL202].freq_mark); + phi_space = 2. * M_PI / ((double) attr->sample_rate / (double) handle->downsampling_count / (double) fsk_modem_definitions[FSK_BELL202].freq_space); + + for (i = 0; i < handle->corrsize; i++) { + handle->correlates[0][i] = sin(phi_mark * (double) i); + handle->correlates[1][i] = cos(phi_mark * (double) i); + handle->correlates[2][i] = sin(phi_space * (double) i); + handle->correlates[3][i] = cos(phi_space * (double) i); + } + + /* initialize the ring buffer */ + handle->buffer = malloc(sizeof(double) * handle->corrsize); + if (!handle->buffer) { /* failed; back out memory allocations */ + dsp_fsk_destroy(&handle); + return NULL; + } + memset(handle->buffer, 0, sizeof(double) * handle->corrsize); + handle->ringstart = 0; + + /* initalize intra-cell position */ + handle->cellpos = 0; + handle->celladj = fsk_modem_definitions[FSK_BELL202].baud_rate / (double) attr->sample_rate * (double) handle->downsampling_count; + + /* if they have provided a byte handler, add a UART to the processing chain */ + if (handle->attr.bytehandler) { + dsp_uart_attr_t uart_attr; + dsp_uart_handle_t *uart_handle; + + dsp_uart_attr_init(&uart_attr); + dsp_uart_attr_set_bytehandler(&uart_attr, handle->attr.bytehandler, handle->attr.bytehandler_arg); + uart_handle = dsp_uart_create(&uart_attr); + if (uart_handle == NULL) { + dsp_fsk_destroy(&handle); + return NULL; + } + handle->attr.bithandler = dsp_uart_bit_handler; + handle->attr.bithandler_arg = uart_handle; + } + + return handle; +} + +/* + * dsp_fsk_destroy + * + * Destroys a handle, releasing any associated memory. Sets handle pointer to NULL + * so A destroyed handle can not be used for anything after the destroy. +*/ + +void dsp_fsk_destroy(dsp_fsk_handle_t **handle) +{ + int i; + + /* if empty handle, just return */ + if (*handle == NULL) { + return; + } + + for (i = 0; i < 4; i++) { + if ((*handle)->correlates[i] != NULL) { + free((*handle)->correlates[i]); + (*handle)->correlates[i] = NULL; + } + } + + if ((*handle)->buffer != NULL) { + free((*handle)->buffer); + (*handle)->buffer = NULL; + } + + if ((*handle)->attr.bytehandler) { + dsp_uart_handle_t** dhandle = (void *)(&(*handle)->attr.bithandler_arg); + dsp_uart_destroy(dhandle); + } + + free(*handle); + *handle = NULL; +} + +/* + * dsp_fsk_sample + * + * This is the main processing entry point. The function accepts a normalized + * sample (i.e., one whose range is between -1 and +1). The function performs + * the Bell-202 FSK modem decode processing, and, if it detects a valid bit, + * will call the bithandler associated with the attributes structure. + * + * For the Bell-202 standard, a logical zero (space) is 2200 Hz, and a logical + * one (mark) is 1200 Hz. +*/ + +void +dsp_fsk_sample (dsp_fsk_handle_t *handle, double normalized_sample) +{ + double val; + double factors[4]; + int i, j; + + /* if we can avoid processing samples, do so */ + if (handle->downsampling_count != 1) { + if (handle->current_downsample < handle->downsampling_count) { + handle->current_downsample++; + return; /* throw this sample out */ + } + handle->current_downsample = 1; + } + + /* store sample in buffer */ + handle->buffer[handle->ringstart++] = normalized_sample; + if (handle->ringstart >= handle->corrsize) { + handle->ringstart = 0; + } + + /* do the correlation calculation */ + factors[0] = factors[1] = factors[2] = factors[3] = 0; /* clear out intermediate sums */ + j = handle->ringstart; + for (i = 0; i < handle->corrsize; i++) { + if (j >= handle->corrsize) { + j = 0; + } + val = handle->buffer[j]; + factors[0] += handle->correlates[0][i] * val; + factors[1] += handle->correlates[1][i] * val; + factors[2] += handle->correlates[2][i] * val; + factors[3] += handle->correlates[3][i] * val; + j++; + } + + /* store the bit (bit value is comparison of the two sets of correlate factors) */ + handle->previous_bit = handle->current_bit; + handle->current_bit = (factors[0] * factors[0] + factors[1] * factors[1] > factors[2] * factors[2] + factors[3] * factors[3]); + + /* if there's a transition, we can synchronize the cell position */ + if (handle->previous_bit != handle->current_bit) { + handle->cellpos = 0.5; /* adjust cell position to be in the middle of the cell */ + } + handle->cellpos += handle->celladj; /* walk the cell along */ + + if (handle->cellpos > 1.0) { + handle->cellpos -= 1.0; + + switch (handle->state) { + case FSK_STATE_DATA: + { + + (*handle->attr.bithandler) (handle->attr.bithandler_arg, handle->current_bit); + } + break; + case FSK_STATE_CHANSEIZE: + { + + if (handle->last_bit != handle->current_bit) { + handle->conscutive_state_bits++; + } else { + handle->conscutive_state_bits = 0; + } + + if (handle->conscutive_state_bits > 15) { + handle->state = FSK_STATE_CARRIERSIG; + handle->conscutive_state_bits = 0; + } + } + break; + case FSK_STATE_CARRIERSIG: + { + if (handle->current_bit) { + handle->conscutive_state_bits++; + } else { + handle->conscutive_state_bits = 0; + } + + if (handle->conscutive_state_bits > 15) { + handle->state = FSK_STATE_DATA; + handle->conscutive_state_bits = 0; + } + } + break; + } + + handle->last_bit = handle->current_bit; + } +} + diff --git a/src/mod/applications/mod_fsk/fsk.h b/src/mod/applications/mod_fsk/fsk.h new file mode 100644 index 0000000000..b098444d03 --- /dev/null +++ b/src/mod/applications/mod_fsk/fsk.h @@ -0,0 +1,113 @@ +/* + * bell202.h + * + * Copyright (c) 2005 Robert Krten. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This module contains the manifest constants and declarations for + * the Bell-202 1200 baud FSK modem. + * + * 2005 03 20 R. Krten created +*/ + +#ifndef __FSK_H__ +#define __FSK_H__ +#include "uart.h" + +typedef struct { + int freq_space; /* Frequency of the 0 bit */ + int freq_mark; /* Frequency of the 1 bit */ + int baud_rate; /* baud rate for the modem */ +} fsk_modem_definition_t; + +/* Must be kept in sync with fsk_modem_definitions array in fsk.c */ +/* V.23 definitions: http://www.itu.int/rec/recommendation.asp?type=folders&lang=e&parent=T-REC-V.23 */ +typedef enum { + FSK_V23_FORWARD_MODE1 = 0, /* Maximum 600 bps for long haul */ + FSK_V23_FORWARD_MODE2, /* Standard 1200 bps V.23 */ + FSK_V23_BACKWARD, /* 75 bps return path for V.23 */ + FSK_BELL202 /* Bell 202 half-duplex 1200 bps */ +} fsk_modem_types_t; + +typedef enum { + FSK_STATE_CHANSEIZE = 0, + FSK_STATE_CARRIERSIG, + FSK_STATE_DATA +} fsk_state_t; + +typedef struct dsp_fsk_attr_s +{ + int sample_rate; /* sample rate in HZ */ + bithandler_func_t bithandler; /* bit handler */ + void *bithandler_arg; /* arbitrary ID passed to bithandler as first argument */ + bytehandler_func_t bytehandler; /* byte handler */ + void *bytehandler_arg; /* arbitrary ID passed to bytehandler as first argument */ +} dsp_fsk_attr_t; + +typedef struct +{ + fsk_state_t state; + dsp_fsk_attr_t attr; /* attributes structure */ + double *correlates[4]; /* one for each of sin/cos for mark/space */ + int corrsize; /* correlate size (also number of samples in ring buffer) */ + double *buffer; /* sample ring buffer */ + int ringstart; /* ring buffer start offset */ + double cellpos; /* bit cell position */ + double celladj; /* bit cell adjustment for each sample */ + int previous_bit; /* previous bit (for detecting a transition to sync-up cell position) */ + int current_bit; /* current bit */ + int last_bit; + int downsampling_count; /* number of samples to skip */ + int current_downsample; /* current skip count */ + int conscutive_state_bits; /* number of bits in a row that matches the pattern for the current state */ +} dsp_fsk_handle_t; + +/* + * Function prototypes + * + * General calling order is: + * a) create the attributes structure (dsp_fsk_attr_init) + * b) initialize fields in the attributes structure (dsp_fsk_attr_set_*) + * c) create a Bell-202 handle (dsp_fsk_create) + * d) feed samples through the handler (dsp_fsk_sample) +*/ + +void dsp_fsk_attr_init(dsp_fsk_attr_t *attributes); + +bithandler_func_t dsp_fsk_attr_get_bithandler(dsp_fsk_attr_t *attributes, void **bithandler_arg); +void dsp_fsk_attr_set_bithandler(dsp_fsk_attr_t *attributes, bithandler_func_t bithandler, void *bithandler_arg); +bytehandler_func_t dsp_fsk_attr_get_bytehandler(dsp_fsk_attr_t *attributes, void **bytehandler_arg); +void dsp_fsk_attr_set_bytehandler(dsp_fsk_attr_t *attributes, bytehandler_func_t bytehandler, void *bytehandler_arg); +int dsp_fsk_attr_get_samplerate(dsp_fsk_attr_t *attributes); +int dsp_fsk_attr_set_samplerate(dsp_fsk_attr_t *attributes, int samplerate); + +dsp_fsk_handle_t * dsp_fsk_create(dsp_fsk_attr_t *attributes); +void dsp_fsk_destroy(dsp_fsk_handle_t **handle); + +void dsp_fsk_sample(dsp_fsk_handle_t *handle, double normalized_sample); + +extern fsk_modem_definition_t fsk_modem_definitions[]; + +#endif + diff --git a/src/mod/applications/mod_fsk/fsk_callerid.c b/src/mod/applications/mod_fsk/fsk_callerid.c new file mode 100644 index 0000000000..2146f663c5 --- /dev/null +++ b/src/mod/applications/mod_fsk/fsk_callerid.c @@ -0,0 +1,398 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2011, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * + * mod_fsk -- FSK data transfer + * + */ + +#include "switch.h" +#include "fsk_callerid.h" + +void bitstream_init(bitstream_t *bsp, uint8_t *data, uint32_t datalen, endian_t endian, uint8_t ss) +{ + memset(bsp, 0, sizeof(*bsp)); + bsp->data = data; + bsp->datalen = datalen; + bsp->endian = endian; + bsp->ss = ss; + + if (endian < 0) { + bsp->top = bsp->bit_index = 7; + bsp->bot = 0; + } else { + bsp->top = bsp->bit_index = 0; + bsp->bot = 7; + } + +} + +int8_t bitstream_get_bit(bitstream_t *bsp) +{ + int8_t bit = -1; + + + if (bsp->byte_index >= bsp->datalen) { + goto done; + } + + if (bsp->ss) { + if (!bsp->ssv) { + bsp->ssv = 1; + return 0; + } else if (bsp->ssv == 2) { + bsp->byte_index++; + bsp->ssv = 0; + return 1; + } + } + + bit = (bsp->data[bsp->byte_index] >> (bsp->bit_index)) & 1; + + if (bsp->bit_index == bsp->bot) { + bsp->bit_index = bsp->top; + if (bsp->ss) { + bsp->ssv = 2; + goto done; + } + + if (++bsp->byte_index > bsp->datalen) { + bit = -1; + goto done; + } + + } else { + bsp->bit_index = bsp->bit_index + bsp->endian; + } + + + done: + return bit; +} + + + +static void fsk_byte_handler (void *x, int data) +{ + fsk_data_state_t *state = (fsk_data_state_t *) x; + uint8_t byte = (uint8_t)data; + + top: + + if (state->init == 3) { + return; + } + + if (state->dlen) { + goto add_byte; + } + + if (state->bpos == 1) { + state->blen = byte; + + if ((uint32_t)(state->dlen = state->bpos + byte + 2) > state->bufsize) { + state->dlen = state->bufsize; + } + goto top; + } + + add_byte: + + if (state->bpos <= state->dlen) { + state->buf[state->bpos++] = byte; + } else { + state->init = 3; + } +} + +switch_status_t fsk_data_init(fsk_data_state_t *state, uint8_t *data, uint32_t datalen) +{ + memset(state, 0, sizeof(*state)); + state->buf = data; + state->bufsize = datalen; + state->bpos = 2; + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t fsk_data_add_sdmf(fsk_data_state_t *state, const char *date, char *number) +{ + size_t dlen = strlen(date); + size_t nlen = strlen(number); + + state->buf[0] = CID_TYPE_SDMF; + memcpy(&state->buf[state->bpos], date, dlen); + state->bpos += dlen; + memcpy(&state->buf[state->bpos], number, nlen); + state->bpos += nlen; + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t fsk_data_add_mdmf(fsk_data_state_t *state, mdmf_type_t type, const uint8_t *data, uint32_t datalen) +{ + state->buf[0] = CID_TYPE_MDMF; + state->buf[state->bpos++] = type; + state->buf[state->bpos++] = (uint8_t)datalen; + memcpy(&state->buf[state->bpos], data, datalen); + state->bpos += datalen; + return SWITCH_STATUS_SUCCESS; +} + + +switch_status_t fsk_data_add_checksum(fsk_data_state_t *state) +{ + uint32_t i; + uint8_t check = 0; + + state->buf[1] = (uint8_t)(state->bpos - 2); + + for (i = 0; i < state->bpos; i++) { + check = check + state->buf[i]; + } + + state->checksum = state->buf[state->bpos] = (uint8_t)(256 - check); + state->bpos++; + + state->dlen = state->bpos; + state->blen = state->buf[1]; + + return SWITCH_STATUS_SUCCESS; +} + + +switch_status_t fsk_data_parse(fsk_data_state_t *state, size_t *type, char **data, size_t *len) +{ + + size_t i; + int sum = 0; + + top: + + if (state->checksum != 0 || state->ppos >= state->dlen - 1) { + return SWITCH_STATUS_FALSE; + } + + if (!state->ppos) { + for(i = 0; i < state->bpos; i++) { + sum += state->buf[i]; + } + state->checksum = sum % 256; + state->ppos = 2; + + if (state->buf[0] != CID_TYPE_MDMF && state->buf[0] != CID_TYPE_SDMF) { + state->checksum = -1; + } + goto top; + } + + if (state->buf[0] == CID_TYPE_SDMF) { + /* convert sdmf to mdmf so we don't need 2 parsers */ + if (state->ppos == 2) { + *type = MDMF_DATETIME; + *len = 8; + } else { + if (state->buf[state->ppos] == 'P' || state->buf[state->ppos] == 'O') { + *type = MDMF_NO_NUM; + *len = 1; + } else { + *type = MDMF_PHONE_NUM; + *len = state->blen - 8; + } + } + *data = (char *)&state->buf[state->ppos]; + state->ppos += *len; + return SWITCH_STATUS_SUCCESS; + } else if (state->buf[0] == CID_TYPE_MDMF) { + *type = state->buf[state->ppos++]; + *len = state->buf[state->ppos++]; + *data = (char *)&state->buf[state->ppos]; + state->ppos += *len; + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_FALSE; +} + +switch_status_t fsk_demod_feed(fsk_data_state_t *state, int16_t *data, size_t samples) +{ + uint32_t x; + int16_t *sp = data; + + if (state->init == 3) { + return SWITCH_STATUS_FALSE; + } + + for (x = 0; x < samples; x++) { + dsp_fsk_sample (state->fsk1200_handle, (double) *sp++ / 32767.0); + if (state->dlen && state->bpos >= state->dlen) { + state->init = 3; + return SWITCH_STATUS_FALSE; + } + } + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t fsk_demod_destroy(fsk_data_state_t *state) +{ + dsp_fsk_destroy(&state->fsk1200_handle); + memset(state, 0, sizeof(*state)); + return SWITCH_STATUS_SUCCESS; +} + +int fsk_demod_init(fsk_data_state_t *state, int rate, uint8_t *buf, size_t bufsize) +{ + + dsp_fsk_attr_t fsk1200_attr; + + if (state->fsk1200_handle) { + dsp_fsk_destroy(&state->fsk1200_handle); + } + + memset(state, 0, sizeof(*state)); + memset(buf, 0, bufsize); + state->buf = buf; + state->bufsize = bufsize; + + dsp_fsk_attr_init (&fsk1200_attr); + dsp_fsk_attr_set_samplerate (&fsk1200_attr, rate); + dsp_fsk_attr_set_bytehandler (&fsk1200_attr, fsk_byte_handler, state); + state->fsk1200_handle = dsp_fsk_create (&fsk1200_attr); + + if (state->fsk1200_handle == NULL) { + return SWITCH_STATUS_FALSE; + } + + return SWITCH_STATUS_SUCCESS; +} + +size_t fsk_modulator_generate_bit(fsk_modulator_t *fsk_trans, int8_t bit, int16_t *buf, size_t buflen) +{ + size_t i; + + for(i = 0 ; i < buflen; i++) { + fsk_trans->bit_accum += fsk_trans->bit_factor; + if (fsk_trans->bit_accum >= FSK_MOD_FACTOR) { + fsk_trans->bit_accum -= (FSK_MOD_FACTOR + fsk_trans->bit_factor); + break; + } + + buf[i] = teletone_dds_state_modulate_sample(&fsk_trans->dds, bit); + } + + return i; +} + + +int32_t fsk_modulator_generate_carrier_bits(fsk_modulator_t *fsk_trans, uint32_t bits) +{ + uint32_t i = 0; + size_t r = 0; + int8_t bit = 1; + + for (i = 0; i < bits; i++) { + if ((r = fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) { + if (fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data) != SWITCH_STATUS_SUCCESS) { + break; + } + } else { + break; + } + } + + return i; +} + + +void fsk_modulator_generate_chan_sieze(fsk_modulator_t *fsk_trans) +{ + uint32_t i = 0; + size_t r = 0; + int8_t bit = 0; + + for (i = 0; i < fsk_trans->chan_sieze_bits; i++) { + if ((r = fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) { + if (fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data) != SWITCH_STATUS_SUCCESS) { + break; + } + } else { + break; + } + bit = !bit; + } + + +} + + +void fsk_modulator_send_data(fsk_modulator_t *fsk_trans) +{ + size_t r = 0; + int8_t bit = 0; + + while((bit = bitstream_get_bit(&fsk_trans->bs)) > -1) { + if ((r = fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) { + if (fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data) != SWITCH_STATUS_SUCCESS) { + break; + } + } else { + break; + } + } +} + + +switch_status_t fsk_modulator_init(fsk_modulator_t *fsk_trans, + fsk_modem_types_t modem_type, + uint32_t sample_rate, + fsk_data_state_t *fsk_data, + float db_level, + uint32_t carrier_bits_start, + uint32_t carrier_bits_stop, + uint32_t chan_sieze_bits, + fsk_write_sample_t write_sample_callback, + void *user_data) +{ + memset(fsk_trans, 0, sizeof(*fsk_trans)); + fsk_trans->modem_type = modem_type; + teletone_dds_state_set_tone(&fsk_trans->dds, fsk_modem_definitions[fsk_trans->modem_type].freq_space, sample_rate, 0); + teletone_dds_state_set_tone(&fsk_trans->dds, fsk_modem_definitions[fsk_trans->modem_type].freq_mark, sample_rate, 1); + fsk_trans->bit_factor = (uint32_t)((fsk_modem_definitions[fsk_trans->modem_type].baud_rate * FSK_MOD_FACTOR) / (float)sample_rate); + fsk_trans->samples_per_bit = (uint32_t) (sample_rate / fsk_modem_definitions[fsk_trans->modem_type].baud_rate); + fsk_trans->est_bytes = (int32_t)(((fsk_data->dlen * 10) + carrier_bits_start + carrier_bits_stop + chan_sieze_bits) * ((fsk_trans->samples_per_bit + 1) * 2)); + fsk_trans->bit_accum = 0; + fsk_trans->fsk_data = fsk_data; + teletone_dds_state_set_tx_level(&fsk_trans->dds, db_level); + bitstream_init(&fsk_trans->bs, fsk_trans->fsk_data->buf, (uint32_t)fsk_trans->fsk_data->dlen, ENDIAN_BIG, 1); + fsk_trans->carrier_bits_start = carrier_bits_start; + fsk_trans->carrier_bits_stop = carrier_bits_stop; + fsk_trans->chan_sieze_bits = chan_sieze_bits; + fsk_trans->write_sample_callback = write_sample_callback; + fsk_trans->user_data = user_data; + return SWITCH_STATUS_SUCCESS; +} + diff --git a/src/mod/applications/mod_fsk/fsk_callerid.h b/src/mod/applications/mod_fsk/fsk_callerid.h new file mode 100644 index 0000000000..9018201ce5 --- /dev/null +++ b/src/mod/applications/mod_fsk/fsk_callerid.h @@ -0,0 +1,144 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2011, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * + * mod_fsk -- FSK data transfer + * + */ +#ifndef __FSK_CALLER_ID_H +#define __FSK_CALLER_ID_H +SWITCH_BEGIN_EXTERN_C +#include "fsk.h" +#include "uart.h" + +#define FSK_MOD_FACTOR 0x10000 + +typedef enum { + ENDIAN_BIG = 1, + ENDIAN_LITTLE = -1 +} endian_t; + +typedef enum { + CID_TYPE_SDMF = 0x04, + CID_TYPE_MDMF = 0x80 +} cid_type_t; + +typedef enum { + MDMF_DATETIME = 1, + MDMF_PHONE_NUM = 2, + MDMF_DDN = 3, + MDMF_NO_NUM = 4, + MDMF_PHONE_NAME = 7, + MDMF_NO_NAME = 8, + MDMF_ALT_ROUTE = 9, + MDMF_NAME_VALUE = 10, + MDMF_INVALID = 11 +} mdmf_type_t; + +struct bitstream { + uint8_t *data; + uint32_t datalen; + uint32_t byte_index; + uint8_t bit_index; + int8_t endian; + uint8_t top; + uint8_t bot; + uint8_t ss; + uint8_t ssv; +}; + +struct fsk_data_state { + dsp_fsk_handle_t *fsk1200_handle; + uint8_t init; + uint8_t *buf; + size_t bufsize; + size_t blen; + size_t bpos; + size_t dlen; + size_t ppos; + int checksum; +}; + +typedef struct bitstream bitstream_t; +typedef struct fsk_data_state fsk_data_state_t; +typedef switch_status_t (*fsk_write_sample_t)(int16_t *buf, size_t buflen, void *user_data); + +struct fsk_modulator { + teletone_dds_state_t dds; + bitstream_t bs; + uint32_t carrier_bits_start; + uint32_t carrier_bits_stop; + uint32_t chan_sieze_bits; + uint32_t bit_factor; + uint32_t bit_accum; + uint32_t sample_counter; + int32_t samples_per_bit; + int32_t est_bytes; + fsk_modem_types_t modem_type; + fsk_data_state_t *fsk_data; + fsk_write_sample_t write_sample_callback; + void *user_data; + int16_t sample_buffer[64]; +}; + + +typedef int (*fsk_data_decoder_t)(fsk_data_state_t *state); + +typedef void (*logger_t)(const char *file, const char *func, int line, int level, const char *fmt, ...); +typedef struct fsk_modulator fsk_modulator_t; + +switch_status_t fsk_data_init(fsk_data_state_t *state, uint8_t *data, uint32_t datalen); +void bitstream_init(bitstream_t *bsp, uint8_t *data, uint32_t datalen, endian_t endian, uint8_t ss); +int8_t bitstream_get_bit(bitstream_t *bsp); +switch_status_t fsk_data_add_mdmf(fsk_data_state_t *state, mdmf_type_t type, const uint8_t *data, uint32_t datalen); +switch_status_t fsk_data_add_checksum(fsk_data_state_t *state); +switch_status_t fsk_data_parse(fsk_data_state_t *state, size_t *type, char **data, size_t *len); +switch_status_t fsk_demod_feed(fsk_data_state_t *state, int16_t *data, size_t samples); +switch_status_t fsk_demod_destroy(fsk_data_state_t *state); +int fsk_demod_init(fsk_data_state_t *state, int rate, uint8_t *buf, size_t bufsize); +size_t fsk_modulator_generate_bit(fsk_modulator_t *fsk_trans, int8_t bit, int16_t *buf, size_t buflen); +int32_t fsk_modulator_generate_carrier_bits(fsk_modulator_t *fsk_trans, uint32_t bits); +void fsk_modulator_generate_chan_sieze(fsk_modulator_t *fsk_trans); +void fsk_modulator_send_data(fsk_modulator_t *fsk_trans); +switch_status_t fsk_modulator_init(fsk_modulator_t *fsk_trans, + fsk_modem_types_t modem_type, + uint32_t sample_rate, + fsk_data_state_t *fsk_data, + float db_level, + uint32_t carrier_bits_start, + uint32_t carrier_bits_stop, + uint32_t chan_sieze_bits, + fsk_write_sample_t write_sample_callback, + void *user_data); + + +#define fsk_modulator_send_all(_it) fsk_modulator_generate_chan_sieze(_it); \ + fsk_modulator_generate_carrier_bits(_it, _it->carrier_bits_start); \ + fsk_modulator_send_data(_it); \ + fsk_modulator_generate_carrier_bits(_it, _it->carrier_bits_stop) + +SWITCH_END_EXTERN_C +#endif diff --git a/src/mod/applications/mod_fsk/mod_fsk.c b/src/mod/applications/mod_fsk/mod_fsk.c new file mode 100644 index 0000000000..9802353075 --- /dev/null +++ b/src/mod/applications/mod_fsk/mod_fsk.c @@ -0,0 +1,486 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2011, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * + * mod_fsk.c -- FSK data transfer + * + */ +#include +#include "fsk_callerid.h" + +/* Prototypes */ +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_fsk_shutdown); +SWITCH_MODULE_RUNTIME_FUNCTION(mod_fsk_runtime); +SWITCH_MODULE_LOAD_FUNCTION(mod_fsk_load); + +/* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime) + * Defines a switch_loadable_module_function_table_t and a static const char[] modname + */ +SWITCH_MODULE_DEFINITION(mod_fsk, mod_fsk_load, mod_fsk_shutdown, NULL); + +switch_status_t my_write_sample(int16_t *buf, size_t buflen, void *user_data) +{ + switch_buffer_t *buffer = (switch_buffer_t *) user_data; + + switch_buffer_write(buffer, buf, buflen * 2); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t write_fsk_data(uint32_t rate, int32_t db, switch_buffer_t *buffer, switch_event_t *event, const char *prefix) +{ + fsk_modulator_t fsk_trans; + fsk_data_state_t fsk_data = {0}; + uint8_t databuf[1024] = ""; + char time_str[9]; + struct tm tm; + time_t now; + switch_event_header_t *hp; + switch_size_t plen = 0; + + memset(&fsk_trans, 0, sizeof(fsk_trans)); + + time(&now); + localtime_r(&now, &tm); + strftime(time_str, sizeof(time_str), "%m%d%H%M", &tm); + + fsk_data_init(&fsk_data, databuf, sizeof(databuf)); + fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, (uint8_t *)time_str, strlen(time_str)); + + if (prefix) { + plen = strlen(prefix); + } + + + if (event) { + for (hp = event->headers; hp; hp = hp->next) { + char *packed; + char *name = hp->name; + + if (plen && strncasecmp(name, prefix, plen)) { + continue; + } + + name += plen; + + if (zstr(name)) { + continue; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Encoding [%s][%s]\n", hp->name, hp->value); + + if (!strcasecmp(name, "phone_num")) { + fsk_data_add_mdmf(&fsk_data, MDMF_PHONE_NUM, (uint8_t *)hp->value, strlen(hp->value)); + } else if (!strcasecmp(name, "phone_name")) { + fsk_data_add_mdmf(&fsk_data, MDMF_PHONE_NAME, (uint8_t *)hp->value, strlen(hp->value)); + } else { + packed = switch_mprintf("%q:%q", name, hp->value); + fsk_data_add_mdmf(&fsk_data, MDMF_NAME_VALUE, (uint8_t *)packed, strlen(packed)); + free(packed); + } + } + } + + fsk_data_add_checksum(&fsk_data); + + fsk_modulator_init(&fsk_trans, FSK_BELL202, rate, &fsk_data, db, 180, 5, 300, my_write_sample, buffer); + fsk_modulator_send_all((&fsk_trans)); + + fsk_demod_destroy(&fsk_data); + + return SWITCH_STATUS_SUCCESS; +} + + +SWITCH_STANDARD_APP(fsk_send_function) { + switch_event_t *event = NULL; + switch_buffer_t *buffer; + switch_slin_data_t sdata = { 0 }; + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_frame_t *read_frame; + switch_status_t status; + + + if (data) { + switch_ivr_sleep(session, 1000, SWITCH_TRUE, NULL); + switch_core_session_send_dtmf_string(session, (const char *) data); + switch_ivr_sleep(session, 1500, SWITCH_TRUE, NULL); + } + + if (switch_core_session_set_codec_slin(session, &sdata) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), + SWITCH_LOG_ERROR, "FAILURE\n"); + return; + } + + switch_buffer_create_dynamic(&buffer, 1024, 2048, 0); + + switch_channel_get_variables(channel, &event); + + write_fsk_data(sdata.codec.implementation->actual_samples_per_second, -14, buffer, event, "fsk_"); + + while(switch_channel_ready(channel)) { + status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0); + + if (!SWITCH_READ_ACCEPTABLE(status)) { + break; + } + + if ((sdata.write_frame.datalen = switch_buffer_read(buffer, sdata.write_frame.data, + sdata.codec.implementation->decoded_bytes_per_packet)) <= 0) { + break; + } + + + if (sdata.write_frame.datalen < sdata.codec.implementation->decoded_bytes_per_packet) { + memset((char *)sdata.write_frame.data + sdata.write_frame.datalen, 255, + sdata.codec.implementation->decoded_bytes_per_packet - sdata.write_frame.datalen); + sdata.write_frame.datalen = sdata.codec.implementation->decoded_bytes_per_packet; + } + sdata.write_frame.samples = sdata.write_frame.datalen / 2; + switch_core_session_write_frame(sdata.session, &sdata.write_frame, SWITCH_IO_FLAG_NONE, 0); + } + + switch_buffer_destroy(&buffer); + switch_core_codec_destroy(&sdata.codec); + switch_core_session_set_read_codec(session, NULL); + +} + +typedef struct { + switch_core_session_t *session; + fsk_data_state_t fsk_data; + uint8_t fbuf[512]; + int skip; +} switch_fsk_detect_t; + + + + +static switch_bool_t fsk_detect_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type) +{ + switch_fsk_detect_t *pvt = (switch_fsk_detect_t *) user_data; + //switch_frame_t *frame = NULL; + switch_channel_t *channel = switch_core_session_get_channel(pvt->session); + + switch (type) { + case SWITCH_ABC_TYPE_INIT: { + switch_codec_implementation_t read_impl = { 0 }; + switch_core_session_get_read_impl(pvt->session, &read_impl); + + if (fsk_demod_init(&pvt->fsk_data, read_impl.actual_samples_per_second, pvt->fbuf, sizeof(pvt->fbuf))) { + return SWITCH_FALSE; + } + + break; + } + case SWITCH_ABC_TYPE_CLOSE: + { + fsk_demod_destroy(&pvt->fsk_data); + } + break; + + case SWITCH_ABC_TYPE_WRITE_REPLACE: + case SWITCH_ABC_TYPE_READ_REPLACE: + { + switch_frame_t *rframe; + + if (type == SWITCH_ABC_TYPE_READ_REPLACE) { + rframe = switch_core_media_bug_get_read_replace_frame(bug); + } else { + rframe = switch_core_media_bug_get_write_replace_frame(bug); + } + + if (!pvt->skip && fsk_demod_feed(&pvt->fsk_data, rframe->data, rframe->datalen / 2) != SWITCH_STATUS_SUCCESS) { + char str[1024] = ""; + size_t type, mlen; + char *sp; + switch_event_t *event; + const char *app_var; + + switch_event_create_plain(&event, SWITCH_EVENT_CHANNEL_DATA); + + while(fsk_data_parse(&pvt->fsk_data, &type, &sp, &mlen) == SWITCH_STATUS_SUCCESS) { + char *varname = NULL, *val, *p; + + switch_copy_string(str, sp, mlen+1); + *(str+mlen) = '\0'; + switch_clean_string(str); + //printf("TYPE %u LEN %u VAL [%s]\n", (unsigned)type, (unsigned)mlen, str); + + val = str; + + switch(type) { + case MDMF_DATETIME: + varname = "fsk_datetime"; + break; + case MDMF_PHONE_NAME: + varname = "fsk_phone_name"; + break; + case MDMF_PHONE_NUM: + varname = "fsk_phone_num"; + break; + case MDMF_NAME_VALUE: + varname = switch_core_session_sprintf(pvt->session, "fsk_%s", val); + if ((p = strchr(varname, ':'))) { + *p++ = '\0'; + val = p; + } + break; + default: + break; + } + + if (varname && val) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "%s setting FSK var [%s][%s]\n", + switch_channel_get_name(channel), varname, val); + switch_channel_set_variable(channel, varname, val); + if (event) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, varname, val); + } + } + } + + if (event) { + if (switch_core_session_queue_event(pvt->session, &event) != SWITCH_STATUS_SUCCESS) { + switch_event_destroy(&event); + } + } + + if ((app_var = switch_channel_get_variable(channel, "execute_on_fsk"))) { + char *app_arg; + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "%s processing execute_on_fsk [%s]\n", + switch_channel_get_name(channel), app_var); + if ((app_arg = strchr(app_var, ' '))) { + *app_arg++ = '\0'; + } + switch_core_session_execute_application(pvt->session, app_var, app_arg); + } + + pvt->skip = 10; + } + + memset(rframe->data, 255, rframe->datalen); + + if (type == SWITCH_ABC_TYPE_READ_REPLACE) { + switch_core_media_bug_set_read_replace_frame(bug, rframe); + } else { + switch_core_media_bug_set_write_replace_frame(bug, rframe); + } + + if (pvt->skip && !--pvt->skip) { + return SWITCH_FALSE; + } + + } + break; + case SWITCH_ABC_TYPE_WRITE: + default: + break; + } + + return SWITCH_TRUE; +} + +switch_status_t stop_fsk_detect_session(switch_core_session_t *session) +{ + switch_media_bug_t *bug; + switch_channel_t *channel = switch_core_session_get_channel(session); + + if ((bug = switch_channel_get_private(channel, "fsk"))) { + switch_channel_set_private(channel, "fsk", NULL); + switch_core_media_bug_remove(session, &bug); + return SWITCH_STATUS_SUCCESS; + } + return SWITCH_STATUS_FALSE; +} + +switch_status_t fsk_detect_session(switch_core_session_t *session, const char *flags) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_media_bug_t *bug; + switch_status_t status; + switch_fsk_detect_t *pvt = { 0 }; + switch_codec_implementation_t read_impl = { 0 }; + int bflags = SMBF_READ_REPLACE; + + if (strchr(flags, 'w')) { + bflags = SMBF_WRITE_REPLACE; + } + + switch_core_session_get_read_impl(session, &read_impl); + + if (!(pvt = switch_core_session_alloc(session, sizeof(*pvt)))) { + return SWITCH_STATUS_MEMERR; + } + + pvt->session = session; + + + if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_FALSE; + } + + if ((status = switch_core_media_bug_add(session, "fsk_detect", NULL, + fsk_detect_callback, pvt, 0, bflags | SMBF_NO_PAUSE, &bug)) != SWITCH_STATUS_SUCCESS) { + return status; + } + + switch_channel_set_private(channel, "fsk", bug); + + return SWITCH_STATUS_SUCCESS; +} + + +SWITCH_STANDARD_APP(fsk_recv_function) +{ + fsk_detect_session(session, data); +} + +SWITCH_STANDARD_APP(fsk_display_function) +{ + /* expected to be called via 'execute_on_fsk' -- passes display update over FSK */ + + const char *cid_name, *cid_num; + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_core_session_message_t *msg; + switch_core_session_t *psession, *usession = NULL; + char *flags = (char *) data; + + cid_name = switch_channel_get_variable(channel, "fsk_phone_name"); + cid_num = switch_channel_get_variable(channel, "fsk_phone_num"); + + if (zstr(cid_name)) { + cid_name = cid_num; + } + + if (zstr(cid_num)) { + return; + } + + if (strchr(flags, 'b')) { + if (switch_core_session_get_partner(session, &psession) == SWITCH_STATUS_SUCCESS) { + usession = psession; + } + } + + if (!usession) { + usession = session; + } + + msg = switch_core_session_alloc(usession, sizeof(*msg)); + MESSAGE_STAMP_FFL(msg); + msg->message_id = SWITCH_MESSAGE_INDICATE_DISPLAY; + msg->string_array_arg[0] = switch_core_session_strdup(usession, cid_name); + msg->string_array_arg[1] = switch_core_session_strdup(usession, cid_num); + msg->from = __FILE__; + switch_core_session_queue_message(usession, msg); + + if (psession) { + switch_core_session_rwunlock(psession); + psession = NULL; + } +} + +SWITCH_STANDARD_APP(fsk_simplify_function) +{ + /* expected to be called via 'execute_on_fsk' -- redirects call to point-to-point and eliminates legs in the middle */ + switch_channel_t *channel = switch_core_session_get_channel(session); + const char *sip_uri, *fsk_simplify_profile, *fsk_simplify_context; + char *bridgeto; + + if (!(sip_uri = switch_channel_get_variable(channel, "fsk_uri"))) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s Missing URI field!\n", switch_channel_get_name(channel)); + } + + if (!(fsk_simplify_profile = switch_channel_get_variable(channel, "fsk_simplify_profile"))) { + fsk_simplify_profile = "internal"; + } + + fsk_simplify_context = switch_channel_get_variable(channel, "fsk_simplify_context"); + + if (!zstr(sip_uri)) { + switch_core_session_t *psession; + switch_channel_t *pchannel; + + bridgeto = switch_core_session_sprintf(session, "bridge:sofia/%s/sip:%s", fsk_simplify_profile, sip_uri); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s transfering to [%s]\n", + switch_channel_get_name(channel), bridgeto); + + + if (switch_core_session_get_partner(session, &psession) == SWITCH_STATUS_SUCCESS) { + pchannel = switch_core_session_get_channel(psession); + switch_channel_set_flag(pchannel, CF_REDIRECT); + switch_channel_set_flag(pchannel, CF_TRANSFER); + } + + switch_ivr_session_transfer(session, bridgeto, "inline", fsk_simplify_context); + + if (psession) { + switch_ivr_session_transfer(psession, "sleep:5000", "inline", NULL); + switch_core_session_rwunlock(psession); + } + } +} + +/* Macro expands to: switch_status_t mod_fsk_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */ +SWITCH_MODULE_LOAD_FUNCTION(mod_fsk_load) +{ + switch_application_interface_t *app_interface; + + /* connect my internal structure to the blank pointer passed to me */ + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + + SWITCH_ADD_APP(app_interface, "fsk_send", "fsk_send", NULL, fsk_send_function, NULL, SAF_NONE); + SWITCH_ADD_APP(app_interface, "fsk_recv", "fsk_recv", NULL, fsk_recv_function, NULL, SAF_NONE); + SWITCH_ADD_APP(app_interface, "fsk_simplify", "fsk_simplify", NULL, fsk_simplify_function, NULL, SAF_NONE); + SWITCH_ADD_APP(app_interface, "fsk_display", "fsk_display", NULL, fsk_display_function, NULL, SAF_NONE); + + /* indicate that the module should continue to be loaded */ + return SWITCH_STATUS_SUCCESS; +} + +/* + Called when the system shuts down + Macro expands to: switch_status_t mod_fsk_shutdown() */ +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_fsk_shutdown) +{ + /* Cleanup dynamically allocated config settings */ + + return SWITCH_STATUS_SUCCESS; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 + */ diff --git a/src/mod/applications/mod_fsk/uart.c b/src/mod/applications/mod_fsk/uart.c new file mode 100644 index 0000000000..5e0dd85350 --- /dev/null +++ b/src/mod/applications/mod_fsk/uart.c @@ -0,0 +1,124 @@ + +/* + * uart.c + * + * Copyright (c) 2005 Robert Krten. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This module contains a simple 8-bit UART, which performs a callback + * with the decoded byte value. + * + * 2005 06 11 R. Krten created +*/ + +#include +#include +#include +#include + +#include "uart.h" + +/* + * dsp_uart_attr_init + * + * Initializes the attributes structure; this must be done before the + * attributes structure is used. +*/ + +void dsp_uart_attr_init (dsp_uart_attr_t *attr) +{ + memset (attr, 0, sizeof (*attr)); +} + +/* + * dsp_uart_attr_get_bytehandler + * dsp_uart_attr_set_bytehandler + * + * These functions get and set their respective elements from the + * attributes structure. If an error code is returned, it is just + * zero == ok, -1 == fail. +*/ + +bytehandler_func_t dsp_uart_attr_get_bytehandler(dsp_uart_attr_t *attr, void **bytehandler_arg) +{ + *bytehandler_arg = attr->bytehandler_arg; + return attr->bytehandler; +} + +void dsp_uart_attr_set_bytehandler(dsp_uart_attr_t *attr, bytehandler_func_t bytehandler, void *bytehandler_arg) +{ + attr->bytehandler = bytehandler; + attr->bytehandler_arg = bytehandler_arg; +} + +dsp_uart_handle_t *dsp_uart_create(dsp_uart_attr_t *attr) +{ + dsp_uart_handle_t *handle; + + handle = malloc(sizeof (*handle)); + if (handle) { + memset(handle, 0, sizeof (*handle)); + + /* fill the attributes member */ + memcpy(&handle->attr, attr, sizeof (*attr)); + } + return handle; +} + +void dsp_uart_destroy(dsp_uart_handle_t **handle) +{ + if (*handle) { + free(*handle); + *handle = NULL; + } +} + + +void dsp_uart_bit_handler(void *x, int bit) +{ + dsp_uart_handle_t *handle = (dsp_uart_handle_t *) x; + + if (!handle->have_start) { + if (bit) { + return; /* waiting for start bit (0) */ + } + handle->have_start = 1; + handle->data = 0; + handle->nbits = 0; + return; + } + + handle->data >>= 1; + handle->data |= 0x80 * !!bit; + handle->nbits++; + + if (handle->nbits == 8) { + handle->attr.bytehandler(handle->attr.bytehandler_arg, handle->data); + handle->nbits = 0; + handle->data = 0; + handle->have_start = 0; + } +/* might consider handling errors in the future... */ +} + diff --git a/src/mod/applications/mod_fsk/uart.h b/src/mod/applications/mod_fsk/uart.h new file mode 100644 index 0000000000..89c3a13abc --- /dev/null +++ b/src/mod/applications/mod_fsk/uart.h @@ -0,0 +1,76 @@ +/* + * uart.h + * + * Copyright (c) 2005 Robert Krten. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This module contains the manifest constants and declarations for + * the UART module. + * + * 2005 06 19 R. Krten created +*/ + +#ifndef __UART_H__ +#define __UART_H__ + +typedef void (*bytehandler_func_t) (void *, int); +typedef void (*bithandler_func_t) (void *, int); + + +typedef struct dsp_uart_attr_s +{ + bytehandler_func_t bytehandler; /* byte handler */ + void *bytehandler_arg; /* arbitrary ID passed to bytehandler as first argument */ +} dsp_uart_attr_t; + +typedef struct +{ + dsp_uart_attr_t attr; + int have_start; /* wait for start bit to show up */ + int data; /* data buffer */ + int nbits; /* number of bits accumulated so far */ +} dsp_uart_handle_t; + +/* + * Function prototypes + * + * General calling order is: + * a) create the attributes structure (dsp_uart_attr_init) + * b) initialize fields in the attributes structure (dsp_uart_attr_set_*) + * c) create a Bell-202 handle (dsp_uart_create) + * d) feed bits through dsp_uart_bit_handler +*/ + +void dsp_uart_attr_init(dsp_uart_attr_t *attributes); + +bytehandler_func_t dsp_uart_attr_get_bytehandler(dsp_uart_attr_t *attributes, void **bytehandler_arg); +void dsp_uart_attr_set_bytehandler(dsp_uart_attr_t *attributes, bytehandler_func_t bytehandler, void *bytehandler_arg); + +dsp_uart_handle_t * dsp_uart_create(dsp_uart_attr_t *attributes); +void dsp_uart_destroy(dsp_uart_handle_t **handle); + +void dsp_uart_bit_handler(void *handle, int bit); + +#endif +