Handle ThumbDV being unplugged gracefully.

When the ThumbDV is unplugged the serial read thread stops and tries to re-connect. All writes to the serial port also stop.
This commit is contained in:
Ed Gonzalez 2015-08-20 14:21:38 -05:00
parent 09cca8a92d
commit 2f828cf2ac
4 changed files with 103 additions and 72 deletions

View file

@ -340,6 +340,11 @@ void sched_waveform_setOwnCall2(uint32 slice , const char * owncall2 )
dstar_dumpHeader(&(_dstar->outgoing_header));
}
void sched_waveform_setFD(int fd)
{
_dv_serial_fd = fd;
}
static void* _sched_waveform_thread(void* param)
{
int nout;
@ -376,7 +381,7 @@ static void* _sched_waveform_thread(void* param)
// ======================= Initialization Section =========================
thumbDV_init("/dev/ttyUSB0", &_dv_serial_fd);
thumbDV_init(&_dv_serial_fd);
// Initialize the Circular Buffers

View file

@ -48,4 +48,5 @@ void sched_waveform_setOwnCall1( uint32 slice , const char * owncall1 );
void sched_waveform_setOwnCall2(uint32 slice , const char * owncall2 );
void sched_waveform_sendStatus(uint32 slice);
void sched_waveform_setFD(int fd);
#endif /* SCHED_WAVEFORM_H_ */

View file

@ -55,6 +55,7 @@
#include "vita_output.h"
#include "thumbDV.h"
#include "sched_waveform.h"
#define DV3000_TTY "/dev/ttyAMA0"
@ -87,6 +88,8 @@ static BufferDescriptor _decoded_root;
static BOOL _decoded_buffering = TRUE;
static uint32 _decoded_count = 0;
static void* _thumbDV_readThread(void* param);
static BufferDescriptor _thumbDVEncodedList_UnlinkHead(void)
{
BufferDescriptor buf_desc = NULL;
@ -441,7 +444,7 @@ int thumbDV_processSerial(int serial_fd)
errno = 0;
len = read(serial_fd, buffer, 1);
if (len != 1) {
output(ANSI_RED "ThumbDV: error when reading from the serial port, len = %d, errno=%d\n" ANSI_WHITE, len, errno);
output(ANSI_RED "ThumbDV: Process serial. error when reading from the serial port, len = %d, errno=%d\n" ANSI_WHITE, len, errno);
return 1;
}
@ -507,7 +510,7 @@ int thumbDV_decode(int serial_fd, unsigned char * packet_in, short * speech_out,
uint32 i = 0;
unsigned char full_packet[15] = {0};
if ( packet_in != NULL ) {
if ( packet_in != NULL && serial_fd > 0 ) {
full_packet[0] = 0x61;
full_packet[1] = 0x00;
full_packet[2] = 0x0B;
@ -600,8 +603,8 @@ int thumbDV_encode(int serial_fd, short * speech_in, unsigned char * packet_out,
idx[0] = speech_in[i] >> 8;
idx[1] = (speech_in[i] & 0x00FF) ;
}
thumbDV_writeSerial(serial_fd, packet, length + AMBE3000_HEADER_LEN);
if ( serial_fd > 0 )
thumbDV_writeSerial(serial_fd, packet, length + AMBE3000_HEADER_LEN);
int32 samples_returned = 0;
BufferDescriptor desc = _thumbDVEncodedList_UnlinkHead();
@ -620,65 +623,20 @@ int thumbDV_encode(int serial_fd, short * speech_in, unsigned char * packet_out,
}
static void* _thumbDV_readThread(void* param)
static void _connectSerial(int * serial_fd)
{
int topFd;
fd_set fds;
int ret;
int serial_fd = *(int*)param;
topFd = serial_fd + 1;
output("Serial FD = %d in thumbDV_readThread(). TopFD = %d\n", serial_fd, topFd);
struct timeval timeout;
while ( !_readThreadAbort ) {
timeout.tv_sec = 1;
timeout.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(serial_fd, &fds);
errno = 0;
ret = select(topFd, &fds, NULL, NULL, &timeout);
if (ret < 0) {
fprintf(stderr, "ThumbDV: error from select, errno=%d\n", errno);
}
if (FD_ISSET(serial_fd, &fds)) {
ret = thumbDV_processSerial(serial_fd);
}
}
output(ANSI_YELLOW "thumbDV_readThread has exited\n" ANSI_WHITE);
return 0;
}
void thumbDV_init(const char * serial_device_name, int * serial_fd)
{
pthread_rwlock_init(&_encoded_list_lock, NULL);
pthread_rwlock_init(&_decoded_list_lock, NULL);
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);
int i = 0 ;
char device[256] = {0} ;
do {
*serial_fd = thumbDV_openSerial("/dev/ttyUSB0");
if ( *serial_fd < 0 )
*serial_fd = thumbDV_openSerial("/dev/ttyUSB1");
for ( i = 0 ; i < 25 ; i++ ) {
sprintf(device, "/dev/ttyUSB%d", i);
*serial_fd =thumbDV_openSerial(device);
if ( *serial_fd > 0 ) {
/* We opened a valid port */
break;
}
}
if ( * serial_fd < 0 )
{
@ -700,20 +658,11 @@ void thumbDV_init(const char * serial_device_name, int * serial_fd)
thumbDV_writeSerial(*serial_fd, disable_parity, 6);
thumbDV_processSerial(*serial_fd);
pthread_create(&_read_thread, NULL, &_thumbDV_readThread, serial_fd);
struct sched_param fifo_param;
fifo_param.sched_priority = 30;
pthread_setschedparam(_read_thread, SCHED_FIFO, &fifo_param);
unsigned char get_prodID[5] = {0x61, 0x00, 0x01, 0x00, 0x30 };
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(*serial_fd, get_prodID, 5 );
thumbDV_writeSerial(*serial_fd, get_version, 5);
thumbDV_writeSerial(*serial_fd, read_cfg, 5);
@ -739,3 +688,79 @@ void thumbDV_init(const char * serial_device_name, int * serial_fd)
thumbDV_writeSerial(*serial_fd, pkt_fmt, 7);
}
static void* _thumbDV_readThread(void* param)
{
int topFd;
fd_set fds;
int ret;
int serial_fd = *(int*)param;
topFd = serial_fd + 1;
output("Serial FD = %d in thumbDV_readThread(). TopFD = %d\n", serial_fd, topFd);
struct timeval timeout;
while ( !_readThreadAbort ) {
timeout.tv_sec = 1;
timeout.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(serial_fd, &fds);
errno = 0;
ret = select(topFd, &fds, NULL, NULL, &timeout);
if (ret < 0) {
fprintf(stderr, "ThumbDV: error from select, errno=%d\n", errno);
}
if (FD_ISSET(serial_fd, &fds)) {
ret = thumbDV_processSerial(serial_fd);
if ( ret != 0 ) {
/* Set invalid FD in sched_waveform so we don't call write functions */
sched_waveform_setFD(-1);
/* This function hangs until a new connection is made */
_connectSerial(&serial_fd);
/* Update the sched_waveform to new valid serial */
sched_waveform_setFD(serial_fd);
topFd = serial_fd + 1;
}
}
}
output(ANSI_YELLOW "thumbDV_readThread has exited\n" ANSI_WHITE);
return 0;
}
void thumbDV_init(int * serial_fd)
{
pthread_rwlock_init(&_encoded_list_lock, NULL);
pthread_rwlock_init(&_decoded_list_lock, NULL);
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(serial_fd);
pthread_create(&_read_thread, NULL, &_thumbDV_readThread, serial_fd);
struct sched_param fifo_param;
fifo_param.sched_priority = 30;
pthread_setschedparam(_read_thread, SCHED_FIFO, &fifo_param);
}

View file

@ -36,7 +36,7 @@
#ifndef THUMBDV_THUMBDV_
#define THUMBDV_THUMBDV_
void thumbDV_init(const char * serial_device_name, int * serial_fd);
void thumbDV_init(int * serial_fd);
int thumbDV_openSerial(const char * tty_name);
int thumbDV_processSerial(int serial_fd);