DV dongle test program
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Mon, 1 Nov 2010 03:29:26 +0000 (03:29 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Mon, 1 Nov 2010 03:29:26 +0000 (03:29 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@208 01035d8c-6547-0410-b346-abe4f91aad63

codec2/unittest/dvdongle2.c [new file with mode: 0644]

diff --git a/codec2/unittest/dvdongle2.c b/codec2/unittest/dvdongle2.c
new file mode 100644 (file)
index 0000000..792b3fc
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>  
+#include <stdio.h>  
+#include <stdlib.h> 
+#include <string.h> 
+#include <unistd.h> 
+#include <fcntl.h>  
+#include <errno.h>  
+#include <termios.h>
+
+#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;
+}