1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934
|
/*
* UnixCW - Unix CW (Morse code) training program
* Copyright (C) 2001 Simon Baldwin (simonb@caldera.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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 General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
* cwlib.c - C library of extensive low-level Morse code services
*
*/
/* Include files. */
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <errno.h>
#if defined(HAVE_STRING_H)
# include <string.h>
#endif /* HAVE_STRING_H */
#if defined(HAVE_STRINGS_H)
# include <strings.h>
#endif /* HAVE_STRINGS_H */
#if defined(HAVE_SYS_KD_H)
# include <sys/kd.h> /* Linux, UnixWare */
#else /* not HAVE_SYS_KD_H */
# if defined(HAVE_SYS_VTKD_H)
# include <sys/vtkd.h> /* OpenServer */
# else /* not HAVE_SYS_VTKD_H */
# error "Neither sys/kd.h nor sys/vtkd.h header files available"
# endif /* not HAVE_SYS_VTKD_H */
#endif /* not HAVE_SYS_KD_H */
/* Library include file for the library we are implementing. */
#include "cwlib.h"
#define MAJOR_VERSION 2
#define MINOR_VERSION 0
#define VERSION "cwlib version 2.0"
#define COPYRIGHT "Copyright (C) 2001 Simon Baldwin\n" \
"This program comes with ABSOLUTELY NO WARRANTY; for details\n" \
"please see the file 'COPYING' supplied with the source code.\n" \
"This is free software, and you are welcome to redistribute it\n" \
"under certain conditions; again, see 'COPYING' for details.\n" \
"This program is released under the GNU General Public License."
#define ASC_NUL '\0' /* End of string */
#define ASC_SPACE ' ' /* ASCII space char */
/* Tone and timing magic numbers. */
#define TONE_MAGIC 1190000 /* Kernel tone delay magic number */
#define DOT_MAGIC 1200000 /* Dot length magic number. The Dot
length is 1200000/WPM Usec */
#define TONE_SILENT 0 /* 0Hz = silent 'tone' */
#define USECS_PER_SEC 1000000 /* Microseconds in a second */
/* True/False macros, for use with int-type (lazy person) "booleans". */
#define FALSE (0)
#define TRUE (!FALSE)
/* Success/Error macros for return codes from public library routines. */
#define RC_SUCCESS CWLIB_SUCCESS
#define RC_ERROR CWLIB_ERROR
/* Other general macros. */
#define INITIAL_FD 1 /* Initial stdout */
#define INITIAL_SEND_SPEED 12 /* Initial send speed in WPM */
#define INITIAL_RECEIVE_SPEED 12 /* Initial receive speed in WPM */
#define INITIAL_FREQUENCY 800 /* Initial tone in Hz */
#define INITIAL_GAP 0 /* Initial gap setting */
#define INITIAL_TOLERANCE 50 /* Initial tolerance setting */
#define INITIAL_ADAPTIVE FALSE /* Initial adaptive receive setting */
#define INITIAL_THRESHOLD (DOT_MAGIC / INITIAL_RECEIVE_SPEED) * 2
/* Initial adaptive speed threshold */
#define INITIAL_NOISE_THRESHOLD (DOT_MAGIC / CW_MAX_SPEED) / 2
/* Initial noise filter threshold */
/*
* Library variables, indicating the user-selected parameters for generating
* Morse code output and receiving Morse code input.
*/
static int cw_file_descriptor
= INITIAL_FD; /* Initially stdout */
static int cw_send_speed= INITIAL_SEND_SPEED;
/* Initially 12 WPM */
static int cw_frequency = INITIAL_FREQUENCY;
/* Initially 800 Hz */
static int cw_gap = INITIAL_GAP; /* Initially no 'Farnsworth' gap */
static int cw_receive_speed
= INITIAL_RECEIVE_SPEED;
/* Initially 12 WPM, fixed speed */
static int cw_tolerance = INITIAL_TOLERANCE;
/* Initially +/-50% on timings */
static int cw_adaptive_receive_enabled
= INITIAL_ADAPTIVE;
/* Initially do fixed speed receive */
static int cw_noise_spike_threshold
= INITIAL_NOISE_THRESHOLD;
/* Initially ignore any tone < 10mS */
/*
* Library variable which is automatically maintained from the Morse input
* stream, rather than being settable by the user.
*/
static int cw_adaptive_receive_threshold
= INITIAL_THRESHOLD;
/* Initially 2-dot threshold for
adaptive speed */
/*
* The following variables must be recalculated each time any of the above
* Morse parameters associated with speeds, gap, tolerance, or threshold
* change. Keeping these in step means that we then don't have to spend time
* calculating them on the fly.
*
* Since they have to be kept in sync, the problem of how to have them
* calculated on first call if none of the above parameters has been
* changed is taken care of with a synchronization flag. Doing this saves
* us from otherwise having to have a 'library initialize' function.
*/
static int cw_in_sync = FALSE;/* Synchronization flag */
/* Sending parameters: */
static int cw_send_dot_length = 0; /* Length of a send Dot, in Usec */
static int cw_send_dash_length = 0; /* Length of a send Dash, in Usec */
static int cw_end_of_ele_delay = 0; /* Extra delay at the end of element */
static int cw_end_of_char_delay = 0; /* Extra delay at the end of a char */
static int cw_additional_delay = 0; /* More delay at the end of a char */
static int cw_end_of_word_delay = 0; /* Extra delay at the end of a word */
/* Receiving parameters: */
static int cw_receive_dot_length= 0; /* Length of a receive Dot, in Usec */
static int cw_receive_dash_length
= 0; /* Length of a receive Dash, in Usec */
static int cw_dot_range_minimum = 0; /* Shortest dot period allowable */
static int cw_dot_range_maximum = 0; /* Longest dot period allowable */
static int cw_dash_range_minimum= 0; /* Shortest dot period allowable */
static int cw_dash_range_maximum= 0; /* Longest dot period allowable */
static int cw_eoe_range_minimum = 0; /* Shortest end of ele allowable */
static int cw_eoe_range_maximum = 0; /* Longest end of ele allowable */
static int cw_eoc_range_minimum = 0; /* Shortest end of char allowable */
static int cw_eoc_range_maximum = 0; /* Longest end of char allowable */
/*
* Debugging flags variable.
*/
static int cw_debug_flags = 0; /* No debug unless requested */
/*
* Morse code characters table. This table allows lookup of the Morse
* shape of a given alphanumeric character. Shapes are held as a string,
* with '-' representing dash, and '.' representing dot. The table ends
* with a NULL entry.
*/
typedef struct {
const unsigned char
character; /* The character represented */
const char *representation;/* Dot-dash shape of the character */
} cw_entry_t;
static const cw_entry_t cw_table[] = {
/* ASCII 7bit letters */
{ 'A', ".-" }, { 'B', "-..." }, { 'C', "-.-." },
{ 'D', "-.." }, { 'E', "." }, { 'F', "..-." },
{ 'G', "--." }, { 'H', "...." }, { 'I', ".." },
{ 'J', ".---" }, { 'K', "-.-" }, { 'L', ".-.." },
{ 'M', "--" }, { 'N', "-." }, { 'O', "---" },
{ 'P', ".--." }, { 'Q', "--.-" }, { 'R', ".-." },
{ 'S', "..." }, { 'T', "-" }, { 'U', "..-" },
{ 'V', "...-" }, { 'W', ".--" }, { 'X', "-..-" },
{ 'Y', "-.--" }, { 'Z', "--.." },
/* Numerals */
{ '0', "-----" }, { '1', ".----" }, { '2', "..---" },
{ '3', "...--" }, { '4', "....-" }, { '5', "....." },
{ '6', "-...." }, { '7', "--..." }, { '8', "---.." },
{ '9', "----." },
/* Punctuation */
{ '"', ".-..-." }, { '\'',".----." }, { '$', "...-..-"},
{ '(', "-.--." }, { ')', "-.--.-" }, { '+', ".-.-." },
{ ',', "--..--" }, { '-', "-....-" }, { '.', ".-.-.-" },
{ '/', "-..-." }, { ':', "---..." }, { ';', "-.-.-." },
{ '=', "-...-" }, { '?', "..--.." }, { '_', "..--.-" },
/* ISO 8859-1 accented characters */
{ 0334,"..--" }, /* U with diaresis */
{ 0304,".-.-" }, /* A with diaeresis */
{ 0307,"-.-.." }, /* C with cedilla */
{ 0326,"---." }, /* O with diaresis */
{ 0311,"..-.." }, /* E with acute */
{ 0310,".-..-" }, /* E with grave */
{ 0300,".--.-" }, /* A with grave */
{ 0321,"--.--" }, /* N with tilde */
/* ISO 8859-2 accented characters */
{ 0252,"----" }, /* S with cedilla */
{ 0256,"--..-" }, /* Z with dot above */
/* Sentinel end of table value */
{ ASC_NUL, NULL } };
/*
* External keying function. It is useful for a client to be able to have
* this library control an external keying device, for example, an oscill-
* ator, or a transmitter. Here is where we keep the address of a function
* that is passed to us for this purpose.
*/
static void (*cw_kk_key_callback) (int) = NULL;
/* Callback function for key control */
/*
* The library registers a single central SIGALRM handler. This handler will
* call all of the functions on a list sequentially on each SIGALRM received.
* This is where the list is kept. We also use a flag to tell us if the
* SIGALRM handler is installed, and a place to keep the old SIGALRM
* disposition, just so we can tidy it back up to how it was when the library
* decides it can stop handling SIGALRM for a while.
*/
#define SIGALRM_HANDLERS 32 /* More than enough handlers */
static void (*cw_request_handlers[ SIGALRM_HANDLERS ]) (int);
/* List of low level handlers */
static int cw_sigalrm_handler_installed = FALSE;
/* Flag indicating handler installed */
static struct sigaction
cw_sigalrm_original_disposition;
/* Saved SIGALRM disposition */
/*
* Tone queue. This is a circular list of tone durations and frequencies
* pending, and a pair of indexes, head (enqueue) and tail (dequeue) to
* manage additions and asynchronous sending.
*/
#define TONE_QUEUE_CAPACITY 3000 /* ~= 5 minutes at 12 WPM */
#define TONE_QUEUE_HIGH_WATER_MARK \
2900 /* Refuse characters if <100 free*/
typedef struct {
int usec; /* Tone duration in usecs */
int frequency; /* Frequency of the tone */
} cw_queued_tone_t;
static cw_queued_tone_t cw_tone_queue[ TONE_QUEUE_CAPACITY ];
static int cw_tq_head = 0; /* Tone queue head index */
static int cw_tq_tail = 0; /* Tone queue head index */
/*
* It's useful to have the tone queue dequeue function call a client-
* supplied callback routine when the amount of data in the queue drops
* below a defined low water mark. This routine can then refill the
* buffer, as required.
*/
static int cw_tq_low_water_mark = 0;
/* Low water mark definition */
static void (*cw_tq_low_water_callback) (void) = NULL;
/* Callback function for low water */
/*
* Receive buffering. This is a fixed-length representation, filled in
* as tone on/off timings are taken.
*/
#define RECEIVE_CAPACITY 256 /* Way longer than any representation */
static char cw_receive_representation_buffer[ RECEIVE_CAPACITY ];
static int cw_rr_current = 0;
/* Receive buffer current location */
static struct timeval cw_rr_start_timestamp = {0, 0};
/* Tone start timestamp */
static struct timeval cw_rr_end_timestamp = {0, 0};
/* Tone end timestamp */
/*
* Receive adaptive speed tracking. We keep a small array of dot lengths,
* and a small array of dash lengths. We also keep a running sum of the
* elements of each array, and an index to the current array position.
*/
#define AVERAGE_ARRAY_LENGTH 4 /* Keep four dot/dash lengths */
static int cw_dot_tracking_array[ AVERAGE_ARRAY_LENGTH ];
static int cw_dash_tracking_array[ AVERAGE_ARRAY_LENGTH ];
/* Dot and dash length arrays */
static int cw_dt_dot_index = 0;
static int cw_dt_dash_index = 0; /* Circular indexes into the arrays */
static int cw_dt_dot_tracking_sum = 0;
static int cw_dt_dash_tracking_sum = 0;
/* Running sum of array members */
/*
* Iambic keyer status. The keyer functions maintain the current known state
* of the paddles, and latch FALSE-to-TRUE transitions while busy, to form the
* iambic effect. For Curtis mode B, the keyer also latches any point where
* both paddle states are TRUE at the same time.
*/
static int cw_ik_dot_paddle = FALSE;/* Current dot paddle state */
static int cw_ik_dash_paddle = FALSE;/* Current dash paddle state */
static int cw_ik_dot_latch = FALSE;/* Dot FALSE->TRUE latch */
static int cw_ik_dash_latch = FALSE;/* Dash FALSE->TRUE latch */
static int cw_ik_curtis_b_latch = FALSE;/* Curtis Dot&&Dash latch */
/*
* Iambic keyer "Curtis" mode A/B selector. Mode A and mode B timings differ
* slightly, and some people have a preference for one or the other. Mode A
* is a bit less timing-critical, so we'll make that the default.
*/
static int cw_ik_curtis_mode_b = FALSE;
/*
* Straight key status. Just a key-up or key-down indication. Real simple.
*/
static int cw_sk_key_down = FALSE;/* Indicates key up or down */
/**
* cw_version()
*
* Returns the version number of the library. Version numbers are returned
* as an int, composed of Major_version << 16 | Minor_version.
*/
int
cw_version ()
{
return MAJOR_VERSION << 16 | MINOR_VERSION;
}
/**
* cw_license()
*
* Prints a short library licensing message to stdout.
*/
void
cw_license ()
{
printf ("%s, ", VERSION);
printf ("%s\n", COPYRIGHT);
}
/**
* cw_set_debug_flags()
*
* Sets a value for the library debug flags. Debug output is generally
* strings printed on stderr. There is no validation of flags.
*/
void
cw_set_debug_flags (int new_value)
{
cw_debug_flags = new_value;
}
/**
* cw_get_debug_flags()
*
* Retrieves library debug flags. If no flags are set, then on first
* call, it will check the environment variable CWLIB_DEBUG, and if it
* is available, will set debug flags to its value. The provides a way
* for a program to set the debug flags without needing to make any source
* code changes.
*/
int
cw_get_debug_flags ()
{
static int cwlib_debug_checked
= FALSE;/* Initialization flag */
char *debug_value; /* Value of CWLIB_DEBUG */
/* If already done, simply ignore the call. */
if (!cwlib_debug_checked)
{
/* Do not overwrite any debug flags already set. */
if (cw_debug_flags == 0)
{
/*
* Set the debug flags from CWLIB_DEBUG. If it is
* an invalid numeric, treat it as 0; there is no
* error checking.
*/
debug_value = getenv ("CWLIB_DEBUG");
if (debug_value != NULL)
cw_debug_flags = atoi (debug_value);
}
/* Set checked flag, so we never do this again. */
cwlib_debug_checked = TRUE;
}
/* Return the flags setting. */
return cw_debug_flags;
}
/**
* cw_get_[speed|frequency|gap|tolerance]_limits()
*
* Return the limits on the speed, frequency, gap, and tolerance parameters.
* Normal values are speed 4-60 WPM, frequency 0-10,000 Hz, gap 0-20 dots,
* and tolerance 0-90 %.
*/
void
cw_get_speed_limits (int *min_speed, int *max_speed)
{
if (min_speed != NULL)
*min_speed = CW_MIN_SPEED;
if (max_speed != NULL)
*max_speed = CW_MAX_SPEED;
}
void
cw_get_frequency_limits (int *min_frequency, int *max_frequency)
{
if (min_frequency != NULL)
*min_frequency = CW_MIN_FREQUENCY;
if (max_frequency != NULL)
*max_frequency = CW_MAX_FREQUENCY;
}
void
cw_get_gap_limits (int *min_gap, int *max_gap)
{
if (min_gap != NULL)
*min_gap = CW_MIN_GAP;
if (max_gap != NULL)
*max_gap = CW_MAX_GAP;
}
void
cw_get_tolerance_limits (int *min_tolerance, int *max_tolerance)
{
if (min_tolerance != NULL)
*min_tolerance = CW_MIN_TOLERANCE;
if (max_tolerance != NULL)
*max_tolerance = CW_MAX_TOLERANCE;
}
/**
* cw_sync_parameters_internal()
*
* Synchronize the dot, dash, end of element, end of character, and end
* of word timings and ranges to new values of Morse speed, 'Farnsworth'
* gap, or receive tolerance.
*/
static void
cw_sync_parameters_internal ()
{
/* Do nothing if we are already synchronized with speed/gap. */
if (!cw_in_sync)
{
/*
* Send parameters:
*
* Calculate the length of a Dot as 1200000 / speed in wpm,
* and the length of a Dash as three Dot lengths.
*/
cw_send_dot_length = DOT_MAGIC / cw_send_speed;
cw_send_dash_length = 3 * cw_send_dot_length;
/*
* An end of element length is one Dot, end of character is
* three Dots total, and end of word is seven Dots total.
*/
cw_end_of_ele_delay = cw_send_dot_length;
cw_end_of_char_delay = 3 * cw_send_dot_length
- cw_end_of_ele_delay;
cw_end_of_word_delay = 7 * cw_send_dot_length
- cw_end_of_char_delay;
cw_additional_delay = cw_gap * cw_send_dot_length;
/* Print out if debug requested. */
if (cw_get_debug_flags () & CW_DEBUG_PARAMETERS)
fprintf (stderr,
"cw: send usec timings <%d>:"
" %d, %d, %d, %d, %d, %d\n",
cw_send_speed,
cw_send_dot_length, cw_send_dash_length,
cw_end_of_ele_delay, cw_end_of_char_delay,
cw_end_of_word_delay, cw_additional_delay);
/*
* Receive parameters:
*
* First, depending on whether we are set for fixed speed or
* adaptive speed, calculate either the threshold from the
* receive speed, or the receive speed from the threshold,
* knowing that the threshold is always, effectively, two
* dot lengths.
*/
if (cw_adaptive_receive_enabled)
cw_receive_speed = DOT_MAGIC
/ (cw_adaptive_receive_threshold / 2);
else
cw_adaptive_receive_threshold = 2 * DOT_MAGIC
/ cw_receive_speed;
/*
* Calculate the basic receive dot and dash lengths.
*/
cw_receive_dot_length = DOT_MAGIC / cw_receive_speed;
cw_receive_dash_length = 3 * cw_receive_dot_length;
/*
* Set the ranges of respectable timing elements depending
* very much on whether we are required to adapt to the
* incoming Morse code speeds.
*/
if (cw_adaptive_receive_enabled)
{
/*
* For adaptive timing, calculate the Dot and Dash
* timing ranges as zero to two Dots is a Dot, and
* anything, anything at all, larger than this is a
* Dash.
*/
cw_dot_range_minimum = 0;
cw_dot_range_maximum = 2 * cw_receive_dot_length;
cw_dash_range_minimum = cw_dot_range_maximum;
cw_dash_range_maximum = INT_MAX;
/*
* Make the inter-element gap be anything up to the
* adaptive threshold lengths - that is two Dots. And
* the end of character gap is anything longer than
* that, and shorter than two receive thresholds (that
* is, four Dots).
*/
cw_eoe_range_minimum = cw_dot_range_minimum;
cw_eoe_range_maximum = cw_dot_range_maximum;
cw_eoc_range_minimum = cw_eoe_range_maximum;
cw_eoc_range_maximum = 4 * cw_receive_dot_length;
}
else
{
/*
* For fixed speed receiving, calculate the Dot timing
* range as the Dot length +/- dot*tolerance%, and the
* Dash timing range as the Dash length including
* +/- dot*tolerance% as well.
*/
cw_dot_range_minimum = cw_receive_dot_length
- (cw_receive_dot_length * cw_tolerance) / 100;
cw_dot_range_maximum = cw_receive_dot_length
+ (cw_receive_dot_length * cw_tolerance) / 100;
cw_dash_range_minimum = cw_receive_dash_length
- (cw_receive_dot_length * cw_tolerance) / 100;
cw_dash_range_maximum = cw_receive_dash_length
+ (cw_receive_dot_length * cw_tolerance) / 100;
/*
* Make the inter-element gap the same as the Dot range.
* Make the inter-character gap, expected to be three
* Dots, the same as Dash range at the lower end, but
* make it the same as the Dash range _plus_ the
* 'Farnsworth' delay at the top of the range.
*
* Any gap longer than this is by implication
* inter-word.
*/
cw_eoe_range_minimum = cw_dot_range_minimum;
cw_eoe_range_maximum = cw_dot_range_maximum;
cw_eoc_range_minimum = cw_dash_range_minimum;
cw_eoc_range_maximum = cw_dash_range_maximum
+ cw_additional_delay;
}
/* Print out if debug requested. */
if (cw_get_debug_flags () & CW_DEBUG_PARAMETERS)
fprintf (stderr,
"cw: receive usec timings <%d>: "
"%d-%d, %d-%d, %d-%d, %d-%d, %d\n",
cw_receive_speed,
cw_dot_range_minimum, cw_dot_range_maximum,
cw_dash_range_minimum, cw_dash_range_maximum,
cw_eoe_range_minimum, cw_eoe_range_maximum,
cw_eoc_range_minimum, cw_eoc_range_maximum,
cw_adaptive_receive_threshold);
/* Set the parameters in sync flag. */
cw_in_sync = TRUE;
}
}
/**
* cw_[gs]et_[send_speed|receive_speed|frequency|gap|tolerance|device]()
*
* Get and set routines for all the Morse code parameters available to
* control the library. Set routines return 0 on success, or -1 on failure,
* with errno set to indicate the problem, usually EINVAL, except for
* cw_set_device, which returns the errno from the KIOCSOUND ioctl call,
* and cw_set_receive_speed, which returns EINVAL if the new value is
* invalid, or EPERM if the receive mode is currently set for adaptive
* receive speed tracking. Get routines simply return the current value.
*
* The default values of the parameters where none are explicitly set are
* send/receive speed 12 WPM, frequency 800 Hz, gap 0 dots, tolerance 50 %,
* and device set to standard output (file descriptor 1).
*/
int
cw_set_send_speed (int new_value)
{
if (new_value < CW_MIN_SPEED || new_value > CW_MAX_SPEED)
{
errno = EINVAL;
return RC_ERROR;
}
cw_send_speed = new_value;
/* Changes of speed, gap, and tolerance require resynchronization. */
cw_in_sync = FALSE; cw_sync_parameters_internal ();
return RC_SUCCESS;
}
int
cw_set_receive_speed (int new_value)
{
if (cw_adaptive_receive_enabled)
{
errno = EPERM;
return RC_ERROR;
}
else
{
if (new_value < CW_MIN_SPEED || new_value > CW_MAX_SPEED)
{
errno = EINVAL;
return RC_ERROR;
}
}
cw_receive_speed = new_value;
/* Changes of speed, gap, and tolerance require resynchronization. */
cw_in_sync = FALSE; cw_sync_parameters_internal ();
return RC_SUCCESS;
}
int
cw_set_frequency (int new_value)
{
if (new_value < CW_MIN_FREQUENCY || new_value > CW_MAX_FREQUENCY)
{
errno = EINVAL;
return RC_ERROR;
}
cw_frequency = new_value;
return RC_SUCCESS;
}
int
cw_set_gap (int new_value)
{
if (new_value < CW_MIN_GAP || new_value > CW_MAX_GAP)
{
errno = EINVAL;
return RC_ERROR;
}
cw_gap = new_value;
/* Changes of speed, gap, and tolerance require resynchronization. */
cw_in_sync = FALSE; cw_sync_parameters_internal ();
return RC_SUCCESS;
}
int
cw_set_tolerance (int new_value)
{
if (new_value < CW_MIN_TOLERANCE || new_value > CW_MAX_TOLERANCE)
{
errno = EINVAL;
return RC_ERROR;
}
cw_tolerance = new_value;
/* Changes of speed, gap, and tolerance require resynchronization. */
cw_in_sync = FALSE; cw_sync_parameters_internal ();
return RC_SUCCESS;
}
int
cw_set_file_descriptor (int new_value)
{
if (!(cw_get_debug_flags () & CW_DEBUG_SILENT))
{
if (ioctl (new_value, KIOCSOUND, 0) == -1)
{
return RC_ERROR;
}
}
cw_file_descriptor = new_value;
return RC_SUCCESS;
}
int
cw_get_send_speed ()
{
return cw_send_speed;
}
int
cw_get_receive_speed ()
{
return cw_receive_speed;
}
int
cw_get_frequency ()
{
return cw_frequency;
}
int
cw_get_gap ()
{
return cw_gap;
}
int
cw_get_tolerance ()
{
return cw_tolerance;
}
int
cw_get_file_descriptor ()
{
return cw_file_descriptor;
}
/**
* cw_set_adaptive_receive_internal()
*
* Set the value of the flag that controls whether, on receive, the receive
* functions do fixed speed receive, or track the speed of the received Morse
* code by adapting to the input stream.
*/
static void
cw_set_adaptive_receive_internal (int flag)
{
int index; /* Averaging arrays index */
/* Look for change of adaptive receive state. */
if ((cw_adaptive_receive_enabled && !flag)
|| (!cw_adaptive_receive_enabled && flag))
{
cw_adaptive_receive_enabled = flag;
/* Changing the flag forces a change in low-level parameters. */
cw_in_sync = FALSE; cw_sync_parameters_internal ();
/*
* If we have just switched to adaptive mode, (re-)initialize
* the averages array to the current dot/dash lengths, so that
* initial averages match the current speed. And reset the
* running sums too.
*/
if (cw_adaptive_receive_enabled)
{
for (index = 0; index < AVERAGE_ARRAY_LENGTH; index++)
{
cw_dot_tracking_array[index]
= cw_receive_dot_length;
cw_dash_tracking_array[index]
= cw_receive_dash_length;
}
cw_dt_dot_tracking_sum = cw_receive_dot_length
* AVERAGE_ARRAY_LENGTH;
cw_dt_dash_tracking_sum = cw_receive_dash_length
* AVERAGE_ARRAY_LENGTH;
}
}
}
/**
* cw_enable_adaptive_receive()
* cw_disable_adaptive_receive()
* cw_get_adaptive_receive_state()
*
* Enable and disable adaptive receive speeds. If adaptive speed tracking
* is enabled, the receive functions will attempt to automatically adjust
* the receive speed setting to match the speed of the incoming Morse code.
* If it is disabled, the receive functions will use fixed speed settings,
* and reject incoming Morse which is not at the expected speed. The
* cw_get_adaptive_receive_state function returns TRUE if adaptive speed
* tracking is enabled, FALSE otherwise. The default state is adaptive
* speed tracking disabled.
*/
void
cw_enable_adaptive_receive ()
{
cw_set_adaptive_receive_internal (TRUE);
}
void
cw_disable_adaptive_receive ()
{
cw_set_adaptive_receive_internal (FALSE);
}
int
cw_get_adaptive_receive_state ()
{
return cw_adaptive_receive_enabled;
}
/**
* cw_enable_iambic_curtis_mode_b()
* cw_disable_iambic_curtis_mode_b()
* cw_get_iambic_curtis_mode_b_state()
*
* Normally, the iambic keying functions will emulate Curtis 8044 Keyer
* mode A. In this mode, when both paddles are pressed together, the last
* dot or dash being sent on release is completed, and nothing else is sent.
* In mode B, when both paddles are pressed together, the last dot or dash
* being sent on release is completed, then an opposite element is also sent.
* Some operators prefer mode B, but timing is more critical in this mode.
* The default mode is Curtis mode A.
*/
void
cw_enable_iambic_curtis_mode_b ()
{
cw_ik_curtis_mode_b = TRUE;
}
void
cw_disable_iambic_curtis_mode_b ()
{
cw_ik_curtis_mode_b = FALSE;
}
int
cw_get_iambic_curtis_mode_b ()
{
return cw_ik_curtis_mode_b;
}
/**
* cw_[gs]et_noise_spike_threshold()
*
* Set and get the period shorter than which, on receive, received tones are
* ignored. This allows the receive tone functions to apply noise cancelling
* for very short apparent tones. For useful results the value should never
* exceed the dot length of a dot at maximum speed; 20,000 Usec (the dot
* length at 60WPM). Setting a noise threshold of zero turns off receive
* tone noise cancelling. The default noise spike threshold is 10,000 Usec.
*/
int
cw_set_noise_spike_threshold (int threshold)
{
if (threshold < 0)
{
errno = EINVAL;
return RC_ERROR;
}
cw_noise_spike_threshold = threshold;
return RC_SUCCESS;
}
int
cw_get_noise_spike_threshold ()
{
return cw_noise_spike_threshold;
}
/**
* cw_get_send_parameters()
* cw_get_receive_parameters()
*
* Return the low-level timing parameters calculated from the speed, gap,
* and tolerance set. Parameter values are returned in usecs. Use NULL
* for the pointer argument to any parameter value not required.
*/
void
cw_get_send_parameters (int *dot_usecs, int *dash_usecs,
int *end_of_element_usecs, int *end_of_character_usecs,
int *end_of_word_usecs, int *additional_usecs)
{
cw_sync_parameters_internal ();
if (dot_usecs != NULL)
*dot_usecs = cw_send_dot_length;
if (dash_usecs != NULL)
*dash_usecs = cw_send_dash_length;
if (end_of_element_usecs != NULL)
*end_of_element_usecs = cw_end_of_ele_delay;
if (end_of_character_usecs != NULL)
*end_of_character_usecs = cw_end_of_char_delay;
if (end_of_word_usecs != NULL)
*end_of_word_usecs = cw_end_of_word_delay;
if (additional_usecs != NULL)
*additional_usecs = cw_additional_delay;
}
void
cw_get_receive_parameters (int *dot_usecs, int *dash_usecs,
int *dot_min_usecs, int *dot_max_usecs,
int *dash_min_usecs, int *dash_max_usecs,
int *end_of_element_min_usecs,
int *end_of_element_max_usecs,
int *end_of_character_min_usecs,
int *end_of_character_max_usecs,
int *adaptive_threshold)
{
cw_sync_parameters_internal ();
if (dot_usecs != NULL)
*dot_usecs = cw_receive_dot_length;
if (dash_usecs != NULL)
*dash_usecs = cw_receive_dash_length;
if (dot_min_usecs != NULL)
*dot_min_usecs = cw_dot_range_minimum;
if (dot_max_usecs != NULL)
*dot_max_usecs = cw_dot_range_maximum;
if (dash_min_usecs != NULL)
*dash_min_usecs = cw_dash_range_minimum;
if (dash_max_usecs != NULL)
*dash_max_usecs = cw_dash_range_maximum;
if (end_of_element_min_usecs != NULL)
*end_of_element_min_usecs = cw_eoe_range_minimum;
if (end_of_element_max_usecs != NULL)
*end_of_element_max_usecs = cw_eoe_range_maximum;
if (end_of_character_min_usecs != NULL)
*end_of_character_min_usecs = cw_eoc_range_minimum;
if (end_of_character_max_usecs != NULL)
*end_of_character_max_usecs = cw_eoc_range_maximum;
if (adaptive_threshold != NULL)
*adaptive_threshold = cw_adaptive_receive_threshold;
}
/**
* cw_set_console_sound()
*
* Routine to enable/disable console sound. This function simply sets the
* value of the related debug flag. The default is enabled sound.
*/
void
cw_set_console_sound (int sound_state)
{
/* Get flags the proper way to read CWLIB_DEBUG. */
cw_get_debug_flags ();
/* Or in, or and out, the silent running bit. */
if (!sound_state)
cw_debug_flags |= CW_DEBUG_SILENT;
else
cw_debug_flags &= ~CW_DEBUG_SILENT;
}
/**
* cw_sound_internal()
*
* Call the console kiocsound ioctl to start a particular tone generating
* in the kernel, and return the status. Routines running inside signal
* handlers are free to ignore the status. The routine does nothing if
* silence is requested in the library flags.
*/
static int
cw_sound_internal (int frequency)
{
int kiocsound_arg; /* Argument for KIOCSOUND */
/* If silence requested, then ignore the call. */
if (!(cw_get_debug_flags () & CW_DEBUG_SILENT))
{
/* Calculate the correct argument for KIOCSOUND. */
if (frequency != TONE_SILENT)
kiocsound_arg = TONE_MAGIC / frequency;
else
kiocsound_arg = 0;
/* Print out any requested debug on sound. */
if (cw_get_debug_flags () & CW_DEBUG_SOUND)
fprintf (stderr, "cw: kiocsound %d Hz, %d\n",
frequency, kiocsound_arg);
/* Call the ioctl, and return any error status. */
if (ioctl (cw_file_descriptor, KIOCSOUND, kiocsound_arg) == -1)
{
perror ("cw: ioctl KIOCSOUND");
return RC_ERROR;
}
}
return RC_SUCCESS;
}
/**
* cw_keying_callback()
*
* Register a function that should be called when a tone state changes
* from key-up to key-down, or vice-versa. The argument passed out to
* the registered function is the key state: TRUE for down, FALSE for up.
* Calling this routine with an NULL function address disables keying
* callbacks.
*/
void
cw_keying_callback (void (*callback_func) (int))
{
cw_kk_key_callback = callback_func;
}
/**
* cw_key_control_internal()
*
* Control function that calls any requested keying callback only when
* there is a change of keying state. This function filters successive
* key-down or key-up actions into a single action.
*/
static void
cw_key_control_internal (int requested_key_state)
{
static int current_key_state = FALSE;
/* Maintain key control state */
/* Ignore the call if there is no change of keying state. */
if (current_key_state != requested_key_state)
{
/* Print out any requested debug on keying. */
if (cw_get_debug_flags () & CW_DEBUG_KEYING)
fprintf (stderr, "cw: keying state %d->%d\n",
current_key_state, requested_key_state);
/* Set the new keying state, and call any requested callback. */
current_key_state = requested_key_state;
if (cw_kk_key_callback != NULL)
(*cw_kk_key_callback) (current_key_state);
}
}
/**
* cw_sigalrm_handler_internal()
*
* Common SIGALRM handler. This function calls the signal handlers of
* the library subsystems, expecting them to ignore unexpected calls.
*/
static void
cw_sigalrm_handler_internal (int sig)
{
int index; /* Low level handler index */
/*
* Call the known functions that are interested in this signal.
* Stop on the first free slot found; valid because the array is
* filled in order from index 0, and there are no deletions.
*/
for (index = 0; index < SIGALRM_HANDLERS
&& cw_request_handlers[index] != NULL; index++)
(*(cw_request_handlers[index])) (sig);
}
/**
* cw_request_timeout_internal()
*
* Install the SIGALRM handler, if not yet installed. Add any given lower
* level handler to the list of registered handlers. Then set an itimer
* to expire after the requested number of usecs.
*/
static int
cw_request_timeout_internal (int usec, void (*request_handler) (int))
{
int error; /* Error status */
int index; /* Low level handler index */
struct sigaction action; /* Sigaction structure */
struct itimerval itimer; /* Itimer control structure */
/* Don't install the handler if we have already done it. */
if (!cw_sigalrm_handler_installed)
{
/*
* Register the SIGALRM handler routine, and keep the old
* information so we can put it back when useful to do so.
*/
action.sa_handler = cw_sigalrm_handler_internal;
action.sa_flags = SA_RESTART;
sigemptyset (&action.sa_mask);
error = sigaction (SIGALRM, &action,
&cw_sigalrm_original_disposition);
if (error == -1)
{
perror ("cw: sigaction");
return RC_ERROR;
}
/* Set the flag so we don't do this again. */
cw_sigalrm_handler_installed = TRUE;
}
/*
* If it's not already present, and one was given, add the request
* handler address to the list of known handlers.
*/
if (request_handler != NULL)
{
/* Search for this handler, or the first free entry. */
for (index = 0; index < SIGALRM_HANDLERS
&& cw_request_handlers[index] != request_handler
&& cw_request_handlers[index] != NULL; )
index++;
/*
* If the handler is already there, do no more. Otherwise,
* add it to the list of lower level handlers.
*/
if (cw_request_handlers[index] != request_handler)
{
if (cw_request_handlers[index] != NULL)
{
errno = ENOMEM;
return RC_ERROR;
}
cw_request_handlers[index] = request_handler;
}
}
/*
* Depending on the value of usec, either set an itimer, or send
* ourselves SIGALRM right away.
*/
if (usec <= 0)
{
/* Send ourselves the SIGALRM immediately. */
if (kill (getpid(), SIGALRM) != 0)
{
perror ("cw: kill");
return RC_ERROR;
}
}
else
{
/*
* Set the itimer to produce a single interrupt after the given
* duration.
*/
itimer.it_interval.tv_sec = 0;
itimer.it_interval.tv_usec = 0;
itimer.it_value.tv_sec = usec / USECS_PER_SEC;
itimer.it_value.tv_usec = usec % USECS_PER_SEC;
error = setitimer (ITIMER_REAL, &itimer, NULL);
if (error == -1)
{
perror ("cw: setitimer");
return RC_ERROR;
}
}
return RC_SUCCESS;
}
/**
* cw_release_timeouts_internal()
*
* Uninstall the SIGALRM handler, if installed. Return SIGALRM's disposition
* for the system to the state we found it in before we installed our own
* SIGALRM handler.
*/
static int
cw_release_timeouts_internal ()
{
int error; /* Error status */
/* Ignore the call if we haven't installed our handler. */
if (cw_sigalrm_handler_installed)
{
/* Put back the SIGALRM information saved earlier. */
error = sigaction (SIGALRM, &cw_sigalrm_original_disposition,
NULL );
if (error == -1)
{
perror ("cw: sigaction");
return RC_ERROR;
}
/*
* Clear the flag so we know to reinstall the handler when
* we get the next timeout request.
*/
cw_sigalrm_handler_installed = FALSE;
}
return RC_SUCCESS;
}
/**
* cw_check_signal_mask_internal()
*
* Check the signal mask of the process, and return an error, with errno
* set to EDEADLK, if SIGALRM is blocked.
*/
static int
cw_check_signal_mask_internal ()
{
int error; /* Error status */
sigset_t emptyset; /* Empty sigset structure */
sigset_t currset; /* Sigset for current state */
/* Block a empty set of signals to obtain the current mask. */
sigemptyset (&emptyset);
error = sigprocmask (SIG_BLOCK, &emptyset, &currset);
if (error == -1)
{
perror ("cw: sigprocmask");
return RC_ERROR;
}
/* Check that SIGALRM is not blocked in the current mask. */
if (sigismember (&currset, SIGALRM))
{
errno = EDEADLK;
return RC_ERROR;
}
return RC_SUCCESS;
}
/**
* cw_block_signal_internal()
*
* Block SIGALRM for the duration of certain critical sections, or unblock
* after; passed TRUE to block SIGALRM, and FALSE to unblock.
*/
static int
cw_block_signal_internal (int block)
{
int error; /* Error status */
sigset_t blockset; /* Block sigset structure */
/* Block SIGALRM for the process. */
sigemptyset (&blockset);
sigaddset (&blockset, SIGALRM);
error = sigprocmask (block ? SIG_BLOCK : SIG_UNBLOCK, &blockset, NULL);
if (error == -1)
{
perror ("cw: sigprocmask");
return RC_ERROR;
}
return RC_SUCCESS;
}
/**
* cw_signal_wait_internal()
*
* Wait for a signal, usually a SIGALRM. Assumes SIGALRM is not blocked.
*/
static int
cw_signal_wait_internal ()
{
int error; /* Error status */
sigset_t emptyset; /* Empty sigset structure */
sigset_t currset; /* Sigset for current state */
/* Block a empty set of signals to obtain the current mask. */
sigemptyset (&emptyset);
error = sigprocmask (SIG_BLOCK, &emptyset, &currset);
if (error == -1)
{
perror ("cw: sigprocmask");
return RC_ERROR;
}
/* Wait on the current mask. */
error = sigsuspend (&currset);
if (error == -1 && errno != EINTR)
{
perror ("cw: sigsuspend");
return RC_ERROR;
}
return RC_SUCCESS;
}
/*
* cw_dequeue_tone_internal implements the following (trivial) state graph:
*
* (queue empty)
* +-------------------------------+
* | |
* v (queue started) |
* --> QS_IDLE ---------------> QS_BUSY --+
* ^ |
* | |
* +-----+
* (queue not empty)
*/
static enum {QS_IDLE,QS_BUSY} cw_dequeue_state = QS_IDLE;
/* Indicates empty queue */
/**
* cw_dequeue_tone_internal()
*
* Signal handler for itimer. Dequeue a tone request, and send the ioctl
* to generate the tone. If the queue is empty when we get the signal,
* then we're at the end of the work list, so set the dequeue state to
* idle and return.
*/
static void
cw_dequeue_tone_internal (int sig)
{
int usec; /* Next tone duration */
int frequency; /* Next tone frequency */
int queue_length; /* Queued tones at the start */
int now_length; /* Queued tones after scan */
/* Ignore the call if the current state is idle. */
if (cw_dequeue_state == QS_IDLE)
return;
/* See if the queue contains any pending tones. */
if (cw_tq_tail != cw_tq_head)
{
/*
* Calculate the current queue length. Later on, we'll
* compare with the length after we've scanned over every
* tone we can omit, and use this to see if we've crossed
* the low water mark, if any.
*/
if (cw_tq_head >= cw_tq_tail)
queue_length = cw_tq_head - cw_tq_tail;
else
queue_length = cw_tq_head - cw_tq_tail
+ TONE_QUEUE_CAPACITY;
/*
* Advance over the tones list until we find the first tone
* with a duration of more than zero usecs, or until the end
* of the list.
*/
do
{
if (cw_tq_tail + 1 < TONE_QUEUE_CAPACITY)
cw_tq_tail++;
else
cw_tq_tail = 0;
}
while (cw_tq_tail != cw_tq_head
&& cw_tone_queue[cw_tq_tail].usec == 0);
/* Dequeue the next tone to send. */
usec = cw_tone_queue[cw_tq_tail].usec;
frequency = cw_tone_queue[cw_tq_tail].frequency;
/* Print out any requested debug on the tone started. */
if (cw_get_debug_flags () & CW_DEBUG_TONE_QUEUE)
fprintf (stderr, "cw: dequeue tone %d usec, %d Hz\n",
usec, frequency);
/*
* Start the tone. If the ioctl fails, there's nothing we
* can do at this point, in the way of returning error codes.
*/
cw_sound_internal (frequency);
/*
* Notify the key control function that there might have
* been a change of keying state (and then again, there
* might not have been - it will sort this out for us).
*/
if (frequency != TONE_SILENT)
cw_key_control_internal (TRUE);
else
cw_key_control_internal (FALSE);
/*
* If microseconds is zero, leave it at that. This way, a
* queued tone of 0 usec implies leaving the sound in this
* state, and 0 usec and 0 frequency leaves silence.
*/
if (usec > 0)
/*
* Request a timeout. If it fails, there's little
* we can do at this point. But it shouldn't fail.
*/
cw_request_timeout_internal (usec, NULL);
else
{
/* Autonomous dequeuing has finished for the moment. */
cw_dequeue_state = QS_IDLE;
cw_release_timeouts_internal();
}
/*
* If there is a low water mark callback registered, and if
* we passed under the water mark, call the callback here.
* We want to be sure to call this late in the processing,
* especially after setting the state to idle, since the most
* likely action of this routine is to queue tones, and we
* don't want to play with the state here after that.
*/
if (cw_tq_low_water_callback != NULL)
{
/* Calculate the current queue length. */
if (cw_tq_head >= cw_tq_tail)
now_length = cw_tq_head - cw_tq_tail;
else
now_length = cw_tq_head - cw_tq_tail
+ TONE_QUEUE_CAPACITY;
/*
* If the length we originally calculated was above
* the low water mark, and the one we have now is
* below or equal to it, call the callback.
*/
if (queue_length > cw_tq_low_water_mark
&& now_length <= cw_tq_low_water_mark)
(cw_tq_low_water_callback) ();
}
}
else
{
/*
* This is the end of the last tone on the queue, and since
* we got a signal we know that it had a usec greater than
* zero. So this is the time to return to silence.
*/
cw_sound_internal (TONE_SILENT);
/* Notify the keying control function, as above. */
cw_key_control_internal (FALSE);
/*
* Set the flag that indicates that autonomous dequeueing
* has finished for the moment. We need this set whenever
* the queue indexes are equal and there is no pending
* itimeout.
*/
cw_dequeue_state = QS_IDLE;
cw_release_timeouts_internal();
}
}
/**
* cw_queue_tone_internal()
*
* Enqueue a tone for specified frequency and number of microseconds. This
* routine adds the new tone to the queue, and if necessary starts the
* itimer process to have the tone sent. The routine returns 0 on success.
* If the tone queue is full, the routine returns -1, with errno set to
* EAGAIN. If the iambic keyer or straight key are currently busy, the
* routine returns -1, with errno set to EBUSY.
*/
static int
cw_queue_tone_internal (int usec, int frequency)
{
int new_tq_head; /* New value of head index */
/*
* If the keyer or straight key are busy, return an error. This is
* because they use the console tones and key control, and will
* interfere with us if we try to use them at the same time.
*/
if (cw_keyer_busy () || cw_straightkey_busy ())
{
errno = EBUSY;
return RC_ERROR;
}
/*
* If this is the first call, there's a possibility that the sound
* device is still the default (stdout), and that may well not be
* a console. At this point, we could, say, on first call, check
* with a call to KIOCSOUND, or similar, that stdout will do sound.
* However, even if we check it now, we can't check it on each
* call, since that would disrupt current tones. And there's
* nothing preventing a client from giving us a usable console file
* descriptor, then closing it, duping it, or whatever, in such a
* way that we can no longer do sound, and then there's nothing we
* can do about it. So... in practice, we'll do NO checking here
* at all, and if any of the above disasters happen, each call
* to ioctl KIOCSOUND will spit out an error to stderr, and it
* should become pretty obvious what the problem is.
*/
/* Calculate the new value of the queue head index. */
if (cw_tq_head + 1 < TONE_QUEUE_CAPACITY)
new_tq_head = cw_tq_head + 1;
else
new_tq_head = 0;
/*
* If the new value is bumping against the tail index, then the
* queue is currently full, so return EAGAIN.
*/
if (new_tq_head == cw_tq_tail)
{
errno = EAGAIN;
return RC_ERROR;
}
/* Print out any requested debug on the tone being queued. */
if (cw_get_debug_flags () & CW_DEBUG_TONE_QUEUE)
fprintf (stderr, "cw: enqueue tone %d usec, %d Hz\n",
usec, frequency);
/* Enqueue the new tone. */
cw_tone_queue[new_tq_head].usec = usec;
cw_tone_queue[new_tq_head].frequency = frequency;
/*
* If there is currently no autonomous dequeue happening, set the
* new head index and kick off the itimer process. Otherwise,
* just set the new head index.
*/
if (cw_dequeue_state == QS_IDLE)
{
cw_tq_head = new_tq_head;
cw_dequeue_state = QS_BUSY;
cw_request_timeout_internal
(0, cw_dequeue_tone_internal);
}
else
cw_tq_head = new_tq_head;
return RC_SUCCESS;
}
/**
* cw_tone_queue_low_callback ()
*
* Registers a function to be called automatically by the dequeue routine
* whenever the tone queue falls to a given level. A NULL function pointer
* suppresses callbacks. On success, the routine returns 0. If level
* is invalid, the routine returns -1 with errno set to EINVAL.
*/
int
cw_tone_queue_low_callback (void (*callback_func) (void), int level)
{
/* Check level for valid values. */
if (level < 0 || level >= TONE_QUEUE_CAPACITY - 1)
{
errno = EINVAL;
return RC_ERROR;
}
/* Store the function and low water mark level. */
cw_tq_low_water_mark = level;
cw_tq_low_water_callback = callback_func;
return RC_SUCCESS;
}
/**
* cw_block_callback()
*
* Blocks the callback from being called for a critical section of caller
* code if block is TRUE, and unblocks the callback if block is FALSE.
* Works by blocking SIGALRM; a block should always be matched by an
* unblock, otherwise the tone queue will suspend forever.
*/
void
cw_block_callback (int block)
{
cw_block_signal_internal (block);
}
/**
* cw_tone_busy()
*
* Indicates if the tone sender is busy; returns TRUE if there are still
* entries in the tone queue, FALSE if the queue is empty.
*/
int
cw_tone_busy ()
{
return (cw_dequeue_state != QS_IDLE);
}
/**
* cw_tone_wait()
*
* Wait for the current tone to complete. The routine returns 0 on success.
* If called with SIGALRM blocked, the routine returns -1, with errno set to
* EDEADLK, to avoid indefinite waits.
*/
int
cw_tone_wait ()
{
int error; /* Error status */
int check_tq_tail; /* Comparison of tail index */
/* Check that SIGALRM is not blocked. */
error = cw_check_signal_mask_internal ();
if (error)
return error;
/* Wait for the tail index to change or the dequeue to go idle. */
check_tq_tail = cw_tq_tail;
while (cw_tq_tail == check_tq_tail
&& cw_dequeue_state != QS_IDLE)
cw_signal_wait_internal ();
return RC_SUCCESS;
}
/**
* cw_tone_queue_wait()
*
* Wait for the tone queue to drain. The routine returns 0 on success.
* If called with SIGALRM blocked, the routine returns -1, with errno set to
* EDEADLK, to avoid indefinite waits.
*/
int
cw_tone_queue_wait ()
{
int error; /* Error status */
/* Check that SIGALRM is not blocked. */
error = cw_check_signal_mask_internal ();
if (error)
return error;
/* Wait until the dequeue indicates it's hit the end of the queue. */
while (cw_dequeue_state != QS_IDLE)
cw_signal_wait_internal ();
return RC_SUCCESS;
}
/**
* cw_tone_queue_full()
*
* Indicates if the tone queue is full, returning TRUE if full, FALSE if not.
*/
int
cw_tone_queue_full()
{
int check_tq_head; /* Test value of head index */
/* See what would happen if we advance the head index. */
if (cw_tq_head + 1 < TONE_QUEUE_CAPACITY)
check_tq_head = cw_tq_head + 1;
else
check_tq_head = 0;
/* If it would meed the tail index, return TRUE. */
return (check_tq_head == cw_tq_tail);
}
/**
* cw_get_tone_queue_capacity()
*
* Returns the number of entries the tone queue can accommodate.
*/
int
cw_get_tone_queue_capacity ()
{
/*
* Since the head and tail indexes cannot be equal, the perceived
* capacity for the client is always one less than the actual
* declared queue size.
*/
return TONE_QUEUE_CAPACITY - 1;
}
/**
* cw_get_tone_queue_length()
*
* Returns the number of entries currently pending in the tone queue.
*/
int
cw_get_tone_queue_length ()
{
if (cw_tq_head >= cw_tq_tail)
return (cw_tq_head - cw_tq_tail);
else
return (cw_tq_head - cw_tq_tail + TONE_QUEUE_CAPACITY);
}
/**
* cw_flush_tone_queue()
*
* Cancel all pending queued tones, and return to silence. If there is a
* tone in progress, the function will wait until this last one has
* completed, then silence the tones.
*
* This function may be called with SIGALRM blocked, in which case it
* will empty the queue as best it can, then return without waiting for
* the final tone to complete. In this case, it may not be possible to
* guarantee silence after the call.
*/
void
cw_flush_tone_queue()
{
/* Empty the queue, by setting the tail to the head. */
cw_tq_tail = cw_tq_head;
/* If we can, wait until the dequeue goes idle. */
if (cw_check_signal_mask_internal () == RC_SUCCESS)
cw_tone_queue_wait ();
/* Force silence on the speaker anyway. */
cw_sound_internal (TONE_SILENT);
}
/**
* cw_queue_tone()
*
* Provides primitive access to simple tone generation. This routine queues
* a tone of given duration and frequency. The routine returns 0 on success.
* If usec or frequency are invalid, it returns -1, with errno set to EINVAL.
* If the console speaker and keying function are busy, it returns -1 with
* errno set to EBUSY. If the tone queue is full, it returns -1 with errno
* set to EAGAIN.
*/
int
cw_queue_tone (int usec, int frequency)
{
/*
* Check the arguments given for realistic values. Note that
* we do nothing here to protect the caller from setting up
* neverending (0 usec) tones, if that's what they want to do.
*/
if (usec < 0 || frequency < 0
|| frequency < CW_MIN_FREQUENCY
|| frequency > CW_MAX_FREQUENCY)
{
errno = EINVAL;
return RC_ERROR;
}
/* Simplistically send the tone requested. */
return cw_queue_tone_internal (usec, frequency);
}
/**
* cw_send_element_internal()
*
* Low level primitive to send a tone element of the given type, followed
* by the standard inter-element silence.
*/
static int
cw_send_element_internal (char element)
{
int error; /* Error status */
/* Synchronize low-level timings if required. */
cw_sync_parameters_internal ();
/* Send either a dot or a dash element, depending on representation. */
if (element == CW_DOT_REPRESENTATION)
{
error = cw_queue_tone_internal (cw_send_dot_length,
cw_frequency);
if (error)
return error;
}
else
{
if (element == CW_DASH_REPRESENTATION)
{
error = cw_queue_tone_internal (cw_send_dash_length,
cw_frequency);
if (error)
return error;
}
}
/* Send the inter-element gap. */
error = cw_queue_tone_internal (cw_end_of_ele_delay, TONE_SILENT);
if (error)
return error;
return RC_SUCCESS;
}
/**
* cw_send_[dot|dash|character_space|word_space]()
*
* Low level primitives, available to send single dots, dashes, character
* spaces, and word spaces. The dot and dash routines always append the
* normal inter-element gap after the tone sent. The cw_send_character_space
* routine sends space timed to exclude the expected prior dot/dash
* inter-element gap. The cw_send_word_space routine sends space timed to
* exclude both the expected prior dot/dash inter-element gap and the prior
* end of character space. These functions return 0 on success, or -1, with
* errno set to EBUSY or EAGAIN on error.
*/
int
cw_send_dot ()
{
return cw_send_element_internal (CW_DOT_REPRESENTATION);
}
int
cw_send_dash ()
{
return cw_send_element_internal (CW_DASH_REPRESENTATION);
}
int
cw_send_character_space ()
{
/* Synchronize low-level timing parameters. */
cw_sync_parameters_internal ();
/*
* Delay for the standard end of character period, plus any
* additional inter-character gap
*/
return cw_queue_tone_internal (cw_end_of_char_delay
+ cw_additional_delay, TONE_SILENT);
}
int
cw_send_word_space ()
{
/* Synchronize low-level timing parameters. */
cw_sync_parameters_internal ();
/* Send silence for the word delay period. */
return cw_queue_tone_internal (cw_end_of_word_delay, TONE_SILENT);
}
/**
* cw_get_character_count()
*
* Returns the number of characters represented in the character lookup
* table.
*/
int
cw_get_character_count ()
{
const cw_entry_t *cwptr; /* Pointer to table entry */
int count; /* Return value */
/* Traverse the main lookup table, counting entries. */
for (count = 0, cwptr = cw_table;
cwptr->character != ASC_NUL; cwptr++)
count++;
/* Return the character count. */
return count;
}
/**
* cw_list_characters()
*
* Returns into list a string containing all of the Morse characters
* represented in our table. The length of list must be at least one
* greater than the number of characters represented in the character
* lookup table, returned by cw_get_character_count.
*/
void
cw_list_characters (unsigned char *list)
{
const cw_entry_t *cwptr; /* Pointer to table entry */
unsigned char *sptr; /* Output string pointer */
/*
* Traverse the main lookup table, appending each character found
* to the output string.
*/
for (sptr = list, cwptr = cw_table;
cwptr->character != ASC_NUL; cwptr++)
{
*sptr = cwptr->character;
sptr++;
}
/* Terminate the output string. */
*sptr = ASC_NUL;
}
/**
* cw_get_maximum_representation_length()
*
* Returns the string length of the longest representation in the character
* lookup table.
*/
int
cw_get_maximum_representation_length ()
{
const cw_entry_t *cwptr; /* Pointer to table entry */
int maximum; /* Return value */
/* Traverse the main lookup table, finding the longest. */
for (cwptr = cw_table, maximum = 0;
cwptr->character != ASC_NUL; cwptr++)
{
if (strlen (cwptr->representation) > maximum)
maximum = strlen (cwptr->representation);
}
/* Return the character count. */
return maximum;
}
/**
* cw_lookup_character_internal()
*
* Look up the given character, and return a pointer to the table entry
* for the representation of that character. Returns NULL if there is
* no table entry for the given character.
*/
static const cw_entry_t*
cw_lookup_character_internal (unsigned char c)
{
static const cw_entry_t *lookup[ UCHAR_MAX ];
static int initialized = FALSE;
/* Fast lookup table initialized
on first function call */
const cw_entry_t *cwptr; /* Pointer to table entry */
/* If not yet initialized, then set up the faster lookup table */
if (!initialized)
{
/* Print any debug message on table initialization. */
if (cw_get_debug_flags () & CW_DEBUG_LOOKUPS)
fprintf (stderr, "cw: initialize fast lookup table\n");
/* For each main table entry, create a fast table entry. */
for (cwptr = cw_table;
cwptr->character != ASC_NUL; cwptr++)
lookup[(unsigned int)cwptr->character] = cwptr;
/* Set the initialized flag now that we built the table. */
initialized = TRUE;
}
/*
* There is no differentiation in the table between upper and lower
* case characters; everything is held as uppercase. So before we
* do the lookup, we convert to ensure that both cases work.
*/
c = toupper (c);
/*
* Now use the table to lookup the table entry. Unknown characters
* return NULL, courtesy of the fact that explicitly uninitialized
* static variables are initialized to zero, so lookup[x] is NULL if
* it's not assigned to in the above loop.
*/
cwptr = lookup[(unsigned int)c];
/* Print out debug message indicating the lookup. */
if (cw_get_debug_flags () & CW_DEBUG_LOOKUPS)
{
if (cwptr != NULL)
fprintf (stderr,
"cw: lookup '%c' returned <'%c':\"%s\">\n",
c, cwptr->character, cwptr->representation);
else
if (isprint (c))
fprintf (stderr,
"cw: lookup '%c' found nothing\n", c);
else
fprintf (stderr,
"cw: lookup 0x%02x found nothing\n", c);
}
return cwptr;
}
/**
* cw_lookup_character()
*
* Returns the string 'shape' of a given Morse code character. The routine
* returns 0 on success, and fills in the string pointer passed in. On error,
* it returns -1, and sets errno to ENOENT, indicating that the character
* could not be found. The length of representation must be at least one
* greater than the longest representation held in the character lookup table,
* returned by cw_get_maximum_representation_length.
*/
int
cw_lookup_character (unsigned char c, char *representation)
{
const cw_entry_t *cwptr; /* Pointer to table entry */
/* Lookup the character, and if found, return the string. */
cwptr = cw_lookup_character_internal (c);
if (cwptr != NULL)
{
if (representation != NULL)
strcpy (representation, cwptr->representation);
return RC_SUCCESS;
}
/* Failed to find the requested character. */
errno = ENOENT;
return RC_ERROR;
}
/**
* cw_tokenize_representation_internal()
*
* Return a token value, in the range 2-255, for a lookup table representation.
* The routine returns 0 if no valid token could be made from the string. To
* avoid casting the value a lot in the caller (we want to use it as an array
* index), we actually return an unsigned int.
*
* This token algorithm is designed ONLY for valid CW representations; that is,
* strings composed of only '.' and '-', and in this case, strings shorter than
* eight characters. The algorithm simply turns the representation into a
* 'bitmask', based on occurrences of '.' and '-'. The first bit set in the
* mask indicates the start of data (hence the 7-character limit). This mask
* is viewable as an integer in the range 2 (".") to 255 ("-------"), and can
* be used as an index into a fast lookup array.
*/
static unsigned int
cw_tokenize_representation_internal (const char *representation)
{
unsigned int token; /* Return token value */
const char *sptr; /* Pointer through string */
/*
* Our algorithm can handle only 7 characters of representation.
* And we insist on there being at least one character, too.
*/
if (strlen (representation) > CHAR_BIT - 1
|| strlen (representation) < 1)
return 0;
/*
* Build up the token value based on the dots and dashes. Start the
* token at 1 - the sentinel (start) bit.
*/
for (sptr = representation, token = 1; *sptr != ASC_NUL; sptr++)
{
/*
* Belt-and-braces check that we don't lose the most
* significant bit, and exceed 255 as a return token.
*/
if (token & (1 << (CHAR_BIT - 1)))
return 0;
/* Left-shift the sentinel (start) bit. */
token <<= 1;
/*
* If the next element is a dash, OR in another bit. If it is
* not a dash or a dot, then there is an error in the repres-
* entation string.
*/
if (*sptr == CW_DASH_REPRESENTATION)
token |= 1;
else
if (*sptr != CW_DOT_REPRESENTATION)
return 0;
}
/* Return the value resulting from our tokenization of the string. */
return token;
}
/**
* cw_lookup_representation_internal()
*
* Look up the given representation, and return a pointer to the table entry
* for the representation of that character. Returns NULL if there is
* no table entry for the given character.
*/
static const cw_entry_t*
cw_lookup_representation_internal (const char *representation)
{
static const cw_entry_t *lookup[ UCHAR_MAX ];
static int initialized = FALSE;
/* Fast lookup table initialized
on first function call */
static int complete = TRUE;/* Set to FALSE if there are any
lookup table entries not in
the fast lookup table */
const cw_entry_t *cwptr; /* Pointer to table entry */
unsigned int token; /* Tokenization code return */
/* If not yet initialized, then set up the tokenized lookup table. */
if (!initialized)
{
/* Print any debug message on table initialization. */
if (cw_get_debug_flags () & CW_DEBUG_LOOKUPS)
fprintf (stderr, "cw: initialize token lookup table\n");
/*
* For each main table entry, create a token entry. If the
* tokenization of any entry fails, note that the table is not
* complete and ignore that entry for now (for the current
* lookup table, this should not happen). The tokenized table
* speeds up lookups of representations by a factor of 5-10.
*/
for (cwptr = cw_table;
cwptr->character != ASC_NUL; cwptr++)
{
token = cw_tokenize_representation_internal
(cwptr->representation);
if (token != 0)
lookup[token] = cwptr;
else
complete = FALSE;
}
/* Print a debug warning if the table is not complete. */
if (cw_get_debug_flags () & CW_DEBUG_LOOKUPS
&& !complete)
fprintf (stderr, "cw: token lookup table incomplete\n");
/* Set the initialized flag now that we built the table. */
initialized = TRUE;
}
/* Tokenize the representation to get an index for the fast lookup. */
token = cw_tokenize_representation_internal (representation);
/*
* If the tokenized lookup table is complete, we can simply believe
* any token value that came back. That is, we just use what is at
* the index 'token', since this is either the entry we want, or NULL.
*/
if (complete)
cwptr = lookup[token];
else
{
/*
* If the tokenized lookup table is not complete, the lookup
* might still have found us the entry we are looking for.
* Here, we'll check to see if it did.
*/
if (token != 0
&& lookup[token]->representation != NULL
&& strcmp (lookup[token]->representation,
representation) == 0)
/* Found it in an incomplete table. */
cwptr = lookup[token];
else
{
/*
* We have no choice but to search the table entry
* by entry, sequentially, from top to bottom.
*/
for (cwptr = cw_table;
cwptr->character != ASC_NUL; cwptr++)
{
if (strcmp (cwptr->representation,
representation) == 0)
break;
}
/* If we got to the end of the table, return NULL. */
if (cwptr->character == ASC_NUL)
cwptr = NULL;
}
}
/* Print out debug message indicating the lookup. */
if (cw_get_debug_flags () & CW_DEBUG_LOOKUPS)
{
if (cwptr != NULL)
fprintf (stderr,
"cw: lookup [0x%02x]'%s' returned <'%c':\"%s\">\n",
token, representation,
cwptr->character, cwptr->representation);
else
fprintf (stderr,
"cw: lookup [0x%02x]'%s' found nothing\n",
token, representation);
}
/* Finally, return anything we managed to get out of this. */
return cwptr;
}
/**
* cw_check_representation()
*
* Checks that the given string is a valid Morse representation. A valid
* string is one composed of only '.' and '-' characters. On success, the
* routine returns 0. On error, it returns -1, with errno set to EINVAL.
*/
int
cw_check_representation (const char *representation)
{
const char *sptr; /* Cw string pointer */
/* Check the characters in representation. */
for (sptr = representation; *sptr != ASC_NUL; sptr++)
{
if (*sptr != CW_DOT_REPRESENTATION
&& *sptr != CW_DASH_REPRESENTATION)
{
errno = EINVAL;
return RC_ERROR;
}
}
return RC_SUCCESS;
}
/**
* cw_lookup_representation()
*
* Returns the character for a given Morse representation. On success, the
* routine returns 0, and fills in unsigned char *c. On error, it returns
* -1, and sets errno to EINVAL if any character of the representation is
* invalid, or ENOENT to indicate that the representation could not be found.
*/
int
cw_lookup_representation (const char *representation,
unsigned char *c)
{
const cw_entry_t *cwptr; /* Pointer to table entry */
/* Check the characters in representation. */
if (cw_check_representation (representation) == RC_ERROR)
{
errno = EINVAL;
return RC_ERROR;
}
/* Lookup the representation, and if found, return the character. */
cwptr = cw_lookup_representation_internal (representation);
if (cwptr != NULL)
{
if (c != NULL)
*c = cwptr->character;
return RC_SUCCESS;
}
/* Failed to find the requested representation. */
errno = ENOENT;
return RC_ERROR;
}
/**
* cw_send_representation_internal()
*
* Send the given string as dots and dashes, adding the post-character
* gap.
*/
static int
cw_send_representation_internal (const char *representation, int partial)
{
int error; /* Error status */
const char *sptr; /* Cw string pointer */
/*
* Before we let this representation loose on tone generation, we'd
* really like to know that all of its tones will get queued up
* successfully. The right way to do this is to calculate the
* number of tones in our representation, then check that the
* space exists in the tone queue. However, since the queue is
* comfortably long, we can get away with just looking for a high
* water mark.
*/
if (cw_get_tone_queue_length () >= TONE_QUEUE_HIGH_WATER_MARK)
{
errno = EAGAIN;
return RC_ERROR;
}
/* Sound the elements of the cw equivalent. */
for (sptr = representation; *sptr != ASC_NUL; sptr++)
{
/*
* Send a tone of dot or dash length, followed by the normal,
* standard, inter-element gap.
*/
error = cw_send_element_internal (*sptr);
if (error)
return error;
}
/*
* If this representation is stated as being 'partial', then suppress
* any and all end of character delays.
*/
if (!partial)
{
error = cw_send_character_space ();
if (error)
return error;
}
return RC_SUCCESS;
}
/**
* cw_send_representation()
*
* Checks, then sends the given string as dots and dashes. The representation
* passed in is assumed to be a complete Morse character; that is, all post-
* character delays will be added when the character is sent. On success,
* the routine returns 0. On error, it returns -1, with errno set to EINVAL
* if any character of the representation is invalid, EBUSY if the console
* speaker or keying system is busy, or EAGAIN if the tone queue is full, or if
* there is insufficient space to queue the tones for the representation.
*/
int
cw_send_representation (const char *representation)
{
/* Check the characters in representation. */
if (cw_check_representation (representation) == RC_ERROR)
{
errno = EINVAL;
return RC_ERROR;
}
/* Sound out the representation. */
return cw_send_representation_internal (representation, FALSE);
}
/**
* cw_send_representation_partial()
*
* Check, then send the given string as dots and dashes. The representation
* passed in is assumed to be only part of a larger Morse representation;
* that is, no post-character delays will be added when the character is sent.
* On success, the routine returns 0. On error, it returns -1, with errno
* set to EINVAL if any character of the representation is invalid, EBUSY
* if the console speaker or keying system is busy, or EAGAIN if the tone
* queue is full, or if there is insufficient space to queue the tones for
* the representation.
*/
int
cw_send_representation_partial (const char *representation)
{
/* Check the characters in representation. */
if (cw_check_representation (representation) == RC_ERROR)
{
errno = ENOENT;
return RC_ERROR;
}
/* Sound out the representation. */
return cw_send_representation_internal (representation, TRUE);
}
/**
* cw_send_character_internal()
*
* Lookup, and send a given ASCII character as cw. If 'partial' is set, the
* end of character delay is not appended to the Morse sent. On success,
* the routine returns 0, otherwise it returns an error.
*/
static int
cw_send_character_internal (unsigned char c, int partial)
{
int error; /* Error status */
const cw_entry_t *cwptr; /* Pointer to table entry */
/* Handle space special case; delay end-of-word and return. */
if (c == ASC_SPACE)
{
error = cw_send_word_space ();
if (error)
return error;
}
else
{
/* Lookup the character, and sound it. */
cwptr = cw_lookup_character_internal (c);
if (cwptr == NULL)
{
errno = ENOENT;
return RC_ERROR;
}
error = cw_send_representation_internal
(cwptr->representation, partial);
if (error)
return error;
}
return RC_SUCCESS;
}
/**
* cw_check_character()
*
* Checks that the given character is validly sendable in Morse. If it is,
* the routine returns 0. If not, the routine returns -1, with errno set
* to ENOENT.
*/
int
cw_check_character (unsigned char c)
{
/*
* If the character is the space special-case, or if not, but it
* is in the lookup table, return success.
*/
if (c == ASC_SPACE
|| cw_lookup_character_internal (c) != NULL)
return RC_SUCCESS;
/* Character is not sendable. */
errno = ENOENT;
return RC_ERROR;
}
/**
* cw_send_character()
*
* Lookup, and send a given ASCII character as Morse. The end of character
* delay is appended to the Morse sent. On success, the routine returns 0.
* On error, it returns -1, with errno set to ENOENT if the given character
* is not a valid Morse character, EBUSY if the console speaker or keying
* system is busy, or EAGAIN if the tone queue is full, or if there is
* insufficient space to queue the tones for the representation.
*
* This routine returns as soon as the character has been successfully
* queued for send; that is, almost immediately. The actual sending takes
* place in background processing. See cw_tone_wait and cw_tone_queue_wait
* for ways to check the progress of sending.
*/
int
cw_send_character (unsigned char c)
{
/* Check that the character is sendable. */
if (cw_check_character (c) == RC_ERROR)
{
errno = ENOENT;
return RC_ERROR;
}
return cw_send_character_internal (c, FALSE);
}
/**
* cw_send_character_partial()
*
* Lookup, and send a given ASCII character as Morse. The end of character
* delay is not appended to the Morse sent by the function, to support the
* formation of combination characters. On success, the routine returns 0.
* On error, it returns -1, with errno set to ENOENT if the given character
* is not a valid Morse character, EBUSY if the console speaker or keying
* system is busy, or EAGAIN if the tone queue is full, or if there is
* insufficient space to queue the tones for the representation.
*
* This routine queues its arguments for background processing. See
* cw_send_character for details of how to check the queue status.
*/
int
cw_send_character_partial (unsigned char c)
{
/* Check that the character is sendable. */
if (cw_check_character (c) == RC_ERROR)
{
errno = ENOENT;
return RC_ERROR;
}
return cw_send_character_internal (c, TRUE);
}
/**
* cw_check_string()
*
* Checks that each character in the given string is validly sendable in Morse.
* On success, the routine returns 0. On error, it returns -1, with errno set
* to EINVAL.
*/
int
cw_check_string (const unsigned char *string)
{
const unsigned char *sptr; /* String pointer */
/*
* Check that each character in the string has a Morse representation,
* or is the space special case.
*/
for (sptr = string; *sptr != ASC_NUL; sptr++)
{
if (*sptr != ASC_SPACE
&& cw_lookup_character_internal (*sptr) == NULL)
{
errno = EINVAL;
return RC_ERROR;
}
}
/* Each character of the string is sendable. */
return RC_SUCCESS;
}
/**
* cw_send_string()
*
* Send a given ASCII string as cw. On success, the routine returns 0.
* On error, it returns -1, with errno set to ENOENT if any character in the
* string is not a valid Morse character, EBUSY if the console speaker and
* keying system is in use by the iambic keyer or the straight key, or EAGAIN
* if the tone queue is full. If the tone queue runs out of space part way
* through queueing the string, the function returns EAGAIN. However, an
* indeterminate number of the characters from the string will have already
* been queued. For safety, clients can ensure the tone queue is empty
* before queueing a string, or use cw_send_character() if they need finer
* control.
*
* This routine queues its arguments for background processing. See
* cw_send_character for details of how to check the queue status.
*/
int
cw_send_string (const unsigned char *string)
{
int error; /* Error status */
const cw_entry_t *cwptr; /* Pointer to table entry */
const unsigned char *sptr; /* String pointer */
/*
* Initially, check that each character in the string has a Morse
* representation, or is the space special case.
*/
if (cw_check_string (string) == RC_ERROR)
{
errno = ENOENT;
return RC_ERROR;
}
/* Send every character in the string. */
for (sptr = string; *sptr != ASC_NUL; sptr++)
{
/* Handle space special case; delay end-of-word and return. */
if (*sptr == ASC_SPACE)
{
error = cw_send_word_space ();
if (error)
return error;
}
else
{
/* Lookup the character, and sound it. */
cwptr = cw_lookup_character_internal (*sptr);
if (cwptr == NULL)
{
errno = ENOENT;
return RC_ERROR;
}
error = cw_send_representation_internal
(cwptr->representation, FALSE);
if (error)
return error;
}
}
return RC_SUCCESS;
}
/*
* The CW receive functions implement the following state graph:
*
* +----------------- RS_ERR_WORD <-------------------+
* |(clear) ^ |
* | (delay=long)| |
* | | |
* +----------------- RS_ERR_CHAR <---------+ |
* |(clear) ^ | | |
* | | +-------------+ |(error,
* | | (delay=short) | delay=long)
* | (error,delay=short)| |
* | | +-----------------------+
* | | |
* +--------------------+ | |
* | (noise)| | |
* | | | |
* v (start tone) | | | (end tone,noise)
* --> RS_IDLE ------------> RS_IN_TONE ------------> RS_AFTER_TONE <------- +
* | ^ ^ | | | ^ | |
* | | (delay=short) +---------------+ | | | +-----------+
* | | +--------------+ (start tone) | | | (not ready,
* | | | | | | | buffer dot,
* | | +-------> RS_END_CHAR <--------------+ | | buffer dash)
* | | | | (delay=short) | |
* | +-------------------+ | | |
* | |(clear) | | |
* | | (delay=long)| | |
* | | v | |
* | +----------------- RS_END_WORD <-------------------+ |
* | (clear) (delay=long) |(buffer dot,
* | | buffer dash)
* +-------------------------------------------------------+
*/
static enum {RS_IDLE,RS_IN_TONE,RS_AFTER_TONE,
RS_END_CHAR,RS_END_WORD,
RS_ERR_CHAR,RS_ERR_WORD}
cw_receive_state = RS_IDLE;
/* Indicates receive state */
/**
* cw_start_receive_tone()
*
* Called on the start of a receive tone. If the timestamp is NULL, the
* current time is used. On success, the routine returns 0. On error,
* it returns -1, with errno set to ERANGE if the call is directly after
* another cw_start_receive_tone call or if an existing received character
* has not been cleared from the buffer, or EINVAL if the timestamp passed
* in is invalid.
*/
int
cw_start_receive_tone (const struct timeval *timestamp)
{
/*
* If the receive state is not idle or after a tone, this is a
* state error. A receive tone start can only happen while we
* are idle, or in the middle of a character.
*/
if (cw_receive_state != RS_IDLE
&& cw_receive_state != RS_AFTER_TONE)
{
errno = ERANGE;
return RC_ERROR;
}
/* Validate and save the timestamp, or get one and then save it. */
if (timestamp != NULL)
{
if (timestamp->tv_sec < 0 || timestamp->tv_usec < 0
|| timestamp->tv_usec >= USECS_PER_SEC)
{
errno = EINVAL;
return RC_ERROR;
}
cw_rr_start_timestamp.tv_sec = timestamp->tv_sec;
cw_rr_start_timestamp.tv_usec = timestamp->tv_usec;
}
else
{
if (gettimeofday (&cw_rr_start_timestamp, NULL) != 0)
{
perror ("cw: gettimeofday");
return RC_ERROR;
}
}
/* Set state to indicate we are inside a tone. */
cw_receive_state = RS_IN_TONE;
/* Print out any state change debug. */
if (cw_get_debug_flags () & CW_DEBUG_RECEIVE_STATES)
fprintf (stderr,
"cw: receive state ->%d\n", cw_receive_state);
return RC_SUCCESS;
}
/**
* cw_compare_timestamps_internal()
*
* Compare two timestamps, and return the difference between them in usecs,
* taking care to clamp values which would overflow an int. This routine
* always returns a +ve integer in the range 0 to INT_MAX.
*/
static int
cw_compare_timestamps_internal (const struct timeval *earlier,
const struct timeval *later)
{
int delta_usec; /* Time difference in usecs */
/*
* Compare the timestamps, taking care on overflows.
*
* At 4 WPM, the dash length is 3*(1200000/4)=900,000 usecs, and
* the word gap is 2,100,000 usecs. With the maximum Farnsworth
* additional delay, the word gap extends to 8,100,000 usecs.
* This fits into an int with a lot of room to spare, in fact,
* an int can represent ~2000,000,000 usecs, or around 33 minutes.
* This is way, way longer than we'd ever want to differentiate,
* so if by some chance we see timestamps farther apart than this,
* and it ought to be very, very unlikely, then we'll clamp the
* return value to INT_MAX with a clear conscience.
*
* Note: passing nonsensical or bogus timevals in may result
* in unpredictable results. Nonsensical includes timevals with
* -ve tv_usec, -ve tv_sec, tv_usec >= 1,000,000, etc. To help
* in this, we check all incoming timestamps for 'well-formedness'.
* However, we assume the gettimeofday() call always returns good
* timevals. All in all, timeval could probably be a better
* thought-out structure.
*/
/* Calculate an initial delta, possibly with overflow. */
delta_usec = (later->tv_sec - earlier->tv_sec) * USECS_PER_SEC
+ later->tv_usec
- earlier->tv_usec;
/* Check specifically for overflow, and clamp if it did. */
if ((later->tv_sec - earlier->tv_sec) > (INT_MAX / USECS_PER_SEC) + 1
|| delta_usec < 0)
delta_usec = INT_MAX;
return delta_usec;
}
/**
* cw_identify_receive_tone_internal()
*
* Analyses a tone using the ranges provided by the low level timing
* parameters. On success, it returns 0 and sends back either a dot or
* a dash in representation. On error, it returns -1 with ERRNO set to
* ENOENT if the tone is not recognizable as either a dot or a dash,
* and sets the receive state to one of the error states, depending on
* the tone length passed in.
*
* Note; for adaptive timing, the tone should _always_ be recognized as
* a dot or a dash, because the ranges will have been set to cover 0 to
* INT_MAX.
*/
static int
cw_identify_receive_tone_internal (int element_usec, char *representation)
{
/* Synchronize low level timings if required */
cw_sync_parameters_internal ();
/*
* If the timing was, within tolerance, a dot, return a dot to the
* caller.
*/
if (element_usec >= cw_dot_range_minimum
&& element_usec <= cw_dot_range_maximum)
{
*representation = CW_DOT_REPRESENTATION;
return RC_SUCCESS;
}
/* Do the same for a dash. */
if (element_usec >= cw_dash_range_minimum
&& element_usec <= cw_dash_range_maximum)
{
*representation = CW_DASH_REPRESENTATION;
return RC_SUCCESS;
}
/*
* This element is not a dot or a dash, so we have an error case.
* Depending on the timestamp difference, we pick which of the
* error states to move to, and move to it. The comparison is
* against the expected end-of-char delay. If it's larger, then
* fix at word error, otherwise settle on char error.
*
* Note that we should never reach here for adaptive timing receive.
*/
if (element_usec > cw_eoc_range_maximum)
cw_receive_state = RS_ERR_WORD;
else
cw_receive_state = RS_ERR_CHAR;
/* Print out any state change debug. */
if (cw_get_debug_flags () & CW_DEBUG_RECEIVE_STATES)
fprintf (stderr,
"cw: receive state ->%d\n", cw_receive_state);
/* Return ENOENT to the caller. */
errno = ENOENT;
return RC_ERROR;
}
/**
* cw_update_adaptive_tracking_internal()
*
* Updates the averages of dot and dash lengths, and recalculates the
* adaptive threshold for the next receive tone.
*/
static void
cw_update_adaptive_tracking_internal (int element_usec, char element)
{
int average_dot; /* Averaged dot length */
int average_dash; /* Averaged dash length */
/* We are not going to tolerate being called in fixed speed mode. */
if (!cw_adaptive_receive_enabled)
return;
/*
* We will update the information held for either dots or dashes.
* Which we pick depends only on what the representation of the
* character was identified as earlier.
*/
if (element == CW_DOT_REPRESENTATION)
{
/* Update the dot data held for averaging. */
cw_dt_dot_tracking_sum
-= cw_dot_tracking_array[cw_dt_dot_index];
cw_dot_tracking_array[cw_dt_dot_index++] = element_usec;
cw_dt_dot_index %= AVERAGE_ARRAY_LENGTH;
cw_dt_dot_tracking_sum += element_usec;
}
else
{
if (element == CW_DASH_REPRESENTATION)
{
/* Update the dash data held for averaging. */
cw_dt_dash_tracking_sum
-= cw_dash_tracking_array[cw_dt_dash_index];
cw_dash_tracking_array[cw_dt_dash_index++] =
element_usec;
cw_dt_dash_index %= AVERAGE_ARRAY_LENGTH;
cw_dt_dash_tracking_sum += element_usec;
}
}
/*
* Recalculate the adaptive threshold from the values currently
* held in the averaging arrays. The threshold is calculated as
* (avg dash length - avg dot length) / 2 + avg dot_length.
*/
average_dot = cw_dt_dot_tracking_sum / AVERAGE_ARRAY_LENGTH;
average_dash = cw_dt_dash_tracking_sum / AVERAGE_ARRAY_LENGTH;
cw_adaptive_receive_threshold = ( average_dash - average_dot ) / 2
+ average_dot;
/*
* Resynchronize the low level timing data following recalculation.
* If the resultant recalculated speed is outside the limits,
* clamp the speed to the limit value and recalculate again.
*
* Resetting the speed directly really means unsetting adaptive
* mode, resyncing to calculate the new threshold, which unfort-
* unately recalculates everything else according to fixed speed;
* so, we then have to reset adaptive and resyncing one more time,
* to get all other timing parameters back to where they should be.
*/
cw_in_sync = FALSE; cw_sync_parameters_internal ();
if (cw_receive_speed < CW_MIN_SPEED)
{
cw_receive_speed = CW_MIN_SPEED;
cw_adaptive_receive_enabled = FALSE;
cw_in_sync = FALSE; cw_sync_parameters_internal ();
cw_adaptive_receive_enabled = TRUE;
cw_in_sync = FALSE; cw_sync_parameters_internal ();
}
else
{
if (cw_receive_speed > CW_MAX_SPEED)
{
cw_receive_speed = CW_MAX_SPEED;
cw_adaptive_receive_enabled = FALSE;
cw_in_sync = FALSE; cw_sync_parameters_internal ();
cw_adaptive_receive_enabled = TRUE;
cw_in_sync = FALSE; cw_sync_parameters_internal ();
}
}
}
/**
* cw_end_receive_tone()
*
* Called on the end of a receive tone. If the timestamp is NULL, the
* current time is used. On success, the routine adds a dot or dash to
* the receive representation buffer, and returns 0. On error, it
* returns -1, with errno set to ERANGE if the call was not preceded by
* a cw_start_receive_tone call, EINVAL if the timestamp passed in is not
* valid, ENOENT if the tone length was out of bounds for the permissible
* dot and dash lengths and fixed speed receiving is selected, ENOMEM if
* the representation buffer is full, or EAGAIN if the tone was shorter
* than the threshold for noise and was therefore ignored.
*/
int
cw_end_receive_tone (const struct timeval *timestamp)
{
int error; /* Error status */
int element_usec; /* Time difference in usecs */
char representation; /* Tone dot or dash character */
struct timeval saved_end_timestamp; /* Safe copy of end timestamp */
/* The receive state is expected to be inside a tone. */
if (cw_receive_state != RS_IN_TONE)
{
errno = ERANGE;
return RC_ERROR;
}
/*
* Take a safe copy of the current end timestamp, in case we need
* to put it back if we decide this tone is really just noise.
*/
saved_end_timestamp.tv_sec = cw_rr_end_timestamp.tv_sec;
saved_end_timestamp.tv_usec = cw_rr_end_timestamp.tv_usec;
/* Save the timestamp passed in, or get one. */
if (timestamp != NULL)
{
if (timestamp->tv_sec < 0 || timestamp->tv_usec < 0
|| timestamp->tv_usec >= USECS_PER_SEC)
{
errno = EINVAL;
return RC_ERROR;
}
cw_rr_end_timestamp.tv_sec = timestamp->tv_sec;
cw_rr_end_timestamp.tv_usec = timestamp->tv_usec;
}
else
{
if (gettimeofday (&cw_rr_end_timestamp, NULL) != 0)
{
perror ("cw: gettimeofday");
return RC_ERROR;
}
}
/*
* Now we need to compare the timestamps to determine the length
* of the tone.
*/
element_usec = cw_compare_timestamps_internal
(&cw_rr_start_timestamp, &cw_rr_end_timestamp);
/*
* If the tone length is shorter than any noise cancelling threshold
* that has been set, then ignore this tone. This means reverting
* to the state before the call to cw_start_receive_tone. Now, by
* rights, we should use an extra state, RS_IN_FIRST_TONE, say, so
* that we know whether to go back to the idle state, or to after
* tone. But to make things a touch simpler, here we can just look
* at the current receive buffer pointer - if it's zero, we came
* from idle, otherwise we came from after tone.
*/
if (cw_noise_spike_threshold > 0
&& element_usec <= cw_noise_spike_threshold)
{
if (cw_rr_current == 0)
cw_receive_state = RS_IDLE;
else
cw_receive_state = RS_AFTER_TONE;
/*
* Put the end tone timestamp back to how it was when we
* came in to the routine.
*/
cw_rr_end_timestamp.tv_sec = saved_end_timestamp.tv_sec;
cw_rr_end_timestamp.tv_usec = saved_end_timestamp.tv_usec;
/* Print out any state change debug. */
if (cw_get_debug_flags () & CW_DEBUG_RECEIVE_STATES)
fprintf (stderr,
"cw: receive state ->%d\n", cw_receive_state);
errno = EAGAIN;
return RC_ERROR;
}
/*
* At this point, we have to make a decision about the element
* just received. Well use a routine that compares ranges to
* tell us what it thinks this element is. If it can't decide,
* it will hand us back an error which we return to the caller.
* Otherwise, it returns a character, dot or dash, for us to
* buffer.
*/
error = cw_identify_receive_tone_internal (element_usec,
&representation);
if (error)
return error;
/*
* Update the averaging buffers so that the adaptive tracking of
* received Morse speed stays up to date. But only do this if
* we have set adaptive receiving; don't fiddle about trying to
* track for fixed speed receive.
*/
if (cw_adaptive_receive_enabled)
cw_update_adaptive_tracking_internal (element_usec,
representation);
/* Add the representation character to the receive buffer. */
cw_receive_representation_buffer[cw_rr_current++]
= representation;
/*
* We just added a representation to the receive buffer. If it's
* full, then we have to do something, even though it's unlikely.
* What we'll do is make a unilateral declaration that if we get
* this far, we go to end-of-char error state automatically.
*/
if (cw_rr_current == RECEIVE_CAPACITY - 1)
{
cw_receive_state = RS_ERR_CHAR;
/* Print out any state change debug. */
if (cw_get_debug_flags () & CW_DEBUG_RECEIVE_STATES)
fprintf (stderr,
"cw: receive state ->%d\n", cw_receive_state);
errno = ENOMEM;
return RC_ERROR;
}
/* All is well. Move to the more normal after-tone state. */
cw_receive_state = RS_AFTER_TONE;
/* Print out any state change debug. */
if (cw_get_debug_flags () & CW_DEBUG_RECEIVE_STATES)
fprintf (stderr,
"cw: receive state ->%d\n", cw_receive_state);
return RC_SUCCESS;
}
/**
* cw_receive_buffer_element_internal()
*
* Adds either a dot or a dash to the receive representation buffer. If
* the timestamp is NULL, the current timestamp is used. The receive state
* is updated as if we had just received a call to cw_end_receive_tone.
*/
static int
cw_receive_buffer_element_internal (const struct timeval *timestamp,
char element)
{
/*
* The receive state is expected to be idle or after a tone in
* order to use this routine.
*/
if (cw_receive_state != RS_IDLE
&& cw_receive_state != RS_AFTER_TONE)
{
errno = ERANGE;
return RC_ERROR;
}
/*
* This routine functions as if we have just seen a tone end, yet
* without really seeing a tone start. To keep timing information
* for routines that come later, we need to make sure that the
* end of tone timestamp is set here. This is because the
* receive representation routine looks at the time since the last
* end of tone to determine whether we are at the end of a word,
* or just at the end of a character. It doesn't matter that the
* start of tone timestamp is never set - this is just for timing
* the tone length, and we don't need to do that since we've
* already been told whether this is a dot or a dash.
*/
if (timestamp != NULL)
{
if (timestamp->tv_sec < 0 || timestamp->tv_usec < 0
|| timestamp->tv_usec >= USECS_PER_SEC)
{
errno = EINVAL;
return RC_ERROR;
}
cw_rr_end_timestamp.tv_sec = timestamp->tv_sec;
cw_rr_end_timestamp.tv_usec = timestamp->tv_usec;
}
else
{
if (gettimeofday (&cw_rr_end_timestamp, NULL) != 0)
{
perror ("cw: gettimeofday");
return RC_ERROR;
}
}
/* Add the element to the receive representation buffer. */
cw_receive_representation_buffer[cw_rr_current++] = element;
/*
* We just added an element to the receive buffer. As above, if
* it's full, then we have to do something, even though it's
* unlikely to actually be full.
*/
if (cw_rr_current == RECEIVE_CAPACITY - 1)
{
cw_receive_state = RS_ERR_CHAR;
/* Print out any state change debug. */
if (cw_get_debug_flags () & CW_DEBUG_RECEIVE_STATES)
fprintf (stderr,
"cw: receive state ->%d\n", cw_receive_state);
errno = ENOMEM;
return RC_ERROR;
}
/*
* Since we effectively just saw the end of a tone, move to the
* after-tone state.
*/
cw_receive_state = RS_AFTER_TONE;
/* Print out any state change debug. */
if (cw_get_debug_flags () & CW_DEBUG_RECEIVE_STATES)
fprintf (stderr,
"cw: receive state ->%d\n", cw_receive_state);
return RC_SUCCESS;
}
/**
* cw_receive_buffer_dot()
* cw_receive_buffer_dash()
*
* Adds either a dot or a dash to the receive representation buffer. If
* the timestamp is NULL, the current timestamp is used. These routines
* are for callers that have already determined whether a dot or dash was
* received by a method other than calling the routines cw_start_receive_tone
* and cw_end_receive_tone. On success, the relevant element is added to
* the receive representation buffer. On error, the routines return -1,
* with errno set to ERANGE if preceded by a cw_start_receive_tone call
* with no matching cw_end_receive_tone or if an error condition currently
* exists within the receive buffer, or ENOMEM if the receive representation
* buffer is full.
*/
int
cw_receive_buffer_dot (const struct timeval *timestamp)
{
return cw_receive_buffer_element_internal (timestamp,
CW_DOT_REPRESENTATION);
}
int
cw_receive_buffer_dash (const struct timeval *timestamp)
{
return cw_receive_buffer_element_internal (timestamp,
CW_DASH_REPRESENTATION);
}
/**
* cw_receive_representation()
*
* Returns the current buffered representation from the receive buffer.
* On success, the function returns 0, and fills in representation with the
* contents of the current representation buffer. On error, it returns -1,
* with errno set to ERANGE if not preceded by a cw_end_receive_tone call,
* a prior successful cw_receive_representation call, or a prior
* cw_receive_buffer_dot or cw_receive_buffer_dash, EINVAL if the timestamp
* passed in is invalid, or EAGAIN if the call is made too early to determine
* whether a complete representation has yet been placed in the buffer
* (that is, less than the inter-character gap period has elapsed since the
* last cw_end_receive_tone or cw_receive_buffer_dot/dash call). end_of_word
* indicates that the delay after the last tone received is longer that the
* inter-word gap, and error_flag indicates that the representation was
* terminated by an error condition.
*/
int
cw_receive_representation (const struct timeval *timestamp,
char *representation, int *end_of_word,
int *error_flag)
{
int space_usec; /* Time difference in usecs */
struct timeval now_timestamp; /* The current time of day */
/*
* If the the receive state indicates that we have in our possession
* a completed representation at the end of word, just [re-]return it.
*/
if (cw_receive_state == RS_END_WORD
|| cw_receive_state == RS_ERR_WORD)
{
/* Return the representation buffered. */
if (end_of_word != NULL)
*end_of_word = TRUE;
if (error_flag != NULL)
*error_flag = (cw_receive_state == RS_ERR_WORD);
*representation = ASC_NUL;
strncat (representation, cw_receive_representation_buffer,
cw_rr_current);
return RC_SUCCESS;
}
/*
* If the receive state is also not end-of-char, and also not after
* a tone, then we are idle or in a tone; in these cases, we return
* ERANGE.
*/
if (cw_receive_state != RS_AFTER_TONE
&& cw_receive_state != RS_END_CHAR
&& cw_receive_state != RS_ERR_CHAR)
{
errno = ERANGE;
return RC_ERROR;
}
/*
* We now know the state is after a tone, or end-of-char, perhaps
* with error. For all three of these cases, we're going to [re-]
* compare the timestamp with the end of tone timestamp. This
* could mean that in the case of end-of-char, we revise our
* opinion on later calls to end-of-word. This is correct, since
* it models reality.
*/
/*
* If we weren't supplied with one, get the current timestamp, for
* comparison against the latest end timestamp.
*/
if (timestamp != NULL)
{
if (timestamp->tv_sec < 0 || timestamp->tv_usec < 0
|| timestamp->tv_usec >= USECS_PER_SEC)
{
errno = EINVAL;
return RC_ERROR;
}
now_timestamp.tv_sec = timestamp->tv_sec;
now_timestamp.tv_usec = timestamp->tv_usec;
}
else
{
if (gettimeofday (&now_timestamp, NULL) != 0)
{
perror ("cw: gettimeofday");
return RC_ERROR;
}
}
/*
* Now we need to compare the timestamps to determine the length
* of the inter-tone gap.
*/
space_usec = cw_compare_timestamps_internal
(&cw_rr_end_timestamp, &now_timestamp);
/* Synchronize low level timings if required */
cw_sync_parameters_internal ();
/*
* If the timing was, within tolerance, a character space, then
* that is what we'll call it. In this case, we complete the
* representation and return it.
*/
if (space_usec >= cw_eoc_range_minimum
&& space_usec <= cw_eoc_range_maximum)
{
/*
* If state is after tone, we can validly move at this point
* to end of char. If it's not, then we're at end char or
* at end char with error already, so leave it.
*/
if (cw_receive_state == RS_AFTER_TONE)
cw_receive_state = RS_END_CHAR;
/* Print out any state change debug. */
if (cw_get_debug_flags () & CW_DEBUG_RECEIVE_STATES)
fprintf (stderr,
"cw: receive state ->%d\n", cw_receive_state);
/* Return the representation buffered. */
if (end_of_word != NULL)
*end_of_word = FALSE;
if (error_flag != NULL)
*error_flag = (cw_receive_state == RS_ERR_CHAR);
*representation = ASC_NUL;
strncat (representation, cw_receive_representation_buffer,
cw_rr_current);
return RC_SUCCESS;
}
/*
* If the timing indicated a word space, again we complete the
* representation and return it. In this case, we also need to
* inform the client that this looked like the end of a word, not
* just a character. And, we don't care about the maximum period,
* only that it exceeds the low end of the range.
*/
if (space_usec > cw_eoc_range_maximum)
{
/*
* In this case, we have a transition to an end of word case.
* If we were sat in an error case, we need to move to the
* correct end of word state, otherwise, at after tone, we
* go safely to the non-error end of word.
*/
if (cw_receive_state == RS_ERR_CHAR)
cw_receive_state = RS_ERR_WORD;
else
cw_receive_state = RS_END_WORD;
/* Print out any state change debug. */
if (cw_get_debug_flags () & CW_DEBUG_RECEIVE_STATES)
fprintf (stderr,
"cw: receive state ->%d\n", cw_receive_state);
/* Return the representation buffered. */
if (end_of_word != NULL)
*end_of_word = TRUE;
if (error_flag != NULL)
*error_flag = (cw_receive_state == RS_ERR_WORD);
*representation = ASC_NUL;
strncat (representation, cw_receive_representation_buffer,
cw_rr_current);
return RC_SUCCESS;
}
/*
* If none of these conditions holds, then we cannot yet make a
* judgement on what we have in the buffer, so return EAGAIN.
*/
errno = EAGAIN;
return RC_ERROR;
}
/**
* cw_receive_character()
*
* Returns the current buffered character from the representation buffer.
* On success, the function returns 0, and fills in unsigned char *c with the
* contents of the current representation buffer, translated into a character.
* On error, it returns -1, with errno set to ERANGE if not preceded by a
* cw_end_receive_tone call, a prior successful cw_receive_character
* call, or a cw_receive_buffer_dot or cw_receive_buffer dash call, EINVAL
* if the timestamp passed in is invalid, or EAGAIN if the call is made too
* early to determine whether a complete character has yet been placed in the
* buffer (that is, less than the inter-character gap period has elapsed since
* the last cw_end_receive_tone or cw_receive_buffer_dot/dash call).
* end_of_word indicates that the delay after the last tone received is
* longer that the inter-word gap, and error_flag indicates that the character
* was terminated by an error condition.
*/
int
cw_receive_character (const struct timeval *timestamp,
unsigned char *c,
int *end_of_word, int *error_flag)
{
int error; /* Error status */
int lend_of_word; /* Local end of word flag */
int lerror_flag; /* Local error flag */
const cw_entry_t *cwptr; /* Pointer to table entry */
char representation[ RECEIVE_CAPACITY + 1 ];
/* Representation buffer */
/* See if we can obtain a representation from the receive routines. */
error = cw_receive_representation (timestamp, representation,
&lend_of_word, &lerror_flag);
if (error)
return error;
/* Look up the representation using the lookup functions. */
cwptr = cw_lookup_representation_internal (representation);
if (cwptr == NULL)
{
errno = ENOENT;
return RC_ERROR;
}
/* If we got this far, all is well, so return what we uncovered. */
if (c != NULL)
*c = cwptr->character;
if (end_of_word != NULL)
*end_of_word = lend_of_word;
if (error_flag != NULL)
*error_flag = lerror_flag;
return RC_SUCCESS;
}
/**
* cw_clear_receive_buffer()
*
* Clears the receive representation buffer to receive tones again. This
* routine must be called after successful, or terminating,
* cw_receive_representation or cw_receive_character calls, to clear the
* states and prepare the buffer to receive more tones.
*/
void
cw_clear_receive_buffer ()
{
cw_rr_current = 0;
cw_receive_state = RS_IDLE;
/* Print out any state change debug. */
if (cw_get_debug_flags () & CW_DEBUG_RECEIVE_STATES)
fprintf (stderr,
"cw: receive state ->%d\n", cw_receive_state);
}
/**
* cw_get_receive_buffer_capacity()
*
* Returns the number of entries the receive buffer can accommodate. The
* maximum number of character written out by cw_receive_representation is
* the capacity + 1, the extra character being used for the terminating
* NUL.
*/
int
cw_get_receive_buffer_capacity ()
{
return RECEIVE_CAPACITY;
}
/**
* cw_get_receive_buffer_length()
*
* Returns the number of elements currently pending in the receive buffer.
*/
int
cw_get_receive_buffer_length ()
{
return cw_rr_current;
}
/*
* cw_keyer_clock_internal implements the following state graph:
*
* +-----------------------------------------------------+
* | (all latches clear) |
* | (dot latch) |
* | +--------------------------+
* | | |
* | v |
* | +-------------> KS_IN_DOT_[A|B] -------> KS_AFTER_DOT_[A|B]
* | |(dot paddle) ^ (delay) |
* | | | |(dash latch/
* | | +------------+ | _B)
* v | | |
* --> KS_IDLE --+ +--------------------------+
* ^ | | |
* | | | +-------------+(dot latch/
* | | | | _B)
* | |(dash paddle) v (delay) |
* | +-------------> KS_IN_DASH_[A|B] -------> KS_AFTER_DASH_[A|B]
* | ^ |
* | | |
* | +--------------------------+
* | (dash latch) |
* | (all latches clear) |
* +-----------------------------------------------------+
*/
static enum {KS_IDLE,KS_IN_DOT_A,KS_IN_DASH_A,KS_AFTER_DOT_A,KS_AFTER_DASH_A,
KS_IN_DOT_B,KS_IN_DASH_B,KS_AFTER_DOT_B,KS_AFTER_DASH_B}
cw_keyer_state = KS_IDLE;
/* Indicates keyer state */
/**
* cw_keyer_clock_internal()
*
* Informs the internal keyer states that the itimer expired, and we
* received SIGALRM.
*/
static void
cw_keyer_clock_internal (int sig)
{
/* Synchronize low level timing parameters if required. */
cw_sync_parameters_internal ();
/* Decide what to do based on the current state. */
switch (cw_keyer_state)
{
/* Ignore calls if our state is idle. */
case KS_IDLE:
return;
/*
* If we were in a dot, turn off tones and begin the after-dot
* delay. Do much the same if we are in a dash. No routine
* status checks are made since we are in a signal handler,
* and can't readily return error codes to the client.
*/
case KS_IN_DOT_A:
case KS_IN_DOT_B:
cw_sound_internal (TONE_SILENT);
cw_key_control_internal (FALSE);
cw_request_timeout_internal (cw_end_of_ele_delay, NULL);
if (cw_keyer_state == KS_IN_DOT_A)
cw_keyer_state = KS_AFTER_DOT_A;
else
cw_keyer_state = KS_AFTER_DOT_B;
/* Print any required debug output. */
if (cw_get_debug_flags () & CW_DEBUG_KEYER_STATES)
fprintf (stderr, "cw: keyer ->%d\n",
cw_keyer_state);
break;
case KS_IN_DASH_A:
case KS_IN_DASH_B:
cw_sound_internal (TONE_SILENT);
cw_key_control_internal (FALSE);
cw_request_timeout_internal (cw_end_of_ele_delay, NULL);
if (cw_keyer_state == KS_IN_DASH_A)
cw_keyer_state = KS_AFTER_DASH_A;
else
cw_keyer_state = KS_AFTER_DASH_B;
/* Print any required debug output. */
if (cw_get_debug_flags () & CW_DEBUG_KEYER_STATES)
fprintf (stderr, "cw: keyer ->%d\n",
cw_keyer_state);
break;
/*
* If we have just finished a dot or a dash and its post-
* element delay, then reset the latches as appropriate.
* Next, if in a _B state, go straight to the opposite
* element state. If in an _A state, check the latch states;
* if the opposite latch is set TRUE, then do the iambic
* thing and alternate dots and dashes. If the same latch
* is TRUE, repeat. And if nothing is true, then revert to
* idling.
*/
case KS_AFTER_DOT_A:
case KS_AFTER_DOT_B:
if (!cw_ik_dot_paddle)
cw_ik_dot_latch = FALSE;
if (cw_keyer_state == KS_AFTER_DOT_B)
{
cw_sound_internal (cw_frequency);
cw_key_control_internal (TRUE);
cw_request_timeout_internal
(cw_send_dash_length, NULL);
cw_keyer_state = KS_IN_DASH_A;
}
else if (cw_ik_dash_latch)
{
cw_sound_internal (cw_frequency);
cw_key_control_internal (TRUE);
cw_request_timeout_internal
(cw_send_dash_length, NULL);
if (cw_ik_curtis_b_latch)
{
cw_ik_curtis_b_latch = FALSE;
cw_keyer_state = KS_IN_DASH_B;
}
else
cw_keyer_state = KS_IN_DASH_A;
}
else if (cw_ik_dot_latch)
{
cw_sound_internal (cw_frequency);
cw_key_control_internal (TRUE);
cw_request_timeout_internal
(cw_send_dot_length, NULL);
cw_keyer_state = KS_IN_DOT_A;
}
else
{
cw_keyer_state = KS_IDLE;
cw_release_timeouts_internal();
}
/* Print any required debug output. */
if (cw_get_debug_flags () & CW_DEBUG_KEYER_STATES)
fprintf (stderr, "cw: keyer ->%d\n",
cw_keyer_state);
break;
case KS_AFTER_DASH_A:
case KS_AFTER_DASH_B:
if (!cw_ik_dash_paddle)
cw_ik_dash_latch = FALSE;
if (cw_keyer_state == KS_AFTER_DASH_B)
{
cw_sound_internal (cw_frequency);
cw_key_control_internal (TRUE);
cw_request_timeout_internal
(cw_send_dot_length, NULL);
cw_keyer_state = KS_IN_DOT_A;
}
else if (cw_ik_dot_latch)
{
cw_sound_internal (cw_frequency);
cw_key_control_internal (TRUE);
cw_request_timeout_internal
(cw_send_dot_length, NULL);
if (cw_ik_curtis_b_latch)
{
cw_ik_curtis_b_latch = FALSE;
cw_keyer_state = KS_IN_DOT_B;
}
else
cw_keyer_state = KS_IN_DOT_A;
}
else if (cw_ik_dash_latch)
{
cw_sound_internal (cw_frequency);
cw_key_control_internal (TRUE);
cw_request_timeout_internal
(cw_send_dash_length, NULL);
cw_keyer_state = KS_IN_DASH_A;
}
else
{
cw_keyer_state = KS_IDLE;
cw_release_timeouts_internal();
}
/* Print any required debug output. */
if (cw_get_debug_flags () & CW_DEBUG_KEYER_STATES)
fprintf (stderr, "cw: keyer ->%d\n",
cw_keyer_state);
break;
}
}
/**
* cw_keyer_paddle_event()
*
* Informs the internal keyer states that the keyer paddles have changed
* state. The new paddle states are recorded, and if either transition from
* FALSE to TRUE, paddle latches, for iambic functions, are also set.
* On success, the routine returns 0. On error, it returns -1, with errno
* set to EBUSY if the tone queue or straight key are using the console
* speaker and keying system.
*
* If appropriate, this routine starts the keyer functions sending the
* relevant element. Element send and timing occurs in the background, so
* this routine returns almost immediately. See cw_keyer_element_wait and
* cw_keyer_wait for details about how to check the current status of
* iambic keyer background processing.
*/
int
cw_keyer_paddle_event (int dot_paddle_state, int dash_paddle_state)
{
/*
* If the tone queue or the straight key are busy, this is going to
* conflict with our use of the console sounder and keying system.
* So return an error status in this case.
*/
if (cw_straightkey_busy () || cw_tone_busy ())
{
errno = EBUSY;
return RC_ERROR;
}
/* Clean up and save the paddle states passed in. */
cw_ik_dot_paddle = (dot_paddle_state != 0);
cw_ik_dash_paddle = (dash_paddle_state != 0);
/*
* Update the paddle latches if either paddle goes TRUE. The
* latches are checked in the signal handler, so if the paddles go
* back to FALSE during this element, the item still gets actioned.
* The signal handler is also responsible for clearing down the
* latches.
*/
if (cw_ik_dot_paddle)
cw_ik_dot_latch = TRUE;
if (cw_ik_dash_paddle)
cw_ik_dash_latch = TRUE;
/*
* If in Curtis mode B, make a special check for both paddles TRUE
* at the same time. This flag is checked by the signal handler,
* to determine whether to add mode B trailing timing elements.
*/
if (cw_ik_curtis_mode_b
&& cw_ik_dot_paddle && cw_ik_dash_paddle)
cw_ik_curtis_b_latch = TRUE;
/* Print any required debug output. */
if (cw_get_debug_flags () & CW_DEBUG_KEYER_STATES)
fprintf (stderr,
"cw: keyer paddles %d,%d, latches %d,%d, curtis_b %d\n",
cw_ik_dot_paddle, cw_ik_dash_paddle,
cw_ik_dot_latch, cw_ik_dash_latch,
cw_ik_curtis_b_latch);
/* If the current state is idle, give the state process a nudge. */
if (cw_keyer_state == KS_IDLE)
{
if (cw_ik_dot_paddle)
{
/* Pretend we just finished a dash. */
if (cw_ik_curtis_b_latch)
cw_keyer_state = KS_AFTER_DASH_B;
else
cw_keyer_state = KS_AFTER_DASH_A;
cw_request_timeout_internal
(0, cw_keyer_clock_internal);
}
else
if (cw_ik_dash_paddle)
{
/* Pretend we just finished a dot. */
if (cw_ik_curtis_b_latch)
cw_keyer_state = KS_AFTER_DOT_B;
else
cw_keyer_state = KS_AFTER_DOT_A;
cw_request_timeout_internal
(0, cw_keyer_clock_internal);
}
}
/* Print any additional required debug output. */
if (cw_get_debug_flags () & CW_DEBUG_KEYER_STATES)
fprintf (stderr, "cw: keyer ->%d\n", cw_keyer_state);
return RC_SUCCESS;
}
/**
* cw_keyer_dot_paddle_event()
* cw_keyer_dash_paddle_event()
*
* Convenience functions to alter the state of just one of the two iambic
* keyer paddles. The other paddle state of the paddle pair remains
* unchanged.
*
* See cw_keyer_paddle_event for details of iambic keyer background
* processing, and how to check its status.
*/
int
cw_keyer_dot_paddle_event (int dot_paddle_state)
{
return cw_keyer_paddle_event (dot_paddle_state, cw_ik_dash_paddle);
}
int
cw_keyer_dash_paddle_event (int dash_paddle_state)
{
return cw_keyer_paddle_event (cw_ik_dot_paddle, dash_paddle_state);
}
/**
* cw_get_keyer_paddles()
*
* Returns the current saved states of the two paddles.
*/
void
cw_get_keyer_paddles (int *dot_paddle_state, int *dash_paddle_state)
{
if (dot_paddle_state != NULL)
*dot_paddle_state = cw_ik_dot_paddle;
if (dash_paddle_state != NULL)
*dash_paddle_state = cw_ik_dash_paddle;
}
/**
* cw_get_keyer_paddle_latches()
*
* Returns the current saved states of the two paddle latches. A paddle
* latches is set to TRUE when the paddle state becomes true, and is
* cleared if the paddle state is FALSE when the element finishes sending.
*/
void
cw_get_keyer_paddle_latches (int *dot_paddle_latch_state,
int *dash_paddle_latch_state)
{
if (dot_paddle_latch_state != NULL)
*dot_paddle_latch_state = cw_ik_dot_latch;
if (dash_paddle_latch_state != NULL)
*dash_paddle_latch_state = cw_ik_dash_latch;
}
/**
* cw_keyer_busy()
*
* Indicates if the keyer is busy; returns TRUE if the keyer is going
* through a dot or dash cycle, FALSE if the keyer is idle.
*/
int
cw_keyer_busy ()
{
return (cw_keyer_state != KS_IDLE);
}
/**
* cw_keyer_element_wait()
*
* Waits until the end of the current element, dot or dash, from the
* keyer. This routine returns 0 on success. On error, it returns -1, with
* errno set to EDEADLK if SIGALRM is blocked.
*/
int
cw_keyer_element_wait()
{
int error; /* Error status */
/* Check that SIGALRM is not blocked. */
error = cw_check_signal_mask_internal ();
if (error)
return error;
/*
* First wait for the state to move to idle (or just do nothing
* if it's not), or to one of the after- states.
*/
while (cw_keyer_state != KS_IDLE
&& cw_keyer_state != KS_AFTER_DOT_A
&& cw_keyer_state != KS_AFTER_DOT_B
&& cw_keyer_state != KS_AFTER_DASH_A
&& cw_keyer_state != KS_AFTER_DASH_B)
cw_signal_wait_internal ();
/*
* Now wait for the state to move to idle (unless it is, or was,
* already), or one of the in- states, at which point we know
* we're actually at the end of the element we were in when we
* entered this routine.
*/
while (cw_keyer_state != KS_IDLE
&& cw_keyer_state != KS_IN_DOT_A
&& cw_keyer_state != KS_IN_DOT_B
&& cw_keyer_state != KS_IN_DASH_A
&& cw_keyer_state != KS_IN_DASH_B)
cw_signal_wait_internal ();
return RC_SUCCESS;
}
/**
* cw_keyer_wait()
*
* Waits for the current keyer cycle to complete. The routine returns 0
* on success. On error, it returns -1, with errno set to EDEADLK if
* SIGALRM is blocked or if either paddle state is TRUE.
*/
int
cw_keyer_wait ()
{
int error; /* Error status */
/* Check that SIGALRM is not blocked. */
error = cw_check_signal_mask_internal ();
if (error)
return error;
/*
* Check that neither paddle is TRUE; if either is, then the
* signal cycle is going to continue forever, and we'll never
* return from this routine.
*/
if (cw_ik_dot_paddle || cw_ik_dash_paddle)
{
errno = EDEADLK;
return RC_ERROR;
}
/* Wait for the keyer state to go idle. */
while (cw_keyer_state != KS_IDLE)
cw_signal_wait_internal ();
return RC_SUCCESS;
}
/**
* cw_straightkey_event()
*
* Informs the library that the straight key has changed state. This routine
* returns 0 on success. On error, it returns -1, with errno set to EBUSY
* if the tone queue or iambic keyer are using the console speaker and keying
* control system. If key_state indicates no change of state, the call is
* ignored.
*/
int
cw_straightkey_event (int key_state)
{
/*
* If the tone queue or the keyer are busy, we can't use the console
* sounder or the key control system.
*/
if (cw_tone_busy () || cw_keyer_busy ())
{
errno = EBUSY;
return RC_ERROR;
}
/* If the key state did not change, ignore the call. */
if ((cw_sk_key_down && !key_state)
|| (!cw_sk_key_down && key_state))
{
/* Save the new key state. */
cw_sk_key_down = (key_state != 0);
/* Print out any debug about the new key state. */
if (cw_get_debug_flags() & CW_DEBUG_STRAIGHTKEY)
fprintf (stderr, "cw: straight key state ->%s\n",
cw_sk_key_down ? "DOWN" : "UP");
/* Do tones and keying to match the new key state. */
if (cw_sk_key_down)
{
cw_sound_internal (cw_frequency);
cw_key_control_internal (TRUE);
}
else
{
cw_sound_internal (TONE_SILENT);
cw_key_control_internal (FALSE);
}
}
return RC_SUCCESS;
}
/**
* cw_get_straightkey_state()
*
* Returns the current saved state of the straight key; TRUE if the key is
* down, FALSE if up.
*/
int
cw_get_straightkey_state ()
{
return cw_sk_key_down;
}
/**
* cw_straightkey_busy()
*
* Returns TRUE if the straight key is busy, FALSE if not. This routine is
* just a pseudonym for cw_get_straightkey_state, and exists to fill a hole
* in the API naming conventions.
*/
int
cw_straightkey_busy ()
{
return cw_sk_key_down;
}
|