dvdongle2.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /*---------------------------------------------------------------------------*\
  2. FILE........: dvdongle2.c
  3. AUTHOR......: David Rowe
  4. DATE CREATED: 28 Oct 2010
  5. Program to encode and decode raw speech samples using the AMBE codec
  6. implemented on a DV Dongle.
  7. The DV Dongle connects to a USB port and provides encoding and
  8. decoding of compressed audio using the DVSI AMBE2000 full duplex
  9. vocoder DSP chip.
  10. Refs:
  11. [1] http://www.dvdongle.com/
  12. [2] http://www.moetronix.com/files/dvdongletechref100.pdf
  13. [3] http://www.dvsinc.com/manuals/AMBE-2000_manual.pdf
  14. [4] http://www.moetronix.com/files/ambetest103.zip
  15. Serial code based on ser.c sample from http://www.captain.at
  16. Compile with:
  17. gcc dvdongle2.c -o dvdongle2 -Wall -g -O2
  18. Note: This program is not very stable, it sometimes stops part way
  19. through processing an utterance. I made it just good enough to work
  20. most of the time, as my purpose was just to process a few sample
  21. files.
  22. \*---------------------------------------------------------------------------*/
  23. /*
  24. Copyright (C) 1990-2010 David Rowe
  25. All rights reserved.
  26. This program is free software; you can redistribute it and/or modify
  27. it under the terms of the GNU Lesser General Public License version 2.1, as
  28. published by the Free Software Foundation. This program is
  29. distributed in the hope that it will be useful, but WITHOUT ANY
  30. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  31. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  32. License for more details.
  33. You should have received a copy of the GNU Lesser General Public License
  34. along with this program; if not, see <http://www.gnu.org/licenses/>.
  35. */
  36. #include <assert.h>
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #include <unistd.h>
  41. #include <fcntl.h>
  42. #include <errno.h>
  43. #include <termios.h>
  44. #define MAX_STR 1024
  45. #define LEN_TARGET_NAME_RESPONSE 14
  46. #define N 160
  47. /* message parsing state machine states */
  48. #define MSGSTATE_HDR1 0
  49. #define MSGSTATE_HDR2 1
  50. #define MSGSTATE_DATA 2
  51. #define LENGTH_MASK 0x1FFF /* mask for message length */
  52. #define TYPE_MASK 0xE0 /* mask for upper byte of header */
  53. #define TYPE_C 0x20 /* compressed speech from target */
  54. #define TYPE_UC 0x40 /* uncompressed speech from target */
  55. #define MAX_MSG_LEN 8192
  56. /* Control items sent to DV Dongle */
  57. char target_name[] = {0x04, 0x20, 0x01, 0x00};
  58. /* note [2] appears to be in error, specifies run as 0x02, stop as 0x01 */
  59. char run_state_stop[] = {0x05, 0x00, 0x18, 0x00, 0x00};
  60. char run_state_run[] = {0x05, 0x00, 0x18, 0x00, 0x01};
  61. /* Control item codes from DV Dongle */
  62. char data_item_0[] = {0x42, 0x81};
  63. char data_item_1[] = {0x32, 0xa0};
  64. char run_state[] = {0x05, 0x00};
  65. char idle[] = {0x00, 0x00};
  66. typedef struct {
  67. short header;
  68. char power;
  69. char control1;
  70. short rate[5];
  71. short unused[3];
  72. short dtmf;
  73. short control2;
  74. short channel_data[12];
  75. } COMPRESSED;
  76. COMPRESSED c_in;
  77. COMPRESSED c_out;
  78. FILE *fin, *fout, *f;
  79. int fd, c_msg, uc_msg;
  80. int initport(int fd) {
  81. struct termios options;
  82. // Set the options for the port...
  83. cfmakeraw(&options);
  84. cfsetispeed(&options, B230400);
  85. cfsetospeed(&options, B230400);
  86. options.c_cflag |= (CLOCAL | CREAD);
  87. tcsetattr(fd, TCSANOW, &options);
  88. return 1;
  89. }
  90. int getbaud(int fd) {
  91. struct termios termAttr;
  92. int inputSpeed = -1;
  93. speed_t baudRate;
  94. tcgetattr(fd, &termAttr);
  95. /* Get the input speed */
  96. baudRate = cfgetispeed(&termAttr);
  97. switch (baudRate) {
  98. case B0: inputSpeed = 0; break;
  99. case B50: inputSpeed = 50; break;
  100. case B110: inputSpeed = 110; break;
  101. case B134: inputSpeed = 134; break;
  102. case B150: inputSpeed = 150; break;
  103. case B200: inputSpeed = 200; break;
  104. case B300: inputSpeed = 300; break;
  105. case B600: inputSpeed = 600; break;
  106. case B1200: inputSpeed = 1200; break;
  107. case B1800: inputSpeed = 1800; break;
  108. case B2400: inputSpeed = 2400; break;
  109. case B4800: inputSpeed = 4800; break;
  110. case B9600: inputSpeed = 9600; break;
  111. case B19200: inputSpeed = 19200; break;
  112. case B38400: inputSpeed = 38400; break;
  113. case B57600: inputSpeed = 38400; break;
  114. case B115200: inputSpeed = 38400; break;
  115. case B230400: inputSpeed = 230400; break;
  116. }
  117. return inputSpeed;
  118. }
  119. void write_dongle(int fd, char *data, int len) {
  120. int n;
  121. //printf(" writing %d bytes\n", len);
  122. n = write(fd, data, len);
  123. if (n < 0) {
  124. perror("write failed");
  125. exit(1);
  126. }
  127. }
  128. void read_dongle(int fd, char *data, int len) {
  129. int n;
  130. //printf(" reading %d bytes \n", len);
  131. n = read(fd, data, len);
  132. if (n < 0) {
  133. perror("read failed");
  134. exit(1);
  135. }
  136. //printf(" read %d bytes\n", len);
  137. }
  138. void parse_message(int msg_type, int msg_len, char msg_data[]) {
  139. short buf[N];
  140. COMPRESSED *c_out;
  141. //printf("msg_type: 0x%02x msg_len: %d\n", msg_type, msg_len);
  142. /* echo compressed speech frames back to target */
  143. if (msg_type == TYPE_C) {
  144. c_out = (COMPRESSED*)msg_data;
  145. #ifdef TMP
  146. printf("control1 0x%04x\n", c_out->control1 & 0xff);
  147. printf("rate[0] 0x%04x\n", c_out->rate[0]);
  148. printf("rate[1] 0x%04x\n", c_out->rate[1]);
  149. printf("rate[2] 0x%04x\n", c_out->rate[2]);
  150. printf("rate[3] 0x%04x\n", c_out->rate[3]);
  151. printf("rate[4] 0x%04x\n", c_out->rate[4]);
  152. printf("control2 0x%04x\n", c_out->control2 & 0xffff);
  153. printf("cd[0] 0x%04x\n", c_out->channel_data[0] & 0xffff);
  154. printf("cd[1] 0x%04x\n", c_out->channel_data[1] & 0xffff);
  155. printf("cd[2] 0x%04x\n", c_out->channel_data[2] & 0xffff);
  156. printf("cd[3] 0x%04x\n", c_out->channel_data[3] & 0xffff);
  157. printf("cd[4] 0x%04x\n", c_out->channel_data[4] & 0xffff);
  158. printf("cd[5] 0x%04x\n", c_out->channel_data[5] & 0xffff);
  159. printf("cd[6] 0x%04x\n", c_out->channel_data[6] & 0xffff);
  160. printf("uc_msg %d\n", uc_msg);
  161. #endif
  162. printf("bit errors %d\n", c_out->unused[2]);
  163. memcpy(&c_in.channel_data,
  164. &c_out->channel_data,
  165. sizeof(c_in.channel_data));
  166. write_dongle(fd, data_item_1, sizeof(data_item_1));
  167. write_dongle(fd, (char*)&c_in, sizeof(c_in));
  168. c_msg++;
  169. }
  170. /* write speech buffers to disk */
  171. if (msg_type == TYPE_UC) {
  172. if (fout != NULL) {
  173. fwrite(msg_data, sizeof(char), msg_len-2, fout);
  174. printf("msg_len %d\n", msg_len);
  175. }
  176. if (fin != NULL)
  177. fread(buf, sizeof(short), N, fin);
  178. else
  179. memset(buf, 0, sizeof(buf));
  180. write_dongle(fd, data_item_0, sizeof(data_item_0));
  181. write_dongle(fd, (char*)buf, sizeof(buf));
  182. uc_msg++;
  183. }
  184. }
  185. int main(int argc, char **argv) {
  186. char response[MAX_STR];
  187. int i;
  188. int state, next_state;
  189. short header;
  190. int msg_type, msg_length;
  191. char msg_data[MAX_MSG_LEN];
  192. int n, length;
  193. int r;
  194. char data;
  195. f = fopen("/tmp/log.txt", "wt");
  196. assert(f != NULL);
  197. /* open and configure serial port */
  198. fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
  199. if (fd == -1) {
  200. perror("open_port: Unable to open /dev/ttyS0 - ");
  201. exit(1);
  202. } else {
  203. fcntl(fd, F_SETFL, 0);
  204. }
  205. initport(fd);
  206. fin = NULL;
  207. if (argc >= 2) {
  208. fin = fopen(argv[1],"rb");
  209. assert(fin != NULL);
  210. }
  211. fout = NULL;
  212. if (argc == 3) {
  213. fout = fopen(argv[2],"wb");
  214. assert(fout != NULL);
  215. }
  216. /* check DV Dongle is alive */
  217. write_dongle(fd, target_name, sizeof(target_name));
  218. read_dongle(fd, response, LEN_TARGET_NAME_RESPONSE);
  219. if (strcmp(&response[4],"DV Dongle") != 0) {
  220. printf("DV Dongle not responding\n");
  221. exit(1);
  222. }
  223. printf("Found DV Dongle....\n");
  224. c_in.header = 0x13ec;
  225. c_in.power = 0x0;
  226. c_in.control1 = 0x0;
  227. #define RATE2000
  228. #ifdef RATE2000
  229. c_in.rate[0] = 0x0028; /* 2000 bit/s, no FEC */
  230. c_in.rate[1] = 0x0000;
  231. c_in.rate[2] = 0x0000;
  232. c_in.rate[3] = 0x0000;
  233. c_in.rate[4] = 0x6248;
  234. #endif
  235. #ifdef RATE3600_1200
  236. c_in.rate[0] = 0x5048; /* 3600 bit/s, 1200 bit/s FEC */
  237. c_in.rate[1] = 0x0001;
  238. c_in.rate[2] = 0x0000;
  239. c_in.rate[3] = 0x2412;
  240. c_in.rate[4] = 0x6860;
  241. #endif
  242. c_in.unused[0] = 0x0;
  243. c_in.unused[1] = 0x0;
  244. c_in.unused[2] = 0x0;
  245. c_in.dtmf = 0x00ff;
  246. c_in.control2 = 0x8000;
  247. /* put codec in run mode */
  248. write_dongle(fd, run_state_run, sizeof(run_state_run));
  249. //write_dongle(fd, data_item_1, sizeof(data_item_1));
  250. //write_dongle(fd, (char*)&c_in, sizeof(c_in));
  251. state = MSGSTATE_HDR1;
  252. header = msg_type = msg_length = n = length = 0;
  253. c_msg = uc_msg = 0;
  254. for(i=0; i<100000; i++) {
  255. /*
  256. We can only reliably read one byte at a time. Until I
  257. realised this there was "much wailing and gnashing of
  258. teeth". Trying to read() n bytes read() returns n but may
  259. actually reads some number between 1 and n. So it may only
  260. read 1 byte int data[] but return n.
  261. */
  262. r = read(fd, &data, 1);
  263. assert(r == 1);
  264. /* used state machine design from ambetest103.zip, SerialPort.cpp */
  265. next_state = state;
  266. switch(state) {
  267. case MSGSTATE_HDR1:
  268. header = data;
  269. next_state = MSGSTATE_HDR2;
  270. break;
  271. case MSGSTATE_HDR2:
  272. header |= data<<8;
  273. msg_length = header & LENGTH_MASK;
  274. msg_type = header & TYPE_MASK;
  275. //printf("%0x %d\n", msg_type, msg_length);
  276. if (length == 2) {
  277. parse_message(msg_type, msg_length, msg_data);
  278. next_state = MSGSTATE_HDR1;
  279. }
  280. else {
  281. if (msg_length == 0x0)
  282. length = 8192;
  283. else
  284. length = msg_length - 2;
  285. n = 0;
  286. next_state = MSGSTATE_DATA;
  287. }
  288. break;
  289. case MSGSTATE_DATA:
  290. msg_data[n++] = data;
  291. length--;
  292. if (length == 0) {
  293. parse_message(msg_type, msg_length, msg_data);
  294. next_state = MSGSTATE_HDR1;
  295. }
  296. break;
  297. }
  298. state = next_state;
  299. }
  300. printf("finished, c_msg = %d uc_msg = %d\n", c_msg, uc_msg);
  301. write_dongle(fd, run_state_stop, sizeof(run_state_stop));
  302. close(fd);
  303. if (fin != NULL)
  304. fclose(fin);
  305. if (fout != NULL)
  306. fclose(fout);
  307. fclose(f);
  308. return 0;
  309. }