v22bis_tests.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. /*
  2. * SpanDSP - a series of DSP components for telephony
  3. *
  4. * v22bis_tests.c
  5. *
  6. * Written by Steve Underwood <steveu@coppice.org>
  7. *
  8. * Copyright (C) 2004 Steve Underwood
  9. *
  10. * All rights reserved.
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License version 2, as
  14. * published by the Free Software Foundation.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24. */
  25. /*! \page v22bis_tests_page V.22bis modem tests
  26. \section v22bis_tests_page_sec_1 What does it do?
  27. These tests connect two V.22bis modems back to back, through a telephone line
  28. model. BER testing is then used to evaluate performance under various line
  29. conditions.
  30. If the appropriate GUI environment exists, the tests are built such that a visual
  31. display of modem status is maintained.
  32. \section v22bis_tests_page_sec_2 How is it used?
  33. */
  34. #if defined(HAVE_CONFIG_H)
  35. #include "config.h"
  36. #endif
  37. #if defined(HAVE_FL_FL_H) && defined(HAVE_FL_FL_CARTESIAN_H) && defined(HAVE_FL_FL_AUDIO_METER_H)
  38. #define ENABLE_GUI
  39. #endif
  40. #include <stdlib.h>
  41. #include <stdio.h>
  42. #include <fcntl.h>
  43. #include <unistd.h>
  44. #include <string.h>
  45. #include <sndfile.h>
  46. #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
  47. #include "spandsp.h"
  48. #include "spandsp-sim.h"
  49. #if defined(ENABLE_GUI)
  50. #include "modem_monitor.h"
  51. #endif
  52. #define BLOCK_LEN 160
  53. #define OUT_FILE_NAME "v22bis.wav"
  54. char *decode_test_file = NULL;
  55. bool use_gui = false;
  56. int rx_bits = 0;
  57. both_ways_line_model_state_t *model;
  58. typedef struct
  59. {
  60. v22bis_state_t *v22bis;
  61. bert_state_t bert_tx;
  62. bert_state_t bert_rx;
  63. bert_results_t latest_results;
  64. #if defined(ENABLE_GUI)
  65. qam_monitor_t *qam_monitor;
  66. #endif
  67. float smooth_power;
  68. int symbol_no;
  69. } endpoint_t;
  70. endpoint_t endpoint[2];
  71. static void reporter(void *user_data, int reason, bert_results_t *results)
  72. {
  73. endpoint_t *s;
  74. s = (endpoint_t *) user_data;
  75. switch (reason)
  76. {
  77. case BERT_REPORT_REGULAR:
  78. fprintf(stderr, "V.22bis rx %p BERT report regular - %d bits, %d bad bits, %d resyncs\n",
  79. user_data,
  80. results->total_bits,
  81. results->bad_bits,
  82. results->resyncs);
  83. memcpy(&s->latest_results, results, sizeof(s->latest_results));
  84. break;
  85. default:
  86. fprintf(stderr,
  87. "V.22bis rx %p BERT report %s\n",
  88. user_data,
  89. bert_event_to_str(reason));
  90. break;
  91. }
  92. }
  93. /*- End of function --------------------------------------------------------*/
  94. static void v22bis_rx_status(void *user_data, int status)
  95. {
  96. endpoint_t *s;
  97. int bit_rate;
  98. int i;
  99. int len;
  100. #if defined(SPANDSP_USE_FIXED_POINT)
  101. complexi16_t *coeffs;
  102. #else
  103. complexf_t *coeffs;
  104. #endif
  105. /* Special conditions */
  106. s = (endpoint_t *) user_data;
  107. printf("V.22bis rx %p status is %s (%d)\n", user_data, signal_status_to_str(status), status);
  108. switch (status)
  109. {
  110. case SIG_STATUS_TRAINING_SUCCEEDED:
  111. bit_rate = v22bis_get_current_bit_rate(s->v22bis);
  112. printf("Negotiated bit rate: %d\n", bit_rate);
  113. if ((len = v22bis_rx_equalizer_state(s->v22bis, &coeffs)))
  114. {
  115. printf("Equalizer:\n");
  116. for (i = 0; i < len; i++)
  117. #if defined(SPANDSP_USE_FIXED_POINT)
  118. printf("%3d (%15.5f, %15.5f)\n", i, coeffs[i].re/V22BIS_CONSTELLATION_SCALING_FACTOR, coeffs[i].im/V22BIS_CONSTELLATION_SCALING_FACTOR);
  119. #else
  120. printf("%3d (%15.5f, %15.5f) -> %15.5f\n", i, coeffs[i].re, coeffs[i].im, powerf(&coeffs[i]));
  121. #endif
  122. }
  123. break;
  124. }
  125. }
  126. /*- End of function --------------------------------------------------------*/
  127. static void v22bis_putbit(void *user_data, int bit)
  128. {
  129. endpoint_t *s;
  130. if (bit < 0)
  131. {
  132. v22bis_rx_status(user_data, bit);
  133. return;
  134. }
  135. s = (endpoint_t *) user_data;
  136. if (decode_test_file)
  137. printf("Rx bit %p-%d - %d\n", user_data, rx_bits++, bit);
  138. else
  139. bert_put_bit(&s->bert_rx, bit);
  140. }
  141. /*- End of function --------------------------------------------------------*/
  142. static int v22bis_getbit(void *user_data)
  143. {
  144. endpoint_t *s;
  145. int bit;
  146. s = (endpoint_t *) user_data;
  147. bit = bert_get_bit(&s->bert_tx);
  148. return bit;
  149. }
  150. /*- End of function --------------------------------------------------------*/
  151. #if defined(SPANDSP_USE_FIXED_POINT)
  152. static void qam_report(void *user_data, const complexi16_t *constel, const complexi16_t *target, int symbol)
  153. #else
  154. static void qam_report(void *user_data, const complexf_t *constel, const complexf_t *target, int symbol)
  155. #endif
  156. {
  157. int i;
  158. int len;
  159. #if defined(SPANDSP_USE_FIXED_POINT)
  160. complexi16_t *coeffs;
  161. #else
  162. complexf_t *coeffs;
  163. #endif
  164. complexf_t constel_point;
  165. complexf_t target_point;
  166. float fpower;
  167. endpoint_t *s;
  168. s = (endpoint_t *) user_data;
  169. if (constel)
  170. {
  171. constel_point.re = constel->re/V22BIS_CONSTELLATION_SCALING_FACTOR;
  172. constel_point.im = constel->im/V22BIS_CONSTELLATION_SCALING_FACTOR;
  173. target_point.re = target->re/V22BIS_CONSTELLATION_SCALING_FACTOR;
  174. target_point.im = target->im/V22BIS_CONSTELLATION_SCALING_FACTOR;
  175. #if defined(ENABLE_GUI)
  176. if (use_gui)
  177. {
  178. qam_monitor_update_constel(s->qam_monitor, &constel_point);
  179. qam_monitor_update_carrier_tracking(s->qam_monitor, v22bis_rx_carrier_frequency(s->v22bis));
  180. qam_monitor_update_symbol_tracking(s->qam_monitor, v22bis_rx_symbol_timing_correction(s->v22bis));
  181. }
  182. #endif
  183. fpower = (constel->re - target->re)*(constel->re - target->re)
  184. + (constel->im - target->im)*(constel->im - target->im);
  185. s->smooth_power = 0.95f*s->smooth_power + 0.05f*fpower;
  186. printf("%8d [%8.4f, %8.4f] [%8.4f, %8.4f] %2x %8.4f %8.4f %8.4f\n",
  187. s->symbol_no,
  188. constel_point.re,
  189. constel_point.im,
  190. target_point.re,
  191. target_point.im,
  192. symbol,
  193. fpower,
  194. s->smooth_power,
  195. v22bis_rx_signal_power(s->v22bis));
  196. s->symbol_no++;
  197. }
  198. else
  199. {
  200. printf("Gardner step %d\n", symbol);
  201. if ((len = v22bis_rx_equalizer_state(s->v22bis, &coeffs)))
  202. {
  203. printf("Equalizer A:\n");
  204. for (i = 0; i < len; i++)
  205. #if defined(SPANDSP_USE_FIXED_POINT)
  206. printf("%3d (%15.5f, %15.5f)\n", i, coeffs[i].re/V22BIS_CONSTELLATION_SCALING_FACTOR, coeffs[i].im/V22BIS_CONSTELLATION_SCALING_FACTOR);
  207. #else
  208. printf("%3d (%15.5f, %15.5f) -> %15.5f\n", i, coeffs[i].re, coeffs[i].im, powerf(&coeffs[i]));
  209. #endif
  210. #if defined(ENABLE_GUI)
  211. if (use_gui)
  212. {
  213. #if defined(SPANDSP_USE_FIXED_POINT)
  214. qam_monitor_update_int_equalizer(s->qam_monitor, coeffs, len);
  215. #else
  216. qam_monitor_update_equalizer(s->qam_monitor, coeffs, len);
  217. #endif
  218. }
  219. #endif
  220. }
  221. }
  222. }
  223. /*- End of function --------------------------------------------------------*/
  224. int main(int argc, char *argv[])
  225. {
  226. int16_t amp[2][BLOCK_LEN];
  227. int16_t model_amp[2][BLOCK_LEN];
  228. int16_t out_amp[2*BLOCK_LEN];
  229. SNDFILE *inhandle;
  230. SNDFILE *outhandle;
  231. int outframes;
  232. int samples;
  233. int samples2;
  234. int i;
  235. int j;
  236. int test_bps;
  237. int line_model_no;
  238. int channel_codec;
  239. int rbs_pattern;
  240. int bits_per_test;
  241. int noise_level;
  242. int signal_level;
  243. int guard_tone_option;
  244. int opt;
  245. bool log_audio;
  246. channel_codec = MUNGE_CODEC_NONE;
  247. rbs_pattern = 0;
  248. test_bps = 2400;
  249. line_model_no = 0;
  250. decode_test_file = NULL;
  251. noise_level = -70;
  252. signal_level = -13;
  253. bits_per_test = 50000;
  254. guard_tone_option = V22BIS_GUARD_TONE_1800HZ;
  255. log_audio = false;
  256. while ((opt = getopt(argc, argv, "b:B:c:d:gG:lm:n:r:s:")) != -1)
  257. {
  258. switch (opt)
  259. {
  260. case 'b':
  261. test_bps = atoi(optarg);
  262. if (test_bps != 2400 && test_bps != 1200)
  263. {
  264. fprintf(stderr, "Invalid bit rate specified\n");
  265. exit(2);
  266. }
  267. break;
  268. case 'B':
  269. bits_per_test = atoi(optarg);
  270. break;
  271. case 'c':
  272. channel_codec = atoi(optarg);
  273. break;
  274. case 'd':
  275. decode_test_file = optarg;
  276. break;
  277. case 'g':
  278. #if defined(ENABLE_GUI)
  279. use_gui = true;
  280. #else
  281. fprintf(stderr, "Graphical monitoring not available\n");
  282. exit(2);
  283. #endif
  284. break;
  285. case 'G':
  286. guard_tone_option = atoi(optarg);
  287. break;
  288. case 'l':
  289. log_audio = true;
  290. break;
  291. case 'm':
  292. line_model_no = atoi(optarg);
  293. break;
  294. case 'n':
  295. noise_level = atoi(optarg);
  296. break;
  297. case 'r':
  298. rbs_pattern = atoi(optarg);
  299. break;
  300. case 's':
  301. signal_level = atoi(optarg);
  302. break;
  303. default:
  304. //usage();
  305. exit(2);
  306. break;
  307. }
  308. }
  309. inhandle = NULL;
  310. if (decode_test_file)
  311. {
  312. /* We will decode the audio from a file. */
  313. if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL)
  314. {
  315. fprintf(stderr, " Cannot open audio file '%s'\n", decode_test_file);
  316. exit(2);
  317. }
  318. }
  319. outhandle = NULL;
  320. if (log_audio)
  321. {
  322. if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 2)) == NULL)
  323. {
  324. fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME);
  325. exit(2);
  326. }
  327. }
  328. memset(endpoint, 0, sizeof(endpoint));
  329. for (i = 0; i < 2; i++)
  330. {
  331. endpoint[i].v22bis = v22bis_init(NULL, test_bps, guard_tone_option, (i == 0), v22bis_getbit, &endpoint[i], v22bis_putbit, &endpoint[i]);
  332. v22bis_tx_power(endpoint[i].v22bis, signal_level);
  333. /* Move the carrier off a bit */
  334. endpoint[i].v22bis->tx.carrier_phase_rate = dds_phase_ratef((i == 0) ? 1207.0f : 2407.0f);
  335. v22bis_rx_set_qam_report_handler(endpoint[i].v22bis, qam_report, (void *) &endpoint[i]);
  336. span_log_set_level(&endpoint[i].v22bis->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
  337. span_log_set_tag(&endpoint[i].v22bis->logging, (i == 0) ? "caller" : "answerer");
  338. endpoint[i].smooth_power = 0.0f;
  339. endpoint[i].symbol_no = 0;
  340. bert_init(&endpoint[i].bert_tx, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20);
  341. bert_init(&endpoint[i].bert_rx, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20);
  342. bert_set_report(&endpoint[i].bert_rx, 10000, reporter, &endpoint[i]);
  343. }
  344. #if defined(ENABLE_GUI)
  345. if (use_gui)
  346. {
  347. endpoint[0].qam_monitor = qam_monitor_init(6.0f, V22BIS_CONSTELLATION_SCALING_FACTOR, "Calling modem");
  348. endpoint[1].qam_monitor = qam_monitor_init(6.0f, V22BIS_CONSTELLATION_SCALING_FACTOR, "Answering modem");
  349. }
  350. #endif
  351. if ((model = both_ways_line_model_init(line_model_no,
  352. (float) noise_level,
  353. -15.0f,
  354. -15.0f,
  355. line_model_no,
  356. (float) noise_level,
  357. -15.0f,
  358. -15.0f,
  359. channel_codec,
  360. rbs_pattern)) == NULL)
  361. {
  362. fprintf(stderr, " Failed to create line model\n");
  363. exit(2);
  364. }
  365. samples = 0;
  366. for (;;)
  367. {
  368. for (i = 0; i < 2; i++)
  369. {
  370. samples = v22bis_tx(endpoint[i].v22bis, amp[i], BLOCK_LEN);
  371. #if defined(ENABLE_GUI)
  372. if (use_gui)
  373. qam_monitor_update_audio_level(endpoint[i].qam_monitor, amp[i], samples);
  374. #endif
  375. if (samples == 0)
  376. {
  377. /* Note that we might get a few bad bits as the carrier shuts down. */
  378. bert_result(&endpoint[i].bert_rx, &endpoint[i].latest_results);
  379. bert_init(&endpoint[i].bert_tx, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20);
  380. bert_init(&endpoint[i].bert_rx, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20);
  381. bert_set_report(&endpoint[i].bert_rx, 10000, reporter, &endpoint[i]);
  382. printf("Restarting on zero output\n");
  383. v22bis_restart(endpoint[i].v22bis, test_bps);
  384. }
  385. }
  386. #if 1
  387. both_ways_line_model(model,
  388. model_amp[0],
  389. amp[0],
  390. model_amp[1],
  391. amp[1],
  392. samples);
  393. #else
  394. vec_copyi16(model_amp[0], amp[0], samples);
  395. vec_copyi16(model_amp[1], amp[1], samples);
  396. #endif
  397. if (decode_test_file)
  398. {
  399. samples2 = sf_readf_short(inhandle, model_amp[0], samples);
  400. if (samples2 != samples)
  401. break;
  402. }
  403. for (i = 0; i < 2; i++)
  404. {
  405. span_log_bump_samples(&endpoint[i].v22bis->logging, samples);
  406. v22bis_rx(endpoint[i ^ 1].v22bis, model_amp[i], samples);
  407. for (j = 0; j < samples; j++)
  408. out_amp[2*j + i] = model_amp[i][j];
  409. for ( ; j < BLOCK_LEN; j++)
  410. out_amp[2*j + i] = 0;
  411. }
  412. if (log_audio)
  413. {
  414. outframes = sf_writef_short(outhandle, out_amp, BLOCK_LEN);
  415. if (outframes != BLOCK_LEN)
  416. {
  417. fprintf(stderr, " Error writing audio file\n");
  418. exit(2);
  419. }
  420. }
  421. }
  422. both_ways_line_model_free(model);
  423. #if defined(ENABLE_GUI)
  424. if (use_gui)
  425. qam_wait_to_end(endpoint[0].qam_monitor);
  426. #endif
  427. if (decode_test_file)
  428. {
  429. if (sf_close_telephony(inhandle))
  430. {
  431. fprintf(stderr, " Cannot close audio file '%s'\n", decode_test_file);
  432. exit(2);
  433. }
  434. }
  435. if (log_audio)
  436. {
  437. if (sf_close_telephony(outhandle))
  438. {
  439. fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME);
  440. exit(2);
  441. }
  442. }
  443. return 0;
  444. }
  445. /*- End of function --------------------------------------------------------*/
  446. /*- End of file ------------------------------------------------------------*/