mirror of
https://github.com/n5ac/smartsdr-dsp.git
synced 2026-01-04 15:40:06 +01:00
This allowed the TX to modulate; however, still recieving reset packets in TX and RX mode
806 lines
23 KiB
C
806 lines
23 KiB
C
///*! \file thumbdv.c
|
|
// * \brief Functions required to communicate and decode packets from ThumbDV
|
|
// *
|
|
// * \copyright Copyright 2012-2014 FlexRadio Systems. All Rights Reserved.
|
|
// * Unauthorized use, duplication or distribution of this software is
|
|
// * strictly prohibited by law.
|
|
// *
|
|
// * \date 26-MAY-2015
|
|
// * \author Ed Gonzalez
|
|
// *
|
|
// *
|
|
// */
|
|
|
|
/* *****************************************************************************
|
|
*
|
|
* Copyright (C) 2014 FlexRadio Systems.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Contact Information:
|
|
* email: gpl<at>flexradiosystems.com
|
|
* Mail: FlexRadio Systems, Suite 1-150, 4616 W. Howard LN, Austin, TX 78728
|
|
*
|
|
* ************************************************************************** */
|
|
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <termios.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <pthread.h>
|
|
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <sys/select.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/prctl.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include "common.h"
|
|
#include "datatypes.h"
|
|
#include "hal_buffer.h"
|
|
|
|
#include "vita_output.h"
|
|
#include "thumbDV.h"
|
|
#include "sched_waveform.h"
|
|
#include "ftd2xx.h"
|
|
|
|
#define AMBE3000_HEADER_LEN 4U
|
|
#define AMBE3000_START_BYTE 0x61U
|
|
|
|
#define AMBE3000_SPEECHD_HEADER_LEN 3U
|
|
|
|
#define AMBE3000_CTRL_PKT_TYPE 0x00
|
|
#define AMBE3000_SPEECH_PKT_TYPE 0x02
|
|
#define AMBE3000_CHAN_PKT_TYPE 0x01
|
|
|
|
#define BUFFER_LENGTH 400U
|
|
#define THUMBDV_MAX_PACKET_LEN 2048U
|
|
|
|
static pthread_t _read_thread;
|
|
BOOL _readThreadAbort = FALSE;
|
|
|
|
static uint32 _buffering_target = 0;
|
|
static uint32 _encode_buffering_target = 4;
|
|
|
|
static pthread_rwlock_t _encoded_list_lock;
|
|
static BufferDescriptor _encoded_root;
|
|
static BOOL _encoded_buffering = TRUE;
|
|
static uint32 _encoded_count = 0;
|
|
|
|
static pthread_rwlock_t _decoded_list_lock;
|
|
static BufferDescriptor _decoded_root;
|
|
static BOOL _decoded_buffering = TRUE;
|
|
static uint32 _decoded_count = 0;
|
|
|
|
static sem_t _read_sem;
|
|
|
|
//static void * _thumbDV_readThread( void * param );
|
|
|
|
static BufferDescriptor _thumbDVEncodedList_UnlinkHead( void ) {
|
|
BufferDescriptor buf_desc = NULL;
|
|
pthread_rwlock_wrlock( &_encoded_list_lock );
|
|
|
|
|
|
if ( _encoded_root == NULL || _encoded_root->next == NULL ) {
|
|
output( "Attempt to unlink from a NULL head" );
|
|
pthread_rwlock_unlock( &_encoded_list_lock );
|
|
return NULL;
|
|
}
|
|
|
|
if ( _encoded_buffering ) {
|
|
pthread_rwlock_unlock( &_encoded_list_lock );
|
|
return NULL;
|
|
}
|
|
|
|
if ( _encoded_root->next != _encoded_root )
|
|
buf_desc = _encoded_root->next;
|
|
|
|
if ( buf_desc != NULL ) {
|
|
// make sure buffer exists and is actually linked
|
|
if ( !buf_desc || !buf_desc->prev || !buf_desc->next ) {
|
|
output( "Invalid buffer descriptor" );
|
|
buf_desc = NULL;
|
|
} else {
|
|
buf_desc->next->prev = buf_desc->prev;
|
|
buf_desc->prev->next = buf_desc->next;
|
|
buf_desc->next = NULL;
|
|
buf_desc->prev = NULL;
|
|
|
|
if ( _encoded_count > 0 ) _encoded_count--;
|
|
}
|
|
} else {
|
|
if ( !_encoded_buffering ) output( "Encoded list now buffering\n" );
|
|
|
|
_encoded_buffering = TRUE;
|
|
}
|
|
|
|
pthread_rwlock_unlock( &_encoded_list_lock );
|
|
return buf_desc;
|
|
}
|
|
|
|
static void _thumbDVEncodedList_LinkTail( BufferDescriptor buf_desc ) {
|
|
pthread_rwlock_wrlock( &_encoded_list_lock );
|
|
buf_desc->next = _encoded_root;
|
|
buf_desc->prev = _encoded_root->prev;
|
|
_encoded_root->prev->next = buf_desc;
|
|
_encoded_root->prev = buf_desc;
|
|
_encoded_count++;
|
|
|
|
if ( _encoded_count > _encode_buffering_target ) {
|
|
if ( _encoded_buffering ) output( "Encoded Buffering is now FALSE\n" );
|
|
|
|
_encoded_buffering = FALSE;
|
|
}
|
|
|
|
pthread_rwlock_unlock( &_encoded_list_lock );
|
|
}
|
|
|
|
static BufferDescriptor _thumbDVDecodedList_UnlinkHead( void ) {
|
|
BufferDescriptor buf_desc = NULL;
|
|
pthread_rwlock_wrlock( &_decoded_list_lock );
|
|
|
|
if ( _decoded_root == NULL || _decoded_root->next == NULL ) {
|
|
output( "Attempt to unlink from a NULL head" );
|
|
pthread_rwlock_unlock( &_decoded_list_lock );
|
|
return NULL;
|
|
}
|
|
|
|
if ( _decoded_buffering ) {
|
|
pthread_rwlock_unlock( &_decoded_list_lock );
|
|
return NULL;
|
|
}
|
|
|
|
if ( _decoded_root->next != _decoded_root ) {
|
|
buf_desc = _decoded_root->next;
|
|
}
|
|
|
|
if ( buf_desc != NULL ) {
|
|
//output("0");
|
|
// make sure buffer exists and is actually linked
|
|
if ( !buf_desc || !buf_desc->prev || !buf_desc->next ) {
|
|
output( "Invalid buffer descriptor" );
|
|
buf_desc = NULL;
|
|
} else {
|
|
buf_desc->next->prev = buf_desc->prev;
|
|
buf_desc->prev->next = buf_desc->next;
|
|
buf_desc->next = NULL;
|
|
buf_desc->prev = NULL;
|
|
|
|
if ( _decoded_count > 0 ) _decoded_count--;
|
|
}
|
|
} else {
|
|
if ( !_decoded_buffering )
|
|
//output( "DecodedList now Buffering \n" );
|
|
|
|
_decoded_buffering = TRUE;
|
|
}
|
|
|
|
pthread_rwlock_unlock( &_decoded_list_lock );
|
|
return buf_desc;
|
|
}
|
|
|
|
static void _thumbDVDecodedList_LinkTail( BufferDescriptor buf_desc ) {
|
|
pthread_rwlock_wrlock( &_decoded_list_lock );
|
|
buf_desc->next = _decoded_root;
|
|
buf_desc->prev = _decoded_root->prev;
|
|
_decoded_root->prev->next = buf_desc;
|
|
_decoded_root->prev = buf_desc;
|
|
|
|
_decoded_count++;
|
|
|
|
if ( _decoded_count > _buffering_target ) {
|
|
// if ( _decoded_buffering ) output( "Decoded Buffering is now FALSE\n" );
|
|
|
|
_decoded_buffering = FALSE;
|
|
}
|
|
|
|
pthread_rwlock_unlock( &_decoded_list_lock );
|
|
}
|
|
|
|
BOOL thumbDV_getDecodeListBuffering(void)
|
|
{
|
|
return _decoded_buffering;
|
|
}
|
|
|
|
static void delay( unsigned int delay ) {
|
|
struct timespec tim, tim2;
|
|
tim.tv_sec = 0;
|
|
tim.tv_nsec = delay * 1000UL;
|
|
nanosleep( &tim, &tim2 );
|
|
};
|
|
|
|
void thumbDV_flushLists(void)
|
|
{
|
|
BufferDescriptor buf_desc = NULL;
|
|
|
|
do
|
|
{
|
|
buf_desc = _thumbDVEncodedList_UnlinkHead();
|
|
if ( buf_desc != NULL )
|
|
hal_BufferRelease(&buf_desc);
|
|
} while (buf_desc != NULL );
|
|
|
|
|
|
do
|
|
{
|
|
buf_desc = _thumbDVDecodedList_UnlinkHead();
|
|
if ( buf_desc != NULL )
|
|
hal_BufferRelease(&buf_desc);
|
|
} while (buf_desc != NULL );
|
|
}
|
|
|
|
void thumbDV_dump( char * text, unsigned char * data, unsigned int length ) {
|
|
unsigned int offset = 0U;
|
|
unsigned int i;
|
|
|
|
output( "%s", text );
|
|
output( "\n" );
|
|
|
|
while ( length > 0U ) {
|
|
unsigned int bytes = ( length > 16U ) ? 16U : length;
|
|
|
|
output( "%04X: ", offset );
|
|
|
|
for ( i = 0U; i < bytes; i++ )
|
|
output( "%02X ", data[offset + i] );
|
|
|
|
for ( i = bytes; i < 16U; i++ )
|
|
output( " " );
|
|
|
|
output( " *" );
|
|
|
|
for ( i = 0U; i < bytes; i++ ) {
|
|
unsigned char c = data[offset + i];
|
|
|
|
if ( isprint( c ) )
|
|
output( "%c", c );
|
|
else
|
|
output( "." );
|
|
}
|
|
|
|
output( "*\n" );
|
|
|
|
offset += 16U;
|
|
|
|
if ( length >= 16U )
|
|
length -= 16U;
|
|
else
|
|
length = 0U;
|
|
}
|
|
}
|
|
|
|
static int thumbDV_writeSerial( FT_HANDLE handle , unsigned char * buffer, uint32 bytes )
|
|
{
|
|
FT_STATUS status = FT_OK;
|
|
DWORD written = 0;
|
|
|
|
if ( handle != NULL )
|
|
{
|
|
//FT_SetRts(handle);
|
|
status = FT_Write(handle, buffer, bytes, &written);
|
|
usleep(100);
|
|
|
|
if ( status != FT_OK || written != bytes ) {
|
|
output( ANSI_RED "Could not write to serial port. status = %d\n", status );
|
|
return status;
|
|
}
|
|
//FT_ClrRts(handle);
|
|
}
|
|
else
|
|
{
|
|
output( ANSI_RED "Could not write to serial port. Timeout\n" ANSI_WHITE );
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static int _check_serial( FT_HANDLE handle )
|
|
{
|
|
int ret = 0;
|
|
unsigned char reset[5] = { 0x61, 0x00, 0x01, 0x00, 0x33 };
|
|
|
|
thumbDV_writeSerial( handle, reset, 5 );
|
|
ret = thumbDV_processSerial(handle);
|
|
|
|
if ( ret != 0 )
|
|
{
|
|
output( "Could not reset serial port FD = %d \n", handle );
|
|
return -1;
|
|
}
|
|
|
|
unsigned char get_prodID[5] = {0x61, 0x00, 0x01, 0x00, 0x30 };
|
|
thumbDV_writeSerial( handle, get_prodID, 5 );
|
|
ret = thumbDV_processSerial(handle);
|
|
|
|
if ( ret != 0 )
|
|
{
|
|
output( "Could not reset serial port FD = %d \n", handle );
|
|
return -1;
|
|
}
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
FT_HANDLE thumbDV_openSerial( FT_DEVICE_LIST_INFO_NODE device )
|
|
{
|
|
//struct termios tty;
|
|
FT_HANDLE handle = NULL;
|
|
FT_STATUS status = FT_OK;
|
|
UCHAR latency = 5;
|
|
|
|
output("Trying to open serial port %s \n", device.SerialNumber);
|
|
|
|
status = FT_OpenEx(device.SerialNumber, FT_OPEN_BY_SERIAL_NUMBER, &handle);
|
|
|
|
if ( status != FT_OK || handle == NULL )
|
|
{
|
|
if ( device.SerialNumber )
|
|
output("Error opening device %s - error 0x%X\n", device.SerialNumber, status);
|
|
else
|
|
output("Error opening device - error 0x%X\n", status);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
FT_SetBaudRate(handle, FT_BAUD_460800);
|
|
FT_SetDataCharacteristics(handle, FT_BITS_8, FT_STOP_BITS_1, FT_PARITY_NONE);
|
|
FT_SetTimeouts(handle, 0, 0);
|
|
FT_SetFlowControl(handle, FT_FLOW_RTS_CTS, 0, 0);
|
|
|
|
/*
|
|
tty.c_cflag = ( tty.c_cflag & ~CSIZE ) | CS8;
|
|
tty.c_iflag &= ~IGNBRK;
|
|
tty.c_lflag = 0;
|
|
|
|
tty.c_oflag = 0;
|
|
tty.c_cc[VMIN] = 1;
|
|
tty.c_cc[VTIME] = 5;
|
|
|
|
tty.c_iflag &= ~( IXON | IXOFF | IXANY );
|
|
|
|
tty.c_cflag |= ( CLOCAL | CREAD );
|
|
|
|
tty.c_cflag &= ~( PARENB | PARODD );
|
|
tty.c_cflag &= ~CSTOPB;
|
|
tty.c_cflag &= ~CRTSCTS;
|
|
|
|
if ( tcsetattr( fd, TCSANOW, &tty ) != 0 ) {
|
|
output( "ThumbDV: error %d from tcsetattr\n", errno );
|
|
close( fd );
|
|
return -1;
|
|
}
|
|
*/
|
|
if ( _check_serial(handle) != 0 ) {
|
|
output( "Could not detect ThumbDV at 460800 Baud. Trying 230400\n" );
|
|
FT_Close(handle);
|
|
handle = (FT_HANDLE)NULL;
|
|
} else {
|
|
return handle;
|
|
}
|
|
|
|
status = FT_OpenEx(device.SerialNumber, FT_OPEN_BY_SERIAL_NUMBER, &handle);
|
|
|
|
if ( status != FT_OK || handle == NULL )
|
|
{
|
|
if ( device.SerialNumber )
|
|
output("Error opening device %s - error 0x%X\n", device.SerialNumber, status);
|
|
else
|
|
output("Error opening device - error 0x%X\n", status);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
FT_SetBaudRate(handle, FT_BAUD_230400 );
|
|
FT_SetDataCharacteristics(handle, FT_BITS_8, FT_STOP_BITS_1, FT_PARITY_NONE);
|
|
FT_SetTimeouts(handle, 0, 0);
|
|
FT_SetFlowControl(handle, FT_FLOW_NONE, 0, 0);
|
|
FT_SetLatencyTimer(handle, latency);
|
|
|
|
if ( _check_serial( handle ) != 0 ) {
|
|
output( "Could not detect THumbDV at 230400 Baud\n" );
|
|
FT_Close(handle);
|
|
handle = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
return handle;
|
|
}
|
|
|
|
int thumbDV_processSerial( FT_HANDLE handle )
|
|
{
|
|
unsigned char buffer[BUFFER_LENGTH];
|
|
unsigned int respLen;
|
|
|
|
unsigned char packet_type;
|
|
FT_STATUS status = FT_OK;
|
|
DWORD rx_bytes = 0;
|
|
DWORD tx_bytes = 0 ;
|
|
DWORD event_word = 0;
|
|
uint32 max_us_sleep = 100000; // 100 ms
|
|
uint32 us_slept = 0;
|
|
do
|
|
{
|
|
status = FT_GetStatus(handle, &rx_bytes, &tx_bytes, &event_word);
|
|
|
|
if ( rx_bytes >= AMBE3000_HEADER_LEN )
|
|
break;
|
|
|
|
usleep(100);
|
|
|
|
us_slept += 100;
|
|
|
|
if ( us_slept > max_us_sleep )
|
|
{
|
|
output("TimeOut #1\n");
|
|
return FT_OTHER_ERROR;
|
|
}
|
|
|
|
} while (rx_bytes < AMBE3000_HEADER_LEN && status == FT_OK );
|
|
|
|
status = FT_Read(handle, buffer, AMBE3000_HEADER_LEN, &rx_bytes);
|
|
|
|
if ( status != FT_OK || rx_bytes != AMBE3000_HEADER_LEN)
|
|
{
|
|
output( ANSI_RED "ThumbDV: Process serial. error when reading from the serial port, len = %d, status=%d\n" ANSI_WHITE, rx_bytes, status );
|
|
return 1;
|
|
}
|
|
|
|
if ( buffer[0U] != AMBE3000_START_BYTE ) {
|
|
output( ANSI_RED "ThumbDV: unknown byte from the DV3000, 0x%02X\n" ANSI_WHITE, buffer[0U] );
|
|
return FT_OTHER_ERROR;
|
|
}
|
|
|
|
respLen = buffer[1U] * 256U + buffer[2U];
|
|
|
|
us_slept = 0;
|
|
do
|
|
{
|
|
status = FT_GetStatus(handle, &rx_bytes, &tx_bytes, &event_word);
|
|
|
|
if ( rx_bytes >= respLen )
|
|
break;
|
|
|
|
usleep(100);
|
|
|
|
us_slept += 100 ;
|
|
|
|
if ( us_slept > max_us_sleep )
|
|
{
|
|
output("TimeOut #2 \n");
|
|
return FT_OTHER_ERROR;
|
|
}
|
|
|
|
} while (rx_bytes < respLen && status == FT_OK);
|
|
|
|
status = FT_Read(handle, buffer + AMBE3000_HEADER_LEN , respLen, &rx_bytes);
|
|
|
|
if ( status != FT_OK || rx_bytes != respLen )
|
|
{
|
|
output( ANSI_RED "ThumbDV: Process serial. error when reading from the serial port, len = %d, status=%d\n" ANSI_WHITE, rx_bytes, status );
|
|
}
|
|
|
|
respLen += AMBE3000_HEADER_LEN;
|
|
|
|
BufferDescriptor desc = NULL;
|
|
packet_type = buffer[3];
|
|
|
|
//thumbDV_dump("Serial data", buffer, respLen);
|
|
if ( packet_type == AMBE3000_CTRL_PKT_TYPE ) {
|
|
thumbDV_dump( ANSI_YELLOW "Serial data" ANSI_WHITE, buffer, respLen );
|
|
} else if ( packet_type == AMBE3000_CHAN_PKT_TYPE ) {
|
|
desc = hal_BufferRequest( respLen, sizeof( unsigned char ) );
|
|
memcpy( desc->buf_ptr, buffer, respLen );
|
|
//thumbDV_dump(ANSI_BLUE "Coded Packet" ANSI_WHITE, buffer, respLen);
|
|
/* Encoded data */
|
|
_thumbDVEncodedList_LinkTail( desc );
|
|
} else if ( packet_type == AMBE3000_SPEECH_PKT_TYPE ) {
|
|
desc = hal_BufferRequest( respLen, sizeof( unsigned char ) );
|
|
memcpy( desc->buf_ptr, buffer, respLen );
|
|
//thumbDV_dump("SPEECH Packet", buffer, respLen);
|
|
/* Speech data */
|
|
_thumbDVDecodedList_LinkTail( desc );
|
|
|
|
} else {
|
|
output( ANSI_RED "Unrecognized packet type 0x%02X ", packet_type );
|
|
return FT_OTHER_ERROR;
|
|
|
|
}
|
|
|
|
|
|
return FT_OK;
|
|
}
|
|
|
|
int thumbDV_unlinkAudio(short * speech_out)
|
|
{
|
|
int32 samples_returned = 0;
|
|
BufferDescriptor desc = _thumbDVDecodedList_UnlinkHead();
|
|
uint32 samples_in_speech_packet = 0;
|
|
uint32 length = 0;
|
|
|
|
if ( desc != NULL ) {
|
|
length = ( ( ( unsigned char * )desc->buf_ptr )[1] << 8 ) + ( ( unsigned char * )desc->buf_ptr )[2];;
|
|
|
|
if ( length != 0x142 ) {
|
|
output( ANSI_YELLOW, "WARNING LENGHT DOESN'T Match %d " ANSI_WHITE, length );
|
|
thumbDV_dump( "MISMATHCED", ( ( unsigned char * ) desc->buf_ptr ), desc->num_samples );
|
|
}
|
|
|
|
samples_in_speech_packet = ( ( unsigned char * )desc->buf_ptr )[5];
|
|
|
|
unsigned char * idx = &( ( ( unsigned char * )desc->buf_ptr )[6] );
|
|
uint32 i = 0;
|
|
|
|
for ( i = 0; i < samples_in_speech_packet; i++, idx += 2 ) {
|
|
speech_out[i] = ( idx[0] << 8 ) + idx[1];
|
|
}
|
|
|
|
samples_returned = samples_in_speech_packet;
|
|
|
|
if ( samples_returned != 160 ) output( "Rate Mismatch expected %d got %d\n", 160, samples_returned );
|
|
|
|
// safe_free( desc );
|
|
hal_BufferRelease(&desc);
|
|
} else {
|
|
/* Do nothing for now */
|
|
}
|
|
|
|
return samples_returned;
|
|
}
|
|
|
|
void thumbDV_decode( FT_HANDLE handle, unsigned char * packet_in, uint8 bytes_in_packet ) {
|
|
uint32 i = 0;
|
|
|
|
unsigned char full_packet[15] = {0};
|
|
|
|
if ( packet_in != NULL && handle != NULL ) {
|
|
full_packet[0] = 0x61;
|
|
full_packet[1] = 0x00;
|
|
full_packet[2] = 0x0B;
|
|
full_packet[3] = 0x01;
|
|
full_packet[4] = 0x01;
|
|
full_packet[5] = 0x48;
|
|
uint32 j = 0;
|
|
|
|
for ( i = 0, j = 8 ; i < 9 ; i++ , j-- ) {
|
|
full_packet[i + 6] = packet_in[i];
|
|
}
|
|
|
|
// thumbDV_dump("Just AMBE", packet_in, 9);
|
|
// thumbDV_dump("Encoded packet:", full_packet, 15);
|
|
thumbDV_writeSerial( handle, full_packet, 15 );
|
|
sem_post(&_read_sem);
|
|
}
|
|
}
|
|
|
|
int thumbDV_encode( FT_HANDLE handle, short * speech_in, unsigned char * packet_out, uint8 num_of_samples )
|
|
{
|
|
unsigned char packet[THUMBDV_MAX_PACKET_LEN];
|
|
uint16 speech_d_bytes = num_of_samples * sizeof( uint16 ); /* Should be 2 times the number of samples */
|
|
|
|
/* Calculate length of packet NOT including the full header just the type field*/
|
|
uint16 length = 0;
|
|
/* Includes Channel Field and SpeechD Field Header */
|
|
length += AMBE3000_SPEECHD_HEADER_LEN;
|
|
length += speech_d_bytes;
|
|
|
|
/* Will be used to write fields into packet */
|
|
unsigned char * idx = &packet[0];
|
|
|
|
*( idx++ ) = AMBE3000_START_BYTE;
|
|
/* Length split into two bytes */
|
|
*( idx++ ) = length >> 8;
|
|
*( idx++ ) = length & 0xFF;
|
|
/* SPEECHD Type */
|
|
*( idx++ ) = AMBE3000_SPEECH_PKT_TYPE;
|
|
/* Channel0 Identifier */
|
|
*( idx++ ) = 0x40;
|
|
/* SPEEECHD Identifier */
|
|
*( idx++ ) = 0x00;
|
|
/* SPEECHD No of Samples */
|
|
*( idx++ ) = num_of_samples;
|
|
uint32 i = 0;
|
|
// output("Num of Samples = 0x%X\n", num_of_samples);
|
|
|
|
#ifdef WOOT
|
|
output( "Encode Packet Header = " );
|
|
unsigned char * p = &packet[0];
|
|
i = 0;
|
|
|
|
for ( i = 0 ; i < 7 ; i++ ) {
|
|
|
|
output( "%02X ", *p );
|
|
p++;
|
|
}
|
|
|
|
output( "\n" );
|
|
|
|
#endif
|
|
//memcpy(idx, speech_in, speech_d_bytes);
|
|
i = 0;
|
|
|
|
for ( i = 0 ; i < num_of_samples ; i++, idx += 2 ) {
|
|
idx[0] = speech_in[i] >> 8;
|
|
idx[1] = ( speech_in[i] & 0x00FF ) ;
|
|
}
|
|
|
|
if ( handle != NULL )
|
|
{
|
|
thumbDV_writeSerial( handle, packet, length + AMBE3000_HEADER_LEN );
|
|
sem_post(&_read_sem);
|
|
}
|
|
|
|
int32 samples_returned = 0;
|
|
BufferDescriptor desc = _thumbDVEncodedList_UnlinkHead();
|
|
|
|
if ( desc != NULL ) {
|
|
memcpy( packet_out, desc->buf_ptr + 6, desc->sample_size * ( desc->num_samples - 6 ) );
|
|
samples_returned = desc->num_samples - 6;
|
|
//safe_free( desc );
|
|
hal_BufferRelease(&desc);
|
|
//thumbDV_dump(ANSI_BLUE "Coded Packet" ANSI_WHITE, packet_out, desc->num_samples - 6);
|
|
|
|
} else {
|
|
/* Do nothing for now */
|
|
}
|
|
|
|
return samples_returned;
|
|
|
|
}
|
|
|
|
static void _connectSerial( FT_HANDLE * ftHandle )
|
|
{
|
|
int i = 0 ;
|
|
|
|
output("ConnectSerial\n");
|
|
|
|
DWORD numDevs = 0;
|
|
FT_DEVICE_LIST_INFO_NODE *devInfo = NULL;
|
|
FT_STATUS status = FT_OK;
|
|
|
|
do {
|
|
|
|
status = FT_CreateDeviceInfoList(&numDevs);
|
|
|
|
devInfo = (FT_DEVICE_LIST_INFO_NODE *) safe_malloc(sizeof(FT_DEVICE_LIST_INFO_NODE) * numDevs);
|
|
|
|
status = FT_GetDeviceInfoList(devInfo, &numDevs);
|
|
|
|
for ( i = 0 ; i < numDevs ; i++ )
|
|
{
|
|
|
|
*ftHandle = thumbDV_openSerial(devInfo[i]);
|
|
|
|
if ( *ftHandle != NULL )
|
|
{
|
|
/* We opened a valid port and detected the ThumbDV */
|
|
break;
|
|
}
|
|
}
|
|
safe_free(devInfo);
|
|
|
|
if ( *ftHandle == NULL ) {
|
|
output( "Could not open serial. Waiting 1 second before trying again.\n" );
|
|
usleep( 1000 * 1000 );
|
|
}
|
|
} while ( *ftHandle == NULL ) ;
|
|
|
|
// Reset and Product ID printout are done in thumbDV_openSerial() which calls _check_serial()
|
|
|
|
unsigned char disable_parity[6] = {0x61, 0x00, 0x02, 0x00, 0x3F, 0x00};
|
|
thumbDV_writeSerial( *ftHandle, disable_parity, 6 );
|
|
thumbDV_processSerial(*ftHandle);
|
|
|
|
unsigned char get_version[5] = {0x61, 0x00, 0x01, 0x00, 0x31};
|
|
unsigned char read_cfg[5] = {0x61, 0x00, 0x01, 0x00, 0x37};
|
|
unsigned char dstar_mode[17] = {0x61, 0x00, 0x0D, 0x00, 0x0A, 0x01, 0x30, 0x07, 0x63, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48};
|
|
|
|
thumbDV_writeSerial( *ftHandle, get_version, 5 );
|
|
thumbDV_processSerial(*ftHandle);
|
|
thumbDV_writeSerial( *ftHandle, read_cfg, 5 );
|
|
thumbDV_processSerial(*ftHandle);
|
|
thumbDV_writeSerial( *ftHandle, dstar_mode, 17 );
|
|
thumbDV_processSerial(*ftHandle);
|
|
|
|
//// /* Init */
|
|
unsigned char pkt_init[6] = { 0x61, 0x00, 0x02, 0x00, 0x0B, 0x07 };
|
|
thumbDV_writeSerial( *ftHandle, pkt_init, 6 );
|
|
thumbDV_processSerial(*ftHandle);
|
|
|
|
/* PKT GAIN - set to 0dB */
|
|
unsigned char pkt_gain[7] = { 0x61, 0x00, 0x03, 0x00, 0x4B, 0x00, 0x00 };
|
|
thumbDV_writeSerial( *ftHandle, pkt_gain, 7 );
|
|
thumbDV_processSerial(*ftHandle);
|
|
|
|
/* Companding off so it uses 16bit linear */
|
|
unsigned char pkt_compand[6] = { 0x61, 0x00, 0x02, 0x00, 0x32, 0x00 };
|
|
thumbDV_writeSerial( *ftHandle, pkt_compand, 6 );
|
|
thumbDV_processSerial(*ftHandle);
|
|
|
|
unsigned char pkt_fmt[7] = {0x61, 0x00, 0x3, 0x00, 0x15, 0x00, 0x00};
|
|
thumbDV_writeSerial( *ftHandle, pkt_fmt, 7 );
|
|
thumbDV_processSerial(*ftHandle);
|
|
|
|
}
|
|
|
|
static void * _thumbDV_readThread( void * param )
|
|
{
|
|
int ret;
|
|
DWORD rx_bytes;
|
|
DWORD tx_bytes;
|
|
DWORD event_dword;
|
|
|
|
FT_STATUS status = FT_OK;
|
|
FT_HANDLE handle = *(FT_HANDLE *) param;
|
|
|
|
prctl(PR_SET_NAME, "DV-Read");
|
|
|
|
while ( !_readThreadAbort )
|
|
{
|
|
sem_wait(&_read_sem);
|
|
|
|
ret = thumbDV_processSerial(handle);
|
|
//TODO Handle reconnection
|
|
// if ( ret != FT_OK )
|
|
// {
|
|
// fprintf( stderr, "ThumbDV: error from status, status=%d\n", ret );
|
|
//
|
|
// /* Set invalid FD in sched_waveform so we don't call write functions */
|
|
// handle = NULL;
|
|
// sched_waveform_setHandle(&handle);
|
|
// /* This function hangs until a new connection is made */
|
|
// _connectSerial( &handle );
|
|
// /* Update the sched_waveform to new valid serial */
|
|
// sched_waveform_setHandle( &handle );
|
|
// }
|
|
}
|
|
|
|
output( ANSI_YELLOW "thumbDV_readThread has exited\n" ANSI_WHITE );
|
|
return 0;
|
|
}
|
|
|
|
void thumbDV_init( FT_HANDLE * handle ) {
|
|
pthread_rwlock_init( &_encoded_list_lock, NULL );
|
|
pthread_rwlock_init( &_decoded_list_lock, NULL );
|
|
|
|
sem_init(&_read_sem, 0, 0);
|
|
|
|
pthread_rwlock_wrlock( &_encoded_list_lock );
|
|
_encoded_root = ( BufferDescriptor )safe_malloc( sizeof( buffer_descriptor ) );
|
|
memset( _encoded_root, 0, sizeof( buffer_descriptor ) );
|
|
_encoded_root->next = _encoded_root;
|
|
_encoded_root->prev = _encoded_root;
|
|
pthread_rwlock_unlock( &_encoded_list_lock );
|
|
|
|
pthread_rwlock_wrlock( &_decoded_list_lock );
|
|
_decoded_root = ( BufferDescriptor )safe_malloc( sizeof( buffer_descriptor ) );
|
|
memset( _decoded_root, 0, sizeof( buffer_descriptor ) );
|
|
_decoded_root->next = _decoded_root;
|
|
_decoded_root->prev = _decoded_root;
|
|
pthread_rwlock_unlock( &_decoded_list_lock );
|
|
|
|
_connectSerial(handle);
|
|
|
|
pthread_create( &_read_thread, NULL, &_thumbDV_readThread, handle );
|
|
|
|
struct sched_param fifo_param;
|
|
fifo_param.sched_priority = 30;
|
|
pthread_setschedparam( _read_thread, SCHED_FIFO, &fifo_param );
|
|
|
|
}
|