freeswitch/libs/openzap/src/fsk.c

352 lines
10 KiB
C

/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#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;
}
}