From: drowe67 Date: Mon, 1 Nov 2010 03:29:26 +0000 (+0000) Subject: DV dongle test program X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=f5a94eaf53a53223df6b1143eeb4f41e652038f5;p=freetel-svn-tracking.git DV dongle test program git-svn-id: https://svn.code.sf.net/p/freetel/code@208 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/codec2/unittest/dvdongle2.c b/codec2/unittest/dvdongle2.c new file mode 100644 index 00000000..792b3fc1 --- /dev/null +++ b/codec2/unittest/dvdongle2.c @@ -0,0 +1,385 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: dvdongle2.c + AUTHOR......: David Rowe + DATE CREATED: 28 Oct 2010 + + Program to encode and decode raw speech samples using the AMBE codec + implemented on a DV Dongle. + + The DV Dongle connects to a USB port and provides encoding and + decoding of compressed audio using the DVSI AMBE2000 full duplex + vocoder DSP chip. + + Refs: + + [1] http://www.dvdongle.com/ + [2] http://www.moetronix.com/files/dvdongletechref100.pdf + [3] http://www.dvsinc.com/manuals/AMBE-2000_manual.pdf + [4] http://www.moetronix.com/files/ambetest103.zip + + Serial code based on ser.c sample from http://www.captain.at + + Compile with: + + gcc dvdongle2.c -o dvdongle2 -Wall -g -O2 + + Note: This program is not very stable, it sometimes stops part way + through processing an utterance. I made it just good enough to work + most of the time, as my purpose was just to process a few sample + files. + + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 1990-2010 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. 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 Lesser General Public License + along with this program; if not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_STR 1024 +#define LEN_TARGET_NAME_RESPONSE 14 +#define N 160 + +/* message parsing state machine states */ + +#define MSGSTATE_HDR1 0 +#define MSGSTATE_HDR2 1 +#define MSGSTATE_DATA 2 + +#define LENGTH_MASK 0x1FFF /* mask for message length */ +#define TYPE_MASK 0xE0 /* mask for upper byte of header */ +#define TYPE_C 0x20 /* compressed speech from target */ +#define TYPE_UC 0x40 /* uncompressed speech from target */ + +#define MAX_MSG_LEN 8192 + +/* Control items sent to DV Dongle */ + +char target_name[] = {0x04, 0x20, 0x01, 0x00}; + +/* note [2] appears to be in error, specifies run as 0x02, stop as 0x01 */ + +char run_state_stop[] = {0x05, 0x00, 0x18, 0x00, 0x00}; +char run_state_run[] = {0x05, 0x00, 0x18, 0x00, 0x01}; + +/* Control item codes from DV Dongle */ + +char data_item_0[] = {0x42, 0x81}; +char data_item_1[] = {0x32, 0xa0}; +char run_state[] = {0x05, 0x00}; +char idle[] = {0x00, 0x00}; + +typedef struct { + short header; + char power; + char control1; + short rate[5]; + short unused[3]; + short dtmf; + short control2; + short channel_data[12]; +} COMPRESSED; + +COMPRESSED c_in; +COMPRESSED c_out; +FILE *fin, *fout, *f; +int fd, c_msg, uc_msg; + +int initport(int fd) { + struct termios options; + + // Set the options for the port... + + cfmakeraw(&options); + cfsetispeed(&options, B230400); + cfsetospeed(&options, B230400); + options.c_cflag |= (CLOCAL | CREAD); + tcsetattr(fd, TCSANOW, &options); + + return 1; +} + +int getbaud(int fd) { + struct termios termAttr; + int inputSpeed = -1; + speed_t baudRate; + + tcgetattr(fd, &termAttr); + + /* Get the input speed */ + + baudRate = cfgetispeed(&termAttr); + switch (baudRate) { + case B0: inputSpeed = 0; break; + case B50: inputSpeed = 50; break; + case B110: inputSpeed = 110; break; + case B134: inputSpeed = 134; break; + case B150: inputSpeed = 150; break; + case B200: inputSpeed = 200; break; + case B300: inputSpeed = 300; break; + case B600: inputSpeed = 600; break; + case B1200: inputSpeed = 1200; break; + case B1800: inputSpeed = 1800; break; + case B2400: inputSpeed = 2400; break; + case B4800: inputSpeed = 4800; break; + case B9600: inputSpeed = 9600; break; + case B19200: inputSpeed = 19200; break; + case B38400: inputSpeed = 38400; break; + case B57600: inputSpeed = 38400; break; + case B115200: inputSpeed = 38400; break; + case B230400: inputSpeed = 230400; break; + } + + return inputSpeed; +} + +void write_dongle(int fd, char *data, int len) { + int n; + //printf(" writing %d bytes\n", len); + n = write(fd, data, len); + if (n < 0) { + perror("write failed"); + exit(1); + } +} + +void read_dongle(int fd, char *data, int len) { + int n; + //printf(" reading %d bytes \n", len); + + n = read(fd, data, len); + if (n < 0) { + perror("read failed"); + exit(1); + } + //printf(" read %d bytes\n", len); +} + +void parse_message(int msg_type, int msg_len, char msg_data[]) { + short buf[N]; + COMPRESSED *c_out; + + //printf("msg_type: 0x%02x msg_len: %d\n", msg_type, msg_len); + + /* echo compressed speech frames back to target */ + + if (msg_type == TYPE_C) { + c_out = (COMPRESSED*)msg_data; +#ifdef TMP + printf("control1 0x%04x\n", c_out->control1 & 0xff); + printf("rate[0] 0x%04x\n", c_out->rate[0]); + printf("rate[1] 0x%04x\n", c_out->rate[1]); + printf("rate[2] 0x%04x\n", c_out->rate[2]); + printf("rate[3] 0x%04x\n", c_out->rate[3]); + printf("rate[4] 0x%04x\n", c_out->rate[4]); + printf("control2 0x%04x\n", c_out->control2 & 0xffff); + printf("cd[0] 0x%04x\n", c_out->channel_data[0] & 0xffff); + printf("cd[1] 0x%04x\n", c_out->channel_data[1] & 0xffff); + printf("cd[2] 0x%04x\n", c_out->channel_data[2] & 0xffff); + printf("cd[3] 0x%04x\n", c_out->channel_data[3] & 0xffff); + printf("cd[4] 0x%04x\n", c_out->channel_data[4] & 0xffff); + printf("cd[5] 0x%04x\n", c_out->channel_data[5] & 0xffff); + printf("cd[6] 0x%04x\n", c_out->channel_data[6] & 0xffff); + printf("uc_msg %d\n", uc_msg); +#endif + printf("bit errors %d\n", c_out->unused[2]); + memcpy(&c_in.channel_data, + &c_out->channel_data, + sizeof(c_in.channel_data)); + + write_dongle(fd, data_item_1, sizeof(data_item_1)); + write_dongle(fd, (char*)&c_in, sizeof(c_in)); + + c_msg++; + } + + /* write speech buffers to disk */ + + if (msg_type == TYPE_UC) { + + if (fout != NULL) { + fwrite(msg_data, sizeof(char), msg_len-2, fout); + printf("msg_len %d\n", msg_len); + } + + if (fin != NULL) + fread(buf, sizeof(short), N, fin); + else + memset(buf, 0, sizeof(buf)); + + write_dongle(fd, data_item_0, sizeof(data_item_0)); + write_dongle(fd, (char*)buf, sizeof(buf)); + + uc_msg++; + } +} + +int main(int argc, char **argv) { + char response[MAX_STR]; + int i; + int state, next_state; + short header; + int msg_type, msg_length; + char msg_data[MAX_MSG_LEN]; + int n, length; + int r; + + char data; + + f = fopen("/tmp/log.txt", "wt"); + assert(f != NULL); + + /* open and configure serial port */ + + fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY); + if (fd == -1) { + perror("open_port: Unable to open /dev/ttyS0 - "); + exit(1); + } else { + fcntl(fd, F_SETFL, 0); + } + + initport(fd); + + fin = NULL; + if (argc >= 2) { + fin = fopen(argv[1],"rb"); + assert(fin != NULL); + } + fout = NULL; + if (argc == 3) { + fout = fopen(argv[2],"wb"); + assert(fout != NULL); + } + + /* check DV Dongle is alive */ + + write_dongle(fd, target_name, sizeof(target_name)); + read_dongle(fd, response, LEN_TARGET_NAME_RESPONSE); + if (strcmp(&response[4],"DV Dongle") != 0) { + printf("DV Dongle not responding\n"); + exit(1); + } + printf("Found DV Dongle....\n"); + + c_in.header = 0x13ec; + c_in.power = 0x0; + c_in.control1 = 0x0; + +#define RATE2000 +#ifdef RATE2000 + c_in.rate[0] = 0x0028; /* 2000 bit/s, no FEC */ + c_in.rate[1] = 0x0000; + c_in.rate[2] = 0x0000; + c_in.rate[3] = 0x0000; + c_in.rate[4] = 0x6248; +#endif + +#ifdef RATE3600_1200 + c_in.rate[0] = 0x5048; /* 3600 bit/s, 1200 bit/s FEC */ + c_in.rate[1] = 0x0001; + c_in.rate[2] = 0x0000; + c_in.rate[3] = 0x2412; + c_in.rate[4] = 0x6860; +#endif + + c_in.unused[0] = 0x0; + c_in.unused[1] = 0x0; + c_in.unused[2] = 0x0; + c_in.dtmf = 0x00ff; + c_in.control2 = 0x8000; + + /* put codec in run mode */ + + write_dongle(fd, run_state_run, sizeof(run_state_run)); + //write_dongle(fd, data_item_1, sizeof(data_item_1)); + //write_dongle(fd, (char*)&c_in, sizeof(c_in)); + + state = MSGSTATE_HDR1; + header = msg_type = msg_length = n = length = 0; + c_msg = uc_msg = 0; + + for(i=0; i<100000; i++) { + /* + We can only reliably read one byte at a time. Until I + realised this there was "much wailing and gnashing of + teeth". Trying to read() n bytes read() returns n but may + actually reads some number between 1 and n. So it may only + read 1 byte int data[] but return n. + */ + r = read(fd, &data, 1); + assert(r == 1); + + /* used state machine design from ambetest103.zip, SerialPort.cpp */ + + next_state = state; + switch(state) { + case MSGSTATE_HDR1: + header = data; + next_state = MSGSTATE_HDR2; + break; + case MSGSTATE_HDR2: + header |= data<<8; + msg_length = header & LENGTH_MASK; + msg_type = header & TYPE_MASK; + //printf("%0x %d\n", msg_type, msg_length); + if (length == 2) { + parse_message(msg_type, msg_length, msg_data); + next_state = MSGSTATE_HDR1; + } + else { + if (msg_length == 0x0) + length = 8192; + else + length = msg_length - 2; + n = 0; + next_state = MSGSTATE_DATA; + } + break; + case MSGSTATE_DATA: + msg_data[n++] = data; + length--; + if (length == 0) { + parse_message(msg_type, msg_length, msg_data); + next_state = MSGSTATE_HDR1; + } + break; + } + state = next_state; + } + + printf("finished, c_msg = %d uc_msg = %d\n", c_msg, uc_msg); + + write_dongle(fd, run_state_stop, sizeof(run_state_stop)); + + close(fd); + if (fin != NULL) + fclose(fin); + if (fout != NULL) + fclose(fout); + fclose(f); + + return 0; +}