├── .gitignore ├── LICENSE.txt ├── README.md ├── icons └── ADIlogo.png ├── jesd.glade ├── jesd_common.c ├── jesd_common.h ├── jesd_eye_scan.c ├── jesd_eye_scan.desktop ├── jesd_eye_scan_autostart.sh ├── jesd_status.c └── makefile /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Libraries 8 | *.lib 9 | *.a 10 | 11 | # Shared objects (inc. Windows DLLs) 12 | *.dll 13 | *.so 14 | *.so.* 15 | *.dylib 16 | 17 | # Executables 18 | *.exe 19 | *.out 20 | *.app 21 | *.i*86 22 | *.x86_64 23 | *.hex 24 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright 2014-2018(c) Analog Devices, Inc. 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | - Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | - Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the 13 | distribution. 14 | - Neither the name of Analog Devices, Inc. nor the names of its 15 | contributors may be used to endorse or promote products derived 16 | from this software without specific prior written permission. 17 | - The use of this software may or may not infringe the patent rights 18 | of one or more patent holders. This license does not release you 19 | from the requirement that you obtain separate licenses from these 20 | patent holders to use this software. 21 | - Use of the software either in source or binary form, must be run 22 | on or directly connected to an Analog Devices Inc. component. 23 | 24 | THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 25 | INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A 26 | PARTICULAR PURPOSE ARE DISCLAIMED. 27 | 28 | IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, INTELLECTUAL PROPERTY 30 | RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 31 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 33 | THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | jesd-eye-scan-gtk 2 | ================= 3 | 4 | JESD204 Eye Scan Visualization Utility 5 | 6 | Weblinks: 7 | http://wiki.analog.com/resources/tools-software/linux-software/jesd_eye_scan 8 | -------------------------------------------------------------------------------- /icons/ADIlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/analogdevicesinc/jesd-eye-scan-gtk/a9ed0b88af5c6dbc395a9aef40c5fd68460b6df1/icons/ADIlogo.png -------------------------------------------------------------------------------- /jesd.glade: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | False 8 | 2D Statistical Eye Scan 9 | 10 | 11 | True 12 | True 13 | 14 | 15 | True 16 | False 17 | 5 18 | 5 19 | 5 20 | 5 21 | 0 22 | in 23 | 24 | 25 | True 26 | False 27 | 12 28 | 29 | 30 | True 31 | False 32 | vertical 33 | 34 | 35 | True 36 | False 37 | 38 | 39 | True 40 | False 41 | 42 | 43 | 44 | 0 45 | 0 46 | 47 | 48 | 49 | 50 | False 51 | True 52 | 2 53 | 0 54 | 55 | 56 | 57 | 58 | True 59 | False 60 | 5 61 | 5 62 | 5 63 | 5 64 | 0 65 | in 66 | 67 | 68 | True 69 | False 70 | 12 71 | 72 | 73 | True 74 | False 75 | 76 | 77 | True 78 | False 79 | 5 80 | 2 81 | Link is 82 | 0 83 | 84 | 85 | 0 86 | 0 87 | 88 | 89 | 90 | 91 | True 92 | False 93 | 5 94 | 2 95 | Link Status 96 | 0 97 | 98 | 99 | 0 100 | 1 101 | 102 | 103 | 104 | 105 | True 106 | False 107 | 5 108 | 2 109 | Measured Link Clock 110 | 0 111 | 112 | 113 | 0 114 | 2 115 | 116 | 117 | 118 | 119 | True 120 | False 121 | 5 122 | 2 123 | Reported Link Clock 124 | 0 125 | 126 | 127 | 0 128 | 3 129 | 130 | 131 | 132 | 133 | True 134 | False 135 | 5 136 | 2 137 | Lane rate 138 | 0 139 | 140 | 141 | 0 142 | 4 143 | 144 | 145 | 146 | 147 | True 148 | False 149 | 5 150 | 2 151 | Lane rate / 40 152 | 0 153 | 154 | 155 | 0 156 | 5 157 | 158 | 159 | 160 | 161 | True 162 | False 163 | 5 164 | 2 165 | SYSREF captured 166 | 0 167 | 168 | 169 | 0 170 | 7 171 | 172 | 173 | 174 | 175 | True 176 | False 177 | 5 178 | 2 179 | SYSREF alignment error 180 | 0 181 | 182 | 183 | 0 184 | 8 185 | 186 | 187 | 188 | 189 | True 190 | False 191 | 5 192 | 2 193 | SYNC~ 194 | 0 195 | 196 | 197 | 0 198 | 9 199 | 200 | 201 | 202 | 203 | True 204 | False 205 | 5 206 | 2 207 | 0 208 | 209 | 210 | 1 211 | 0 212 | 213 | 214 | 215 | 216 | True 217 | False 218 | 5 219 | 2 220 | 0 221 | 222 | 223 | 1 224 | 1 225 | 226 | 227 | 228 | 229 | True 230 | False 231 | 5 232 | 2 233 | 0 234 | 235 | 236 | 1 237 | 2 238 | 239 | 240 | 241 | 242 | True 243 | False 244 | 5 245 | 2 246 | 0 247 | 248 | 249 | 1 250 | 3 251 | 252 | 253 | 254 | 255 | True 256 | False 257 | 5 258 | 2 259 | 0 260 | 261 | 262 | 1 263 | 4 264 | 265 | 266 | 267 | 268 | True 269 | False 270 | 5 271 | 2 272 | 0 273 | 274 | 275 | 1 276 | 5 277 | 278 | 279 | 280 | 281 | True 282 | False 283 | 5 284 | 2 285 | 0 286 | 287 | 288 | 1 289 | 7 290 | 291 | 292 | 293 | 294 | True 295 | False 296 | 5 297 | 2 298 | 0 299 | 300 | 301 | 1 302 | 8 303 | 304 | 305 | 306 | 307 | True 308 | False 309 | 5 310 | 2 311 | 0 312 | 313 | 314 | 1 315 | 9 316 | 317 | 318 | 319 | 320 | True 321 | False 322 | 5 323 | 2 324 | LMFC rate 325 | 0 326 | 327 | 328 | 0 329 | 6 330 | 331 | 332 | 333 | 334 | True 335 | False 336 | 5 337 | 2 338 | 0 339 | 340 | 341 | 1 342 | 6 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | True 352 | False 353 | 2 354 | <b>Status</b> 355 | True 356 | end 357 | 358 | 359 | 360 | 361 | False 362 | True 363 | 2 364 | 1 365 | 366 | 367 | 368 | 369 | True 370 | False 371 | 5 372 | 5 373 | 5 374 | 5 375 | 0 376 | in 377 | 378 | 379 | True 380 | False 381 | 12 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | True 390 | False 391 | 2 392 | <b>LANE Status</b> 393 | True 394 | 395 | 396 | 397 | 398 | False 399 | True 400 | 2 401 | 2 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | True 411 | False 412 | 2 413 | <b>JESD204 Interface Device Select</b> 414 | True 415 | 416 | 417 | 418 | 419 | 420 | 421 | True 422 | False 423 | Status Information 424 | 425 | 426 | False 427 | 428 | 429 | 430 | 431 | True 432 | False 433 | 0 434 | none 435 | 436 | 437 | True 438 | False 439 | 12 440 | 441 | 442 | True 443 | True 444 | in 445 | 446 | 447 | True 448 | False 449 | 450 | 451 | True 452 | False 453 | vertical 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | True 468 | False 469 | <b>Per Lane JESD204 ILAS Information</b> 470 | True 471 | 472 | 473 | 474 | 475 | 1 476 | 477 | 478 | 479 | 480 | True 481 | False 482 | ILAS Lane Information 483 | 484 | 485 | 1 486 | False 487 | 488 | 489 | 490 | 491 | True 492 | False 493 | vertical 494 | 495 | 496 | True 497 | False 498 | vertical 499 | 500 | 501 | 502 | 503 | 504 | True 505 | True 506 | 0 507 | 508 | 509 | 510 | 511 | True 512 | False 513 | 5 514 | 515 | 520 | 521 | 0 522 | 0 523 | 524 | 525 | 526 | 527 | False 528 | False 529 | 5 530 | end 531 | 1 532 | 533 | 534 | 535 | 536 | True 537 | False 538 | 0 539 | none 540 | 541 | 542 | True 543 | False 544 | 12 545 | 546 | 547 | True 548 | False 549 | 5 550 | 5 551 | 552 | 553 | True 554 | False 555 | 0 556 | none 557 | 558 | 559 | True 560 | False 561 | 12 562 | 563 | 564 | True 565 | False 566 | 567 | 568 | LANE 0 569 | False 570 | True 571 | True 572 | False 573 | True 574 | 0 575 | True 576 | True 577 | 578 | 579 | 0 580 | 0 581 | 582 | 583 | 584 | 585 | LANE 1 586 | False 587 | True 588 | True 589 | False 590 | True 591 | 0 592 | True 593 | True 594 | 595 | 596 | 0 597 | 1 598 | 599 | 600 | 601 | 602 | LANE 2 603 | False 604 | True 605 | True 606 | False 607 | True 608 | 0 609 | True 610 | True 611 | 612 | 613 | 0 614 | 2 615 | 616 | 617 | 618 | 619 | LANE 3 620 | False 621 | True 622 | True 623 | False 624 | True 625 | 0 626 | True 627 | True 628 | 629 | 630 | 0 631 | 3 632 | 633 | 634 | 635 | 636 | LANE 4 637 | False 638 | True 639 | True 640 | False 641 | True 642 | 0 643 | True 644 | True 645 | 646 | 647 | 0 648 | 4 649 | 650 | 651 | 652 | 653 | LANE 5 654 | False 655 | True 656 | True 657 | False 658 | True 659 | 0 660 | True 661 | True 662 | 663 | 664 | 0 665 | 5 666 | 667 | 668 | 669 | 670 | LANE 6 671 | False 672 | True 673 | True 674 | False 675 | True 676 | 0 677 | True 678 | True 679 | 680 | 681 | 0 682 | 6 683 | 684 | 685 | 686 | 687 | LANE 7 688 | False 689 | True 690 | True 691 | False 692 | True 693 | 0 694 | True 695 | True 696 | 697 | 698 | 0 699 | 7 700 | 701 | 702 | 703 | 704 | LANE 8 705 | False 706 | True 707 | True 708 | False 709 | True 710 | 0 711 | True 712 | True 713 | 714 | 715 | 1 716 | 0 717 | 718 | 719 | 720 | 721 | LANE 9 722 | False 723 | True 724 | True 725 | False 726 | True 727 | 0 728 | True 729 | True 730 | 731 | 732 | 1 733 | 1 734 | 735 | 736 | 737 | 738 | LANE 10 739 | False 740 | True 741 | True 742 | False 743 | True 744 | 0 745 | True 746 | True 747 | 748 | 749 | 1 750 | 2 751 | 752 | 753 | 754 | 755 | LANE 11 756 | False 757 | True 758 | True 759 | False 760 | True 761 | 0 762 | True 763 | True 764 | 765 | 766 | 1 767 | 3 768 | 769 | 770 | 771 | 772 | LANE 12 773 | False 774 | True 775 | True 776 | False 777 | True 778 | 0 779 | True 780 | True 781 | 782 | 783 | 1 784 | 4 785 | 786 | 787 | 788 | 789 | LANE 13 790 | False 791 | True 792 | True 793 | False 794 | True 795 | 0 796 | True 797 | True 798 | 799 | 800 | 1 801 | 5 802 | 803 | 804 | 805 | 806 | LANE 14 807 | False 808 | True 809 | True 810 | False 811 | True 812 | 0 813 | True 814 | True 815 | 816 | 817 | 1 818 | 6 819 | 820 | 821 | 822 | 823 | LANE 15 824 | False 825 | True 826 | True 827 | False 828 | True 829 | 0 830 | True 831 | True 832 | 833 | 834 | 1 835 | 7 836 | 837 | 838 | 839 | 840 | LANE 16 841 | False 842 | True 843 | True 844 | False 845 | True 846 | 0 847 | True 848 | True 849 | 850 | 851 | 2 852 | 0 853 | 854 | 855 | 856 | 857 | LANE 17 858 | False 859 | True 860 | True 861 | False 862 | True 863 | 0 864 | True 865 | True 866 | 867 | 868 | 2 869 | 1 870 | 871 | 872 | 873 | 874 | LANE 18 875 | False 876 | True 877 | True 878 | False 879 | True 880 | 0 881 | True 882 | True 883 | 884 | 885 | 2 886 | 2 887 | 888 | 889 | 890 | 891 | LANE 19 892 | False 893 | True 894 | True 895 | False 896 | True 897 | 0 898 | True 899 | True 900 | 901 | 902 | 2 903 | 3 904 | 905 | 906 | 907 | 908 | LANE 20 909 | False 910 | True 911 | True 912 | False 913 | True 914 | 0 915 | True 916 | True 917 | 918 | 919 | 2 920 | 4 921 | 922 | 923 | 924 | 925 | LANE 21 926 | False 927 | True 928 | True 929 | False 930 | True 931 | 0 932 | True 933 | True 934 | 935 | 936 | 2 937 | 5 938 | 939 | 940 | 941 | 942 | LANE 22 943 | False 944 | True 945 | True 946 | False 947 | True 948 | 0 949 | True 950 | True 951 | 952 | 953 | 2 954 | 6 955 | 956 | 957 | 958 | 959 | LANE 23 960 | False 961 | True 962 | True 963 | False 964 | True 965 | 0 966 | True 967 | True 968 | 969 | 970 | 2 971 | 7 972 | 973 | 974 | 975 | 976 | LANE 24 977 | False 978 | True 979 | True 980 | False 981 | True 982 | 0 983 | True 984 | True 985 | 986 | 987 | 3 988 | 0 989 | 990 | 991 | 992 | 993 | LANE 25 994 | False 995 | True 996 | True 997 | False 998 | True 999 | 0 1000 | True 1001 | True 1002 | 1003 | 1004 | 3 1005 | 1 1006 | 1007 | 1008 | 1009 | 1010 | LANE 26 1011 | False 1012 | True 1013 | True 1014 | False 1015 | True 1016 | 0 1017 | True 1018 | True 1019 | 1020 | 1021 | 3 1022 | 2 1023 | 1024 | 1025 | 1026 | 1027 | LANE 27 1028 | False 1029 | True 1030 | True 1031 | False 1032 | True 1033 | 0 1034 | True 1035 | True 1036 | 1037 | 1038 | 3 1039 | 3 1040 | 1041 | 1042 | 1043 | 1044 | LANE 28 1045 | False 1046 | True 1047 | True 1048 | False 1049 | True 1050 | 0 1051 | True 1052 | True 1053 | 1054 | 1055 | 3 1056 | 4 1057 | 1058 | 1059 | 1060 | 1061 | LANE 29 1062 | False 1063 | True 1064 | True 1065 | False 1066 | True 1067 | 0 1068 | True 1069 | True 1070 | 1071 | 1072 | 3 1073 | 5 1074 | 1075 | 1076 | 1077 | 1078 | LANE 30 1079 | False 1080 | True 1081 | True 1082 | False 1083 | True 1084 | 0 1085 | True 1086 | True 1087 | 1088 | 1089 | 3 1090 | 6 1091 | 1092 | 1093 | 1094 | 1095 | LANE 31 1096 | False 1097 | True 1098 | True 1099 | False 1100 | True 1101 | 0 1102 | True 1103 | True 1104 | 1105 | 1106 | 3 1107 | 7 1108 | 1109 | 1110 | 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | True 1117 | False 1118 | <b>Lanes</b> 1119 | True 1120 | 1121 | 1122 | 1123 | 1124 | 0 1125 | 0 1126 | 1127 | 1128 | 1129 | 1130 | True 1131 | False 1132 | 0 1133 | none 1134 | 1135 | 1136 | True 1137 | False 1138 | 12 1139 | 1140 | 1141 | True 1142 | False 1143 | 5 1144 | 2 1145 | 1146 | 1147 | True 1148 | False 1149 | Min 1150 | 1151 | 1152 | 0 1153 | 0 1154 | 1155 | 1156 | 1157 | 1158 | True 1159 | False 1160 | Max 1161 | 1162 | 1163 | 0 1164 | 1 1165 | 1166 | 1167 | 1168 | 1169 | True 1170 | False 1171 | vertical 1172 | 1173 | 1174 | True 1175 | False 1176 | 1177 | 1178 | False 1179 | False 1180 | 0 1181 | 1182 | 1183 | 1184 | 1185 | 1 1186 | 0 1187 | 1188 | 1189 | 1190 | 1191 | True 1192 | False 1193 | vertical 1194 | 1195 | 1196 | True 1197 | False 1198 | 1199 | 1200 | False 1201 | False 1202 | 0 1203 | 1204 | 1205 | 1206 | 1207 | 1 1208 | 1 1209 | 1210 | 1211 | 1212 | 1213 | 1214 | 1215 | 1216 | 1217 | True 1218 | False 1219 | <b>BER Scan Depth</b> 1220 | True 1221 | 1222 | 1223 | 1224 | 1225 | 1 1226 | 0 1227 | 1228 | 1229 | 1230 | 1231 | True 1232 | False 1233 | 0 1234 | none 1235 | 1236 | 1237 | True 1238 | False 1239 | 12 1240 | 1241 | 1242 | True 1243 | True 1244 | in 1245 | 200 1246 | 1247 | 1248 | True 1249 | True 1250 | natural 1251 | natural 1252 | False 1253 | 5 1254 | 1255 | 1256 | 1257 | 1258 | 1259 | 1260 | 1261 | 1262 | True 1263 | False 1264 | <b>Info</b> 1265 | True 1266 | 1267 | 1268 | 1269 | 1270 | 3 1271 | 0 1272 | 1273 | 1274 | 1275 | 1276 | True 1277 | False 1278 | vertical 1279 | 1280 | 1281 | True 1282 | False 1283 | 0 1284 | none 1285 | 1286 | 1287 | True 1288 | False 1289 | 12 1290 | 1291 | 1292 | True 1293 | False 1294 | vertical 1295 | 1296 | 1297 | 0 1298 | 0 1299 | True 1300 | False 1301 | 1302 | 1303 | 1304 | False 1305 | False 1306 | 0 1307 | 1308 | 1309 | 1310 | 1311 | 1312 | 1313 | 1314 | 1315 | True 1316 | False 1317 | <b>Device Select</b> 1318 | True 1319 | 1320 | 1321 | 1322 | 1323 | False 1324 | True 1325 | 0 1326 | 1327 | 1328 | 1329 | 1330 | True 1331 | False 1332 | 0 1333 | none 1334 | 1335 | 1336 | True 1337 | False 1338 | 12 1339 | 1340 | 1341 | True 1342 | False 1343 | vertical 1344 | 1345 | 1346 | 0 1347 | 0 1348 | True 1349 | False 1350 | 1351 | 1352 | 1353 | False 1354 | False 1355 | 0 1356 | 1357 | 1358 | 1359 | 1360 | 1361 | 1362 | 1363 | 1364 | True 1365 | False 1366 | <b>Display Select</b> 1367 | True 1368 | 1369 | 1370 | 1371 | 1372 | False 1373 | True 1374 | 1 1375 | 1376 | 1377 | 1378 | 1379 | 2 1380 | 0 1381 | 1382 | 1383 | 1384 | 1385 | 1386 | 1387 | 1388 | 1389 | True 1390 | False 1391 | 5 1392 | <b>JESD204B Statistical Eye Scan Parameters</b> 1393 | True 1394 | 1395 | 1396 | 1397 | 1398 | False 1399 | True 1400 | 2 1401 | 1402 | 1403 | 1404 | 1405 | True 1406 | False 1407 | 5 1408 | end 1409 | 1410 | 1411 | 260 1412 | True 1413 | False 1414 | 1 1415 | True 1416 | 1417 | 1418 | True 1419 | True 1420 | 5 1421 | 0 1422 | True 1423 | 1424 | 1425 | 1426 | 1427 | SAVE PNG 1428 | False 1429 | True 1430 | True 1431 | True 1432 | 1433 | 1434 | 1435 | False 1436 | False 1437 | end 1438 | 1 1439 | 1440 | 1441 | 1442 | 1443 | STOP 1444 | False 1445 | True 1446 | True 1447 | True 1448 | 1449 | 1450 | 1451 | False 1452 | False 1453 | end 1454 | 2 1455 | 1456 | 1457 | 1458 | 1459 | START 1460 | False 1461 | True 1462 | True 1463 | True 1464 | 1465 | 1466 | 1467 | False 1468 | False 1469 | end 1470 | 3 1471 | 1472 | 1473 | 1474 | 1475 | False 1476 | True 1477 | 3 1478 | 1479 | 1480 | 1481 | 1482 | 2 1483 | 1484 | 1485 | 1486 | 1487 | True 1488 | False 1489 | Eye Scan 1490 | 1491 | 1492 | 2 1493 | False 1494 | 1495 | 1496 | 1497 | 1498 | 1499 | 1500 | -------------------------------------------------------------------------------- /jesd_common.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************//** 2 | * @file jesd_common.c 3 | * @brief JESD204 Status Information Utility 4 | * @author Michael Hennerich (michael.hennerich@analog.com) 5 | ******************************************************************************** 6 | * Copyright 2019 (c) Analog Devices, Inc. 7 | * 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are met: 12 | * - Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * - Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in 16 | * the documentation and/or other materials provided with the 17 | * distribution. 18 | * - Neither the name of Analog Devices, Inc. nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * - The use of this software may or may not infringe the patent rights 22 | * of one or more patent holders. This license does not release you 23 | * from the requirement that you obtain separate licenses from these 24 | * patent holders to use this software. 25 | * - Use of the software either in source or binary form, must be run 26 | * on or directly connected to an Analog Devices Inc. component. 27 | * 28 | * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR 29 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, 30 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 31 | * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, 32 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 33 | * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR 34 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 35 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 36 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | *******************************************************************************/ 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include "jesd_common.h" 49 | 50 | char *get_full_device_path(const char *basedir, const char *device) 51 | { 52 | static char path[PATH_MAX]; 53 | 54 | snprintf(path, sizeof(path), "%s/%s", basedir, device); 55 | 56 | return path; 57 | } 58 | 59 | int jesd_find_devices(const char *basedir, const char *driver, const char *file_exists, 60 | char devices[MAX_DEVICES][PATH_MAX], int start) 61 | { 62 | struct dirent *de; 63 | struct stat sfile, efile; 64 | char path[PATH_MAX]; 65 | char stat_path[PATH_MAX]; 66 | DIR *dr; 67 | int num = start, use = 1; 68 | 69 | snprintf(path, sizeof(path), "%s/%s", basedir, driver); 70 | dr = opendir(path); 71 | if (dr == NULL) { 72 | fprintf(stderr, "Could not open current directory\n"); 73 | return 0; 74 | } 75 | 76 | while ((de = readdir(dr)) != NULL) { 77 | snprintf(stat_path, sizeof(stat_path), "%s/%s", path, de->d_name); 78 | 79 | if (lstat(stat_path, &sfile) == -1) 80 | continue; 81 | 82 | if (file_exists && S_ISLNK(sfile.st_mode)) { 83 | snprintf(stat_path, sizeof(stat_path), "%s/%s/%s", path, de->d_name, file_exists); 84 | if (stat(stat_path, &efile) == 0) 85 | use = 1; 86 | else 87 | use = 0; 88 | } 89 | 90 | if (S_ISLNK(sfile.st_mode) && use && num < MAX_DEVICES) { 91 | snprintf((char *)&devices[num], PATH_MAX, "%s/%s", driver, de->d_name); 92 | num++; 93 | } 94 | } 95 | 96 | closedir(dr); 97 | 98 | return num; 99 | } 100 | 101 | int read_encoding(const char *basedir) 102 | { 103 | char temp[PATH_MAX]; 104 | char encoder[MAX_SYSFS_STRING_SIZE]; 105 | FILE *f; 106 | int ret; 107 | 108 | memset(encoder, 0, sizeof(encoder)); 109 | 110 | sprintf(temp, "%s/encoder", basedir); 111 | f = fopen(temp, "r"); 112 | /* 113 | * If the file is not there, default to 8b10b. It might be an older 114 | * kernel and, most likely, only supports jesd204b 115 | */ 116 | if (!f && errno == ENOENT) 117 | return JESD204_ENCODER_8B10B; 118 | else if (!f) 119 | return -errno; 120 | 121 | fread(encoder, sizeof(encoder), 1, f); 122 | 123 | if (!strcmp(encoder, "8b10b")) 124 | ret = JESD204_ENCODER_8B10B; 125 | else 126 | ret = JESD204_ENCODER_64B66B; 127 | 128 | fclose(f); 129 | 130 | return ret; 131 | } 132 | 133 | int read_laneinfo(const char *basedir, unsigned lane, 134 | struct jesd204b_laneinfo *info) 135 | { 136 | FILE *pFile; 137 | char temp[PATH_MAX]; 138 | int ret = 0; 139 | int encoder = read_encoding(basedir); 140 | 141 | if (encoder < 0) 142 | return encoder; 143 | 144 | memset(info, 0, sizeof(*info)); 145 | 146 | sprintf(temp, "%s/lane%d_info", basedir, lane); 147 | 148 | pFile = fopen(temp, "r"); 149 | 150 | if (pFile == NULL) 151 | return -errno; 152 | 153 | ret = fscanf(pFile, "Errors: %u\n", &info->lane_errors); 154 | if (encoder == JESD204_ENCODER_64B66B) { 155 | ret += fscanf(pFile, "State of Extended multiblock alignment:%s\n", 156 | (char *)&info->ext_multiblock_align_state); 157 | goto close_f; 158 | }; 159 | ret += fscanf(pFile, "CGS state: %s\n", (char *)&info->cgs_state); 160 | ret += fscanf(pFile, "Initial Frame Synchronization: %s\n", 161 | (char *)&info->init_frame_sync); 162 | ret += fscanf(pFile, "Lane Latency: %d Multi-frames and %d Octets\n", 163 | &info->lane_latency_multiframes, &info->lane_latency_octets); 164 | ret += fscanf(pFile, "Initial Lane Alignment Sequence: %s\n", 165 | (char *)&info->init_lane_align_seq); 166 | 167 | ret += fscanf(pFile, 168 | "DID: %d, BID: %d, LID: %d, L: %d, SCR: %d, F: %d\n", 169 | &info->did, 170 | &info->bid, 171 | &info->lid, 172 | &info->l, 173 | &info->scr, &info->f); 174 | 175 | if (ret <= 0) { 176 | fclose(pFile); 177 | return -errno; 178 | } 179 | 180 | ret += fscanf(pFile, 181 | "K: %d, M: %d, N: %d, CS: %d, N': %d, S: %d, HD: %d\n", 182 | &info->k, 183 | &info->m, 184 | &info->n, 185 | &info->cs, 186 | &info->nd, 187 | &info->s, &info->hd); 188 | 189 | ret += fscanf(pFile, "FCHK: 0x%X, CF: %d\n", 190 | &info->fchk, &info->cf); 191 | 192 | ret += fscanf(pFile, 193 | "ADJCNT: %d, PHADJ: %d, ADJDIR: %d, JESDV: %d, SUBCLASS: %d\n", 194 | &info->adjcnt, 195 | &info->phyadj, 196 | &info->adjdir, 197 | &info->jesdv, &info->subclassv); 198 | 199 | ret += fscanf(pFile, "FC: %lu\n", &info->fc); 200 | close_f: 201 | fclose(pFile); 202 | 203 | return ret; 204 | } 205 | 206 | int read_all_laneinfo(const char *path, struct jesd204b_laneinfo lane_info[MAX_LANES]) 207 | { 208 | struct stat buf; 209 | int i, ret, cnt = 0; 210 | 211 | if (!stat(path, &buf)) { 212 | for (i = 0; i < MAX_LANES; i++) { 213 | ret = read_laneinfo(path, i, &lane_info[i]); 214 | 215 | if (ret < 0) { 216 | /* No child processes */ 217 | if (ret == -ECHILD) 218 | fprintf(stderr, "not root %i, when looking for lane %i\n", ret, i); 219 | 220 | return cnt; 221 | 222 | } else { 223 | cnt++; 224 | } 225 | } 226 | } else { 227 | fprintf(stderr, "Failed to find JESD device: %s\n", path); 228 | return 0; 229 | } 230 | 231 | return cnt; 232 | } 233 | 234 | void set_not_availabe(char *str) 235 | { 236 | str[0] = 'N'; 237 | str[1] = '/'; 238 | str[2] = 'A'; 239 | str[3] = 0; 240 | } 241 | 242 | int read_jesd204_status(const char *basedir, 243 | struct jesd204b_jesd204_status *info) 244 | { 245 | FILE *pFile; 246 | char temp[PATH_MAX]; 247 | long pos; 248 | int ret = 0; 249 | int encoder = read_encoding(basedir); 250 | 251 | if (encoder < 0) 252 | return encoder; 253 | 254 | sprintf(temp, "%s/status", basedir); 255 | 256 | memset(info, 0, sizeof(*info)); 257 | 258 | pFile = fopen(temp, "r"); 259 | 260 | if (pFile == NULL) { 261 | fprintf(stderr, "Failed to read JESD204 device file: %s\n", 262 | temp); 263 | return -errno; 264 | } 265 | 266 | ret = fscanf(pFile, "Link is %s\n", (char *)&info->link_state); 267 | ret = fscanf(pFile, "Measured Link Clock: %s MHz\n", 268 | (char *)&info->measured_link_clock); 269 | ret = fscanf(pFile, "Reported Link Clock: %s MHz\n", 270 | (char *)&info->reported_link_clock); 271 | 272 | pos = ftell(pFile); 273 | ret = fscanf(pFile, "Measured Device Clock: %s MHz\n", 274 | (char *)&info->measured_device_clock); 275 | 276 | if (ret == 1) { 277 | ret = fscanf(pFile, "Reported Device Clock: %s MHz\n", 278 | (char *)&info->reported_device_clock); 279 | ret = fscanf(pFile, "Desired Device Clock: %s MHz\n", 280 | (char *)&info->desired_device_clock); 281 | } else { 282 | set_not_availabe(info->measured_device_clock); 283 | set_not_availabe(info->reported_device_clock); 284 | set_not_availabe(info->desired_device_clock); 285 | fseek(pFile, pos, SEEK_SET); 286 | } 287 | 288 | pos = ftell(pFile); 289 | ret = fscanf(pFile, "Lane rate: %s MHz\n", (char *)&info->lane_rate); 290 | 291 | if (ret != 1) { 292 | fseek(pFile, pos, SEEK_SET); 293 | ret = fscanf(pFile, "External reset is %s\n", (char *)&info->external_reset); 294 | fclose(pFile); 295 | 296 | return ret; 297 | } 298 | 299 | if (encoder == JESD204_ENCODER_8B10B) { 300 | ret = fscanf(pFile, "Lane rate / 40: %s MHz\n", (char *)&info->lane_rate_div); 301 | ret = fscanf(pFile, "LMFC rate: %s MHz\n", (char *)&info->lmfc_rate); 302 | 303 | /* Only on TX */ 304 | pos = ftell(pFile); 305 | ret = fscanf(pFile, "SYNC~: %s\n", (char *)&info->sync_state); 306 | 307 | if (ret != 1) 308 | fseek(pFile, pos, SEEK_SET); 309 | } else { 310 | ret = fscanf(pFile, "Lane rate / 66: %s MHz\n", (char *)&info->lane_rate_div); 311 | ret = fscanf(pFile, "LEMC rate: %s MHz\n", (char *)&info->lmfc_rate); 312 | } 313 | ret = fscanf(pFile, "Link status: %s\n", (char *)&info->link_status); 314 | ret = fscanf(pFile, "SYSREF captured: %s\n", (char *)&info->sysref_captured); 315 | ret = fscanf(pFile, "SYSREF alignment error: %s\n", 316 | (char *)&info->sysref_alignment_error); 317 | 318 | fclose(pFile); 319 | 320 | return ret; 321 | } 322 | -------------------------------------------------------------------------------- /jesd_common.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************//** 2 | * @file jesd_common.h 3 | * @brief JESD204 Status Information Utility 4 | * @author Michael Hennerich (michael.hennerich@analog.com) 5 | ******************************************************************************** 6 | * Copyright 2019 (c) Analog Devices, Inc. 7 | * 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are met: 12 | * - Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * - Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in 16 | * the documentation and/or other materials provided with the 17 | * distribution. 18 | * - Neither the name of Analog Devices, Inc. nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * - The use of this software may or may not infringe the patent rights 22 | * of one or more patent holders. This license does not release you 23 | * from the requirement that you obtain separate licenses from these 24 | * patent holders to use this software. 25 | * - Use of the software either in source or binary form, must be run 26 | * on or directly connected to an Analog Devices Inc. component. 27 | * 28 | * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR 29 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, 30 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 31 | * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, 32 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 33 | * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR 34 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 35 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 36 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | *******************************************************************************/ 39 | 40 | #ifndef JESD_COMMON_H_ 41 | #define JESD_COMMON_H_ 42 | 43 | #define JESD204B_LANE_ENABLE "enable" 44 | #define JESD204B_PRESCALE "prescale" 45 | #define JESD204B_EYE_DATA "eye_data" 46 | 47 | #define MAX_LANES 32 48 | #define MAX_DEVICES 8 49 | #define MAX_PRESCALE 31 50 | #define MAX_SYSFS_STRING_SIZE 32 51 | 52 | #define PPM(x) ((x) / 1000000.0) 53 | #define CLOCK_ACCURACY 200 54 | 55 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 56 | #define MAX(a,b) (((a)>(b))?(a):(b)) 57 | #define MIN(a,b) (((a)<(b))?(a):(b)) 58 | 59 | #define JESD204_ENCODER_8B10B 0 60 | #define JESD204_ENCODER_64B66B 1 61 | 62 | #define JESD204_RX_DRIVER_NAME "axi-jesd204-rx" 63 | #define JESD204_TX_DRIVER_NAME "axi-jesd204-tx" 64 | #define XCVR_DRIVER_NAME "axi_adxcvr" 65 | #define XCVR_NEW_DRIVER_NAME "axi_adxcvr_drv" 66 | 67 | struct jesd204b_laneinfo { 68 | unsigned did; /* DID Device ID */ 69 | unsigned bid; /* BID Bank ID */ 70 | unsigned lid; /* LID Lane ID */ 71 | unsigned l; /* Number of Lanes per Device */ 72 | unsigned scr; /* SCR Scrambling Enabled */ 73 | unsigned f; /* Octets per Frame */ 74 | unsigned k; /* Frames per Multiframe */ 75 | unsigned m; /* Converters per Device */ 76 | unsigned n; /* Converter Resolution */ 77 | unsigned cs; /* Control Bits per Sample */ 78 | unsigned s; /* Samples per Converter per Frame Cycle */ 79 | unsigned nd; /* Total Bits per Sample */ 80 | unsigned hd; /* High Density Format */ 81 | unsigned fchk; /* Checksum */ 82 | unsigned cf; /* Control Words per Frame Cycle per Link */ 83 | unsigned adjcnt; /* ADJCNT Adjustment step count */ 84 | unsigned phyadj; /* PHYADJ Adjustment request */ 85 | unsigned adjdir; /* ADJDIR Adjustment direction */ 86 | unsigned jesdv; /* JESD204 Version */ 87 | unsigned subclassv; /* JESD204 subclass version */ 88 | 89 | unsigned long fc; 90 | 91 | unsigned lane_errors; 92 | unsigned lane_latency_multiframes; 93 | unsigned lane_latency_octets; 94 | 95 | char cgs_state[MAX_SYSFS_STRING_SIZE]; 96 | char init_frame_sync[MAX_SYSFS_STRING_SIZE]; 97 | char init_lane_align_seq[MAX_SYSFS_STRING_SIZE]; 98 | char ext_multiblock_align_state[MAX_SYSFS_STRING_SIZE]; 99 | }; 100 | 101 | struct jesd204b_xcvr_eyescan_info { 102 | 103 | unsigned es_hsize; 104 | unsigned es_vsize; 105 | unsigned long long cdr_data_width; 106 | unsigned num_lanes; 107 | unsigned lpm; 108 | unsigned long lane_rate; 109 | char gt_interface_path[PATH_MAX]; 110 | }; 111 | 112 | struct jesd204b_jesd204_status { 113 | 114 | char link_state[MAX_SYSFS_STRING_SIZE]; 115 | char measured_link_clock[MAX_SYSFS_STRING_SIZE]; 116 | char reported_link_clock[MAX_SYSFS_STRING_SIZE]; 117 | char measured_device_clock[MAX_SYSFS_STRING_SIZE]; 118 | char reported_device_clock[MAX_SYSFS_STRING_SIZE]; 119 | char desired_device_clock[MAX_SYSFS_STRING_SIZE]; 120 | char lane_rate[MAX_SYSFS_STRING_SIZE]; 121 | char lane_rate_div[MAX_SYSFS_STRING_SIZE]; 122 | char lmfc_rate[MAX_SYSFS_STRING_SIZE]; 123 | char sync_state[MAX_SYSFS_STRING_SIZE]; 124 | char link_status[MAX_SYSFS_STRING_SIZE]; 125 | char sysref_captured[MAX_SYSFS_STRING_SIZE]; 126 | char sysref_alignment_error[MAX_SYSFS_STRING_SIZE]; 127 | char external_reset[MAX_SYSFS_STRING_SIZE]; 128 | }; 129 | 130 | char *get_full_device_path(const char *basedir, const char *device); 131 | int jesd_find_devices(const char *basedir, const char *driver, const char *file_exists, 132 | char devices[MAX_DEVICES][PATH_MAX], int start); 133 | int read_laneinfo(const char *basedir, unsigned lane, 134 | struct jesd204b_laneinfo *info); 135 | int read_all_laneinfo(const char *path, 136 | struct jesd204b_laneinfo lane_info[MAX_LANES]); 137 | int read_jesd204_status(const char *basedir, 138 | struct jesd204b_jesd204_status *info); 139 | int read_encoding(const char *basedir); 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /jesd_eye_scan.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************//** 2 | * @file jesd_eye_scan_gtk.c 3 | * @brief JESD204 Eye Scan Visualization Utility 4 | * @author Michael Hennerich (michael.hennerich@analog.com) 5 | ******************************************************************************** 6 | * Copyright 2014-2018 (c) Analog Devices, Inc. 7 | * 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are met: 12 | * - Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * - Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in 16 | * the documentation and/or other materials provided with the 17 | * distribution. 18 | * - Neither the name of Analog Devices, Inc. nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * - The use of this software may or may not infringe the patent rights 22 | * of one or more patent holders. This license does not release you 23 | * from the requirement that you obtain separate licenses from these 24 | * patent holders to use this software. 25 | * - Use of the software either in source or binary form, must be run 26 | * on or directly connected to an Analog Devices Inc. component. 27 | * 28 | * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR 29 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, 30 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 31 | * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, 32 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 33 | * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR 34 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 35 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 36 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | *******************************************************************************/ 39 | 40 | /* HOWTO Remote: 41 | * sudo sshfs -o allow_other -o sync_read root@10.44.2.224:/ /home/dave/mnt 42 | * jesd_eye_scan -p /home/dave/mnt 43 | */ 44 | 45 | #define _GNU_SOURCE 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | 65 | #include 66 | #include 67 | 68 | #include "jesd_common.h" 69 | 70 | char basedir[PATH_MAX]; 71 | unsigned remote = 0; 72 | guint timer; 73 | 74 | GtkBuilder *builder; 75 | GtkWidget *main_window; 76 | GtkWidget *sock; 77 | GtkWidget *finished_eyes; 78 | GtkWidget *min_ber; 79 | GtkWidget *max_ber; 80 | GtkWidget *device_select; 81 | GtkWidget *jesd_core_selection; 82 | GtkWidget *xcvr_core_selection; 83 | GtkWidget *lane[MAX_LANES]; 84 | GtkWidget *lane_status; 85 | GtkNotebook *nbook; 86 | GtkWidget *grid; 87 | 88 | GtkWidget *progressbar1; 89 | 90 | GtkWidget *tview; 91 | GtkTextBuffer *buffer; 92 | GtkTextIter start, end; 93 | GtkTextIter iter; 94 | GtkWidget *view; 95 | 96 | GtkWidget *link_state; 97 | GtkWidget *measured_link_clock; 98 | GtkWidget *reported_link_clock; 99 | GtkWidget *lane_rate; 100 | GtkWidget *lane_rate_div; 101 | GtkWidget *lmfc_rate; 102 | GtkWidget *sync_state; 103 | GtkWidget *link_status; 104 | GtkWidget *sysref_captured; 105 | GtkWidget *sysref_alignment_error; 106 | GtkWidget *external_reset; 107 | 108 | GdkColor color_red; 109 | GdkColor color_green; 110 | GdkColor color_orange; 111 | 112 | pthread_t work; 113 | GMutex *mutex; 114 | unsigned work_run = 1; 115 | unsigned is_first = 0; 116 | 117 | enum { 118 | COLUMN = 0, 119 | COLUMN2, 120 | NUM_COLS 121 | }; 122 | 123 | struct jesd204b_laneinfo lane_info[MAX_LANES]; 124 | struct jesd204b_xcvr_eyescan_info eyescan_info; 125 | char jesd_devices[MAX_DEVICES][PATH_MAX]; 126 | 127 | unsigned long long get_lane_rate(unsigned lane) 128 | { 129 | return lane_info[lane].fc * 1000ULL; 130 | } 131 | 132 | void text_view_delete(void) 133 | { 134 | if (buffer != NULL) { 135 | gtk_text_buffer_get_start_iter(buffer, &start); 136 | gtk_text_buffer_get_end_iter(buffer, &end); 137 | gtk_text_buffer_delete(buffer, &start, &end); 138 | gtk_text_buffer_get_iter_at_offset(buffer, &iter, 0); 139 | } 140 | } 141 | 142 | #define JESD204_TREE_STORE_NEW_ROW_VAL(name, value)\ 143 | {\ 144 | sprintf(temp, "%d", value);\ 145 | gtk_tree_store_append(treestore, &child, &toplevel);\ 146 | gtk_tree_store_set(treestore, &child, COLUMN, name, COLUMN2, temp, -1);\ 147 | }\ 148 | 149 | #define JESD204_TREE_STORE_NEW_ROW_VALF(name, value)\ 150 | {\ 151 | sprintf(temp, "%.3f", value);\ 152 | gtk_tree_store_append(treestore, &child, &toplevel);\ 153 | gtk_tree_store_set(treestore, &child, COLUMN, name, COLUMN2, temp, -1);\ 154 | }\ 155 | 156 | #define JESD204_TREE_STORE_NEW_ROW_STRING(name, value)\ 157 | {\ 158 | gtk_tree_store_append(treestore, &child, &toplevel);\ 159 | gtk_tree_store_set(treestore, &child, COLUMN, name, COLUMN2, value, -1);\ 160 | }\ 161 | 162 | static int create_and_fill_model(unsigned active_lanes) 163 | { 164 | GtkTreeStore *treestore; 165 | GtkTreeIter toplevel, child; 166 | char temp[256]; 167 | unsigned lane = 0; 168 | 169 | treestore = gtk_tree_store_new(NUM_COLS, G_TYPE_STRING, G_TYPE_STRING); 170 | 171 | for (lane = 0; lane < active_lanes; lane++) { 172 | sprintf(temp, "Lane %d", lane); 173 | gtk_tree_store_append(treestore, &toplevel, NULL); 174 | gtk_tree_store_set(treestore, &toplevel, COLUMN, temp, -1); 175 | 176 | JESD204_TREE_STORE_NEW_ROW_VALF("Lane Rate (Gbps)", 177 | (double)get_lane_rate(lane) / 178 | 1000000000); 179 | 180 | JESD204_TREE_STORE_NEW_ROW_VAL("Device ID (DID)", 181 | lane_info[lane].did); 182 | JESD204_TREE_STORE_NEW_ROW_VAL("Bank ID (BID)", 183 | lane_info[lane].bid); 184 | JESD204_TREE_STORE_NEW_ROW_VAL("Lane ID (LID)", 185 | lane_info[lane].lid); 186 | 187 | JESD204_TREE_STORE_NEW_ROW_VAL("JESD204 Version", 188 | lane_info[lane].jesdv); 189 | JESD204_TREE_STORE_NEW_ROW_VAL("JESD204 subclass version", 190 | lane_info[lane].subclassv); 191 | 192 | JESD204_TREE_STORE_NEW_ROW_VAL("Number of Lanes per Device (L)", 193 | lane_info[lane].l); 194 | JESD204_TREE_STORE_NEW_ROW_VAL("Octets per Frame (F)", 195 | lane_info[lane].f); 196 | JESD204_TREE_STORE_NEW_ROW_VAL("Frames per Multiframe (K)", 197 | lane_info[lane].k); 198 | JESD204_TREE_STORE_NEW_ROW_VAL("Converters per Device (M)", 199 | lane_info[lane].m); 200 | JESD204_TREE_STORE_NEW_ROW_VAL("Converter Resolution (N)", 201 | lane_info[lane].n); 202 | 203 | JESD204_TREE_STORE_NEW_ROW_VAL("Control Bits per Sample (CS)", 204 | lane_info[lane].cs); 205 | JESD204_TREE_STORE_NEW_ROW_VAL 206 | ("Samples per Converter per Frame Cycle (S)", 207 | lane_info[lane].s); 208 | JESD204_TREE_STORE_NEW_ROW_VAL("Total Bits per Sample (N')", 209 | lane_info[lane].nd); 210 | 211 | JESD204_TREE_STORE_NEW_ROW_VAL 212 | ("Control Words per Frame Cycle per Link (CF)", 213 | lane_info[lane].cf); 214 | JESD204_TREE_STORE_NEW_ROW_STRING("Scrambling (SCR)", 215 | lane_info[lane]. 216 | scr ? "Enabled" : "Disabled"); 217 | JESD204_TREE_STORE_NEW_ROW_STRING("High Density Format (HD)", 218 | lane_info[lane]. 219 | hd ? "Enabled" : "Disabled"); 220 | 221 | JESD204_TREE_STORE_NEW_ROW_VAL("Checksum (FCHK)", 222 | lane_info[lane].fchk); 223 | JESD204_TREE_STORE_NEW_ROW_VAL("ADJCNT Adjustment step count", 224 | lane_info[lane].adjcnt); 225 | JESD204_TREE_STORE_NEW_ROW_VAL("PHYADJ Adjustment request", 226 | lane_info[lane].phyadj); 227 | JESD204_TREE_STORE_NEW_ROW_VAL("ADJDIR Adjustment direction", 228 | lane_info[lane].adjdir); 229 | } 230 | 231 | gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(treestore)); 232 | g_object_unref(GTK_TREE_MODEL(treestore)); 233 | 234 | return 0; 235 | } 236 | 237 | static GtkWidget *create_view_and_model(unsigned active_lanes) 238 | { 239 | GtkTreeViewColumn *col; 240 | GtkCellRenderer *renderer; 241 | 242 | view = gtk_tree_view_new(); 243 | 244 | col = gtk_tree_view_column_new(); 245 | gtk_tree_view_column_set_title(col, "Lane"); 246 | gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); 247 | 248 | renderer = gtk_cell_renderer_text_new(); 249 | gtk_tree_view_column_pack_start(col, renderer, TRUE); 250 | gtk_tree_view_column_add_attribute(col, renderer, "text", COLUMN); 251 | 252 | col = gtk_tree_view_column_new(); 253 | gtk_tree_view_column_set_title(col, "Value"); 254 | gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); 255 | 256 | renderer = gtk_cell_renderer_text_new(); 257 | gtk_tree_view_column_pack_start(col, renderer, TRUE); 258 | gtk_tree_view_column_add_attribute(col, renderer, "text", COLUMN2); 259 | 260 | return view; 261 | } 262 | 263 | int get_devices(const char *path, const char *driver, const char *file, GtkWidget *device_select) 264 | { 265 | int dev_num, i; 266 | 267 | dev_num = jesd_find_devices(path, driver, file, jesd_devices, 0); 268 | 269 | for (i = 0; i < dev_num; i++) 270 | gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(device_select), 271 | (const gchar *)jesd_devices[i]); 272 | 273 | gtk_combo_box_set_active(GTK_COMBO_BOX(device_select), 0); 274 | 275 | return dev_num; 276 | } 277 | 278 | int print_output_sys(void *err, const char *str, ...) 279 | { 280 | va_list args; 281 | char buf[250]; 282 | int len; 283 | 284 | bzero(buf, 250); 285 | va_start(args, str); 286 | len = vsprintf(buf, str, args); 287 | va_end(args); 288 | 289 | if (err == stderr) { 290 | fprintf(stderr, buf, NULL); 291 | gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, 292 | buf, -1, "red_bg", 293 | "lmarg", "bold", NULL); 294 | } else if (err == stdout) { 295 | fprintf(stdout, buf, NULL); 296 | gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, 297 | buf, -1, "bold", 298 | "lmarg", NULL); 299 | } 300 | 301 | /* Fix warning: variable ‘len’ set but not used [-Wunused-but-set-variable] */ 302 | return len; 303 | } 304 | 305 | static void analyse(struct jesd204b_xcvr_eyescan_info *info, 306 | unsigned long long *data, unsigned int width, 307 | unsigned int height, FILE *gp) 308 | { 309 | unsigned *data_u32 = (unsigned *)data; 310 | unsigned int x, y; 311 | int xmin, xmax; 312 | int ymin, ymax; 313 | 314 | xmin = -1; 315 | xmax = -1; 316 | y = (height + 1) / 2; 317 | 318 | for (x = 0; x < width; x++) { 319 | if (!(info->lpm ? data_u32[y * width + x] & 0x0000FFFF : 320 | data[y * width + x] & 0xFFFF0000FFFF)) { 321 | if (xmin == -1) { 322 | xmin = x; 323 | } 324 | 325 | xmax = x; 326 | } 327 | } 328 | 329 | ymin = -1; 330 | ymax = -1; 331 | x = (width + 1) / 2; 332 | 333 | for (y = 0; y < height; y++) { 334 | if (!(info->lpm ? data_u32[y * width + x] & 0x0000FFFF : 335 | data[y * width + x] & 0xFFFF0000FFFF)) { 336 | if (ymin == -1) { 337 | ymin = y; 338 | } 339 | 340 | ymax = y; 341 | } 342 | } 343 | 344 | y = (height + 1) / 2; 345 | x = (width + 1) / 2; 346 | xmin -= x; 347 | xmax -= x; 348 | ymin -= y; 349 | ymax -= y; 350 | 351 | fprintf(gp, "set label 'Eye-Opening:' at -0.48,-90 front\n"); 352 | fprintf(gp, "set label 'H: %.3f (UI)' at -0.48,-105 front\n", 353 | (float)xmax / ((float)info->es_hsize) - (float)xmin / ((float)info->es_hsize)); 354 | fprintf(gp, "set label 'V: %d (CODES)' at -0.48,-120 front\n", 355 | ymax - ymin); 356 | 357 | print_output_sys(stdout, " H: %.3f (UI)\n", 358 | (float)xmax / ((float)info->es_hsize) - (float)xmin / ((float)info->es_hsize)); 359 | print_output_sys(stdout, " V: %d (CODES)\n", ymax - ymin); 360 | } 361 | 362 | double calc_ber(struct jesd204b_xcvr_eyescan_info *info, 363 | unsigned long long smpl, unsigned prescale) 364 | { 365 | unsigned long long err_ut0, err_ut1, cnt_ut0, cnt_ut1; 366 | double ber; 367 | 368 | if (info->lpm) { 369 | err_ut0 = smpl & 0xFFFF; 370 | cnt_ut0 = (smpl >> 16) & 0xFFFF; 371 | 372 | if ((err_ut0) == 0) { 373 | ber = 1 / (double)((info->cdr_data_width << (1 + prescale)) * cnt_ut0); 374 | } else { 375 | ber = err_ut0 / (double)((info->cdr_data_width << (1 + prescale)) * cnt_ut0); 376 | } 377 | 378 | } else { 379 | err_ut0 = smpl & 0xFFFF; 380 | err_ut1 = (smpl >> 32) & 0xFFFF; 381 | cnt_ut0 = (smpl >> 16) & 0xFFFF; 382 | cnt_ut1 = (smpl >> 48) & 0xFFFF; 383 | 384 | if ((err_ut0 + err_ut1) == 0) 385 | ber = 386 | 1 / (double)((info->cdr_data_width << (1 + prescale)) * 387 | (cnt_ut0 + cnt_ut1)); 388 | else 389 | ber = (err_ut0 * cnt_ut1 + err_ut1 * cnt_ut0) / 390 | (double)(2 * (info->cdr_data_width << (1 + prescale)) * cnt_ut0 * cnt_ut1); 391 | } 392 | 393 | return ber; 394 | } 395 | 396 | int plot(struct jesd204b_xcvr_eyescan_info *info, char *file, unsigned lane, 397 | unsigned p, char *file_png) 398 | { 399 | static FILE *gp = NULL; 400 | int ret, i, cnt; 401 | unsigned long long *buf; 402 | unsigned *buf_lpm; 403 | 404 | FILE *pFile; 405 | 406 | if (gp == NULL) { 407 | gp = popen("gnuplot", "w"); 408 | } 409 | 410 | if (gp == NULL) { 411 | print_output_sys(stderr, "No Gnuplot found - Please install gnuplot-x11 !\n"); 412 | return -1; 413 | } 414 | 415 | cnt = info->es_hsize * info->es_vsize; /* X,Y */ 416 | 417 | buf = malloc(cnt * (info->lpm ? 4 : 8)); 418 | buf_lpm = (unsigned *) buf; 419 | 420 | if (buf == NULL) { 421 | exit(EXIT_FAILURE); 422 | } 423 | 424 | if (file_png == NULL) { 425 | /* This doesn't work for all versions of GTK/Gnuplot: 426 | * https://stackoverflow.com/questions/41209199/cannot-embed-gnuplot-x11-window-into-gtk3-socket 427 | */ 428 | fprintf(gp, "set term x11 window \"%x\"\n", 429 | (unsigned int)gtk_socket_get_id(GTK_SOCKET(sock))); 430 | fprintf(gp, "set mouse nozoomcoordinates\n"); 431 | fprintf(gp, "set autoscale\n"); 432 | } else { 433 | fprintf(gp, "set term png\n"); 434 | fprintf(gp, "set output '%s'\n", file_png); 435 | } 436 | 437 | fprintf(gp, "set view map\n"); 438 | fprintf(gp, "unset label\n"); 439 | fprintf(gp, "set contour base\n"); 440 | fprintf(gp, "set ylabel 'Vertical Offset (CODES)'\n"); 441 | fprintf(gp, "set xlabel 'Horizontal Offset (UI)'\n"); 442 | fprintf(gp, "set palette rgbformulae 7,5,15\n"); 443 | fprintf(gp, "set title '" 444 | "JESD204B Lane%i @ %.2f Gbps %s (Max BER %.1e)'\n", 445 | lane, (double)info->lane_rate / 1000000, info->lpm ? "LPM" : "DFE", 446 | calc_ber(info, 0xFFFF0000FFFF0000, p)); 447 | 448 | fprintf(gp, 449 | "set label 'Xilinx 2D Statistical Eye Scan' at graph 0.0,1.2 left front\n"); 450 | 451 | fprintf(gp, "set grid xtics ytics front lc rgb 'grey'\n"); 452 | fprintf(gp, "set cblabel 'BER 10E'\n"); 453 | fprintf(gp, "set cntrparam levels incremental -1,-1,%i\n", 454 | (int)log10(calc_ber(info, 0xFFFF0000FFFF0000, p))); 455 | fprintf(gp, 456 | "set arrow from -0.175,0 to 0,22.5 nohead front lw 1 lc rgb \'white\'\n"); 457 | fprintf(gp, 458 | "set arrow from 0,22.5 to 0.175,0 nohead front lw 1 lc rgb \'white\'\n"); 459 | fprintf(gp, 460 | "set arrow from 0.175,0 to 0,-22.5 nohead front lw 1 lc rgb \'white\'\n"); 461 | fprintf(gp, 462 | "set arrow from 0,-22.5 to -0.175,0 nohead front lw 1 lc rgb \'white\'\n"); 463 | fprintf(gp, "set label 'MASK' at 0,0 center front tc rgb 'white'\n"); 464 | 465 | pFile = fopen(file, "r"); 466 | ret = fread(buf, info->lpm ? 4 : 8, cnt, pFile); 467 | fclose(pFile); 468 | 469 | if (ret != cnt) { 470 | print_output_sys(stderr, "%s:%d: read failed\n", __func__, __LINE__); 471 | return -EINVAL; 472 | } 473 | 474 | analyse(info, buf, info->es_hsize, info->es_vsize, gp); 475 | 476 | fprintf(gp, "splot '-' using 2:1:(log10($3)) with pm3d title ' '\n"); 477 | 478 | fflush(gp); 479 | 480 | for (i = 0; i < cnt; i++) { 481 | if (i % info->es_hsize == 0) { 482 | fprintf(gp, "\n"); 483 | } 484 | 485 | fprintf(gp, "%f %f %e\n", 486 | ((float)(i / info->es_hsize) - (info->es_vsize / 2)), 487 | ((float)(i % info->es_hsize) - (info->es_hsize / 2)) / (info->es_hsize - 1), 488 | calc_ber(info, info->lpm ? buf_lpm[i] : buf[i], p)); 489 | 490 | } 491 | 492 | fprintf(gp, "e\n"); 493 | fflush(gp); 494 | 495 | if (buf) { 496 | free(buf); 497 | } 498 | 499 | return 0; 500 | } 501 | 502 | int write_sysfs(char *filename, char *basedir, char *val) 503 | { 504 | FILE *sysfsfp; 505 | char temp[PATH_MAX]; 506 | int ret = 0; 507 | 508 | sprintf(temp, "%s/%s", basedir, filename); 509 | sysfsfp = fopen(temp, "w"); 510 | 511 | if (sysfsfp == NULL) { 512 | return -errno; 513 | } 514 | 515 | ret = fprintf(sysfsfp, "%s", val); 516 | fclose(sysfsfp); 517 | 518 | return ret; 519 | } 520 | 521 | int get_eye_data(struct jesd204b_xcvr_eyescan_info *info, char *filename, 522 | char *basedir, char *filename_out) 523 | { 524 | FILE *sysfsfp, *pFile; 525 | char temp[PATH_MAX]; 526 | unsigned long long *buf; 527 | int ret = 0; 528 | unsigned cnt = info->es_hsize * info->es_vsize; /* X,Y */ 529 | 530 | buf = malloc(cnt * (info->lpm ? 4 : 8)); 531 | 532 | if (buf == NULL) { 533 | return -ENOMEM; 534 | } 535 | 536 | sprintf(temp, "%s/%s", basedir, filename); 537 | sysfsfp = fopen(temp, "r"); 538 | 539 | if (sysfsfp == NULL) { 540 | free(buf); 541 | return -errno; 542 | } 543 | 544 | ret = fread(buf, info->lpm ? 4 : 8, cnt, sysfsfp); 545 | 546 | fclose(sysfsfp); 547 | 548 | if (ret != cnt) { 549 | print_output_sys(stderr, "%s:%d: read failed\n", __func__, __LINE__); 550 | return -EINVAL; 551 | } 552 | 553 | pFile = fopen(filename_out, "w"); 554 | 555 | if (pFile == NULL) { 556 | print_output_sys(stderr, "%s:%d: open failed\n", __func__, __LINE__); 557 | free(buf); 558 | return -errno; 559 | } 560 | 561 | ret = fwrite(buf, info->lpm ? 4 : 8, cnt, pFile); 562 | fclose(pFile); 563 | free(buf); 564 | 565 | if (ret != cnt) { 566 | print_output_sys(stderr, "%s:%d: write failed\n", __func__, __LINE__); 567 | return -EINVAL; 568 | } 569 | 570 | return 0; 571 | } 572 | 573 | int get_eye(struct jesd204b_xcvr_eyescan_info *info, unsigned lane, 574 | unsigned prescale) 575 | { 576 | char temp[64]; 577 | int ret; 578 | 579 | if (!work_run) { 580 | return 0; 581 | } 582 | 583 | sprintf(temp, "%d", prescale); 584 | 585 | write_sysfs(JESD204B_PRESCALE, info->gt_interface_path, temp); 586 | 587 | sprintf(temp, "%d", lane); 588 | write_sysfs(JESD204B_LANE_ENABLE, info->gt_interface_path, temp); 589 | 590 | sprintf(temp, "lane%d_p%d.eye", lane, prescale); 591 | ret = get_eye_data(info, JESD204B_EYE_DATA, info->gt_interface_path, temp); 592 | 593 | if (ret) { 594 | return ret; 595 | } 596 | 597 | sprintf(temp, "Lane %d : %.2e", 598 | lane, calc_ber(info, 0xFFFF0000FFFF0000, prescale)); 599 | 600 | gdk_threads_enter(); 601 | gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(finished_eyes), 602 | (const gchar *)temp); 603 | 604 | if (!is_first) { 605 | gtk_combo_box_set_active(GTK_COMBO_BOX(finished_eyes), 0); 606 | is_first++; 607 | } 608 | 609 | gdk_threads_leave(); 610 | 611 | return 0; 612 | } 613 | 614 | int read_eyescan_info(const char *basedir, 615 | struct jesd204b_xcvr_eyescan_info *info) 616 | { 617 | FILE *pFile; 618 | char temp[PATH_MAX]; 619 | int ret; 620 | 621 | sprintf(temp, "%s/eyescan_info", basedir); 622 | pFile = fopen(temp, "r"); 623 | 624 | if (pFile == NULL) { 625 | print_output_sys(stderr, "Failed to read JESD204 device file: %s\n", 626 | temp); 627 | 628 | print_output_sys(stderr, "Select axi-adxcvr-rx device!\n"); 629 | 630 | return -errno; 631 | } 632 | 633 | ret = fscanf(pFile, "x%d,y%d CDRDW: %llu LPM: %d NL: %d LR: %lu\n", 634 | &info->es_hsize, &info->es_vsize, &info->cdr_data_width, 635 | &info->lpm, &info->num_lanes, &info->lane_rate); 636 | 637 | fclose(pFile); 638 | 639 | if (ret != 6) { 640 | print_output_sys(stderr, "Failed to read full eyescan_info\n"); 641 | return -EINVAL; 642 | } 643 | 644 | return 0; 645 | } 646 | 647 | void *worker(void *args) 648 | { 649 | struct jesd204b_xcvr_eyescan_info *info = args; 650 | unsigned lane_en = 0, p = 0, pmin, pmax, l, i = 0; 651 | 652 | /* get GTK thread lock */ 653 | gdk_threads_enter(); 654 | 655 | for (l = 0; l < MAX_LANES; l++) { 656 | lane_en |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lane[l])) << l; 657 | } 658 | 659 | pmin = gtk_combo_box_get_active(GTK_COMBO_BOX(min_ber)); 660 | pmax = gtk_combo_box_get_active(GTK_COMBO_BOX(max_ber)); 661 | 662 | gdk_threads_leave(); 663 | 664 | if (pmin > pmax) { 665 | p = pmin; 666 | pmin = pmax; 667 | pmax = p; 668 | } 669 | 670 | pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 671 | 672 | for (p = pmin; p <= pmax; p++) { 673 | gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressbar1), 674 | (float)(i++) / ((pmax - pmin) ? (pmax - pmin) : 1)); 675 | 676 | for (l = 0; l < MAX_LANES; l++) 677 | if (lane_en & (1 << l)) { 678 | get_eye(info, l, p); 679 | } 680 | } 681 | 682 | gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressbar1), 1.0); 683 | 684 | return 0; 685 | } 686 | 687 | void save_plot_pressed_cb(GtkButton *button, gpointer user_data) 688 | { 689 | GtkWidget *dialog; 690 | char temp[PATH_MAX]; 691 | unsigned lane, prescale; 692 | gchar *item; 693 | double tmp, tmp2, places; 694 | unsigned int i; 695 | 696 | struct jesd204b_xcvr_eyescan_info *info = &eyescan_info; 697 | 698 | item = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(finished_eyes)); 699 | 700 | if (item == NULL) { 701 | return; 702 | } 703 | 704 | sscanf(item, "Lane %d : %lf", &lane, &tmp); 705 | 706 | for (i = 0; i <= MAX_PRESCALE; i++) { 707 | tmp2 = calc_ber(info, 0xFFFF0000FFFF0000, i); 708 | places = pow(10.0, round(abs(log10(tmp2)))); 709 | tmp2 = (round(tmp2 * places * 1000.0))/(places * 1000.0); 710 | 711 | if (tmp2 == tmp) { 712 | prescale = i; 713 | break; 714 | } 715 | } 716 | 717 | sprintf(item, "lane%d_p%d.eye", lane, prescale); 718 | sprintf(temp, "lane%d_%.2eBERT.png", lane, tmp); 719 | 720 | dialog = gtk_file_chooser_dialog_new("Save File", 721 | NULL, 722 | GTK_FILE_CHOOSER_ACTION_SAVE, 723 | GTK_STOCK_CANCEL, 724 | GTK_RESPONSE_CANCEL, 725 | GTK_STOCK_SAVE, 726 | GTK_RESPONSE_ACCEPT, NULL); 727 | gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), 728 | TRUE); 729 | 730 | gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), "./"); 731 | gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), temp); 732 | 733 | if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { 734 | char *filename; 735 | 736 | filename = 737 | gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); 738 | plot(info, item, lane, prescale, filename); 739 | g_free(filename); 740 | 741 | } 742 | 743 | free(item); 744 | gtk_widget_destroy(dialog); 745 | } 746 | 747 | void show_pressed_cb(GtkButton *button, gpointer user_data) 748 | { 749 | unsigned lane, prescale=0; 750 | double tmp, tmp2, places; 751 | unsigned int i; 752 | 753 | gchar *item = 754 | gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT 755 | (finished_eyes)); 756 | 757 | if (item == NULL) { 758 | return; 759 | } 760 | 761 | struct jesd204b_xcvr_eyescan_info *info = &eyescan_info; 762 | 763 | text_view_delete(); 764 | 765 | sscanf(item, "Lane %d : %lf", &lane, &tmp); 766 | 767 | for (i = 0; i <= MAX_PRESCALE; i++) { 768 | tmp2 = calc_ber(info, 0xFFFF0000FFFF0000, i); 769 | places = pow(10.0, round(abs(log10(tmp2)))); 770 | tmp2 = (round(tmp2 * places * 1000.0))/(places * 1000.0); 771 | 772 | if (tmp2 == tmp) { 773 | prescale = i; 774 | break; 775 | } 776 | } 777 | 778 | sprintf(item, "lane%d_p%d.eye", lane, prescale); 779 | 780 | print_output_sys(stdout, "LANE%d P(%d) @ %.2f Gbps\n", lane, prescale, 781 | (double)info->lane_rate / 1000000); 782 | print_output_sys(stdout, "Eye Center:\n ERR: 0 BER: %.3e\n", 783 | calc_ber(info, 0xFFFF0000FFFF0000, prescale)); 784 | 785 | plot(info, item, lane, prescale, NULL); 786 | free(item); 787 | } 788 | 789 | void start_pressed_cb(GtkButton *button, gpointer user_data) 790 | { 791 | struct jesd204b_xcvr_eyescan_info *info = &eyescan_info; 792 | int ret; 793 | 794 | if (work) { 795 | ret = pthread_tryjoin_np(work, NULL); 796 | if (ret) { 797 | print_output_sys(stderr, "Wait until previous run terminates\n"); 798 | return; 799 | } 800 | } 801 | 802 | ret = read_eyescan_info(info->gt_interface_path, info); 803 | 804 | if (ret) { 805 | return; 806 | } 807 | 808 | work_run = 1; 809 | gtk_list_store_clear(GTK_LIST_STORE 810 | (gtk_combo_box_get_model 811 | (GTK_COMBO_BOX(finished_eyes)))); 812 | is_first = 0; 813 | pthread_create(&work, NULL, worker, info); 814 | } 815 | 816 | void terminate_pressed_cb(GtkButton *button, gpointer user_data) 817 | { 818 | work_run = 0; 819 | if (work) { 820 | pthread_cancel(work); 821 | } 822 | } 823 | 824 | void device_select_pressed_cb(GtkComboBoxText *combo_box, gpointer user_data) 825 | { 826 | int i, ret; 827 | char temp[128]; 828 | struct jesd204b_xcvr_eyescan_info *info = &eyescan_info; 829 | 830 | work_run = 0; 831 | 832 | gchar *item = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo_box)); 833 | 834 | if (item == NULL) { 835 | return; 836 | } 837 | 838 | ret = snprintf(info->gt_interface_path, sizeof(info->gt_interface_path), 839 | "%s/%s", basedir, item); 840 | 841 | if (ret < 0) { 842 | return; 843 | } 844 | 845 | gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX( 846 | finished_eyes)))); 847 | text_view_delete(); 848 | 849 | ret = read_eyescan_info(info->gt_interface_path, info); 850 | 851 | if (ret) { 852 | return; 853 | } 854 | 855 | gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(min_ber)); 856 | gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(max_ber)); 857 | 858 | /* Populate min/max BER combo boxes */ 859 | for (i = 0; i <= MAX_PRESCALE; i++) { 860 | sprintf(temp, "%.2e", 861 | calc_ber(info, 0xFFFF0000FFFF0000, i)); 862 | gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(min_ber), 863 | (const gchar *)temp); 864 | gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(max_ber), 865 | (const gchar *)temp); 866 | 867 | if (i == 0) { 868 | gtk_combo_box_set_active(GTK_COMBO_BOX(min_ber), 0); 869 | gtk_combo_box_set_active(GTK_COMBO_BOX(max_ber), 0); 870 | 871 | } 872 | } 873 | 874 | /* Hide lane enable check boxes */ 875 | for (i = 0; i < MAX_LANES; i++) { 876 | if (i < info->num_lanes) { 877 | gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lane[i]), TRUE); 878 | gtk_widget_show(lane[i]); 879 | } else { 880 | gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lane[i]), FALSE); 881 | gtk_widget_hide(lane[i]); 882 | } 883 | } 884 | } 885 | 886 | GtkWidget *set_lable_text(GtkWidget *label, const char *text, 887 | const char *expected, unsigned invert) 888 | { 889 | GdkColor color; 890 | 891 | if (g_strcmp0(text, expected)) { 892 | color = (invert ? color_green : color_red); 893 | } else { 894 | color = (invert ? color_red: color_green); 895 | } 896 | 897 | if (label) { 898 | gtk_label_set_text(GTK_LABEL(label), text); 899 | } else { 900 | label = gtk_label_new(text); 901 | } 902 | 903 | if (expected != NULL) { 904 | gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &color); 905 | } 906 | 907 | return label; 908 | } 909 | 910 | void my_gtk_label_set_xalign(GtkLabel *label, float xalign) 911 | { 912 | GValue val = G_VALUE_INIT; 913 | g_value_init(&val, G_TYPE_FLOAT); 914 | g_value_set_float(&val, xalign); 915 | g_object_set_property(G_OBJECT(label), "xalign", &val); 916 | g_value_unset(&val); 917 | } 918 | 919 | GtkWidget *set_per_lane_status(struct jesd204b_laneinfo *info, unsigned lanes) 920 | { 921 | struct jesd204b_laneinfo *lane; 922 | GdkColor color; 923 | 924 | GtkWidget *label; 925 | char text[128]; 926 | int i, j; 927 | int latency_min, latency, octets_per_multifame; 928 | struct jesd204b_laneinfo *tmp = info; 929 | 930 | static const char *tab_lables[] = { 931 | "Lane#", 932 | "Errors", 933 | "Latency \n(Multiframes/Octets)", 934 | "CGS State", 935 | "Initial Frame Sync", 936 | "Initial Lane \nAlignment Sequence", 937 | }; 938 | 939 | if (grid) { 940 | gtk_widget_destroy(GTK_WIDGET(grid)); 941 | grid = NULL; 942 | } 943 | 944 | if (lanes == 0) { 945 | return NULL; 946 | } 947 | 948 | for (i = 0, latency_min = INT_MAX; i < lanes; i++) { 949 | lane = tmp++; 950 | octets_per_multifame = lane->k * lane->f; 951 | 952 | latency_min = MIN(latency_min, octets_per_multifame * 953 | lane->lane_latency_multiframes + 954 | lane->lane_latency_octets); 955 | } 956 | 957 | grid = gtk_grid_new(); 958 | gtk_grid_set_column_spacing(GTK_GRID(grid), 20); 959 | gtk_grid_set_row_spacing(GTK_GRID(grid), 10); 960 | 961 | for (i = 0; i < lanes + 1; i++) { 962 | j = 0; 963 | 964 | if (i == 0) { 965 | for (j = 0; j < 6; j++) { 966 | label = set_lable_text(NULL, tab_lables[j], NULL, 0); 967 | my_gtk_label_set_xalign(GTK_LABEL(label), 0); 968 | gtk_grid_attach(GTK_GRID(grid), label, i, j, 1, 1); 969 | } 970 | } else { 971 | lane = info++; 972 | octets_per_multifame = lane->k * lane->f; 973 | 974 | latency = octets_per_multifame * lane->lane_latency_multiframes + 975 | lane->lane_latency_octets; 976 | 977 | if ((latency - latency_min) >= octets_per_multifame) { 978 | color = color_red; 979 | } else { 980 | if ((latency - latency_min) > (octets_per_multifame / 2)) { 981 | color = color_orange; 982 | } else { 983 | color = color_green; 984 | } 985 | } 986 | 987 | g_snprintf(text, sizeof(text), "Lane %d", i); 988 | label = set_lable_text(NULL, text, NULL, 0); 989 | gtk_grid_attach(GTK_GRID(grid), label, i, j++, 1, 1); 990 | 991 | g_snprintf(text, sizeof(text), "%d", lane->lane_errors); 992 | label = set_lable_text(NULL, text, "0", 0); 993 | gtk_grid_attach(GTK_GRID(grid), label, i, j++, 1, 1); 994 | 995 | g_snprintf(text, sizeof(text), "%d / %d", lane->lane_latency_multiframes, 996 | lane->lane_latency_octets); 997 | label = set_lable_text(NULL, text, NULL, 0); 998 | gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &color); 999 | gtk_grid_attach(GTK_GRID(grid), label, i, j++, 1, 1); 1000 | 1001 | label = set_lable_text(NULL, lane->cgs_state, "DATA", 0); 1002 | gtk_grid_attach(GTK_GRID(grid), label, i, j++, 1, 1); 1003 | 1004 | label = set_lable_text(NULL, lane->init_frame_sync, "Yes", 0); 1005 | gtk_grid_attach(GTK_GRID(grid), label, i, j++, 1, 1); 1006 | 1007 | label = set_lable_text(NULL, lane->init_lane_align_seq, "Yes", 0); 1008 | gtk_grid_attach(GTK_GRID(grid), label, i, j++, 1, 1); 1009 | } 1010 | } 1011 | 1012 | gtk_container_add(GTK_CONTAINER(lane_status), grid); 1013 | gtk_widget_show_all(grid); 1014 | 1015 | return grid; 1016 | } 1017 | 1018 | 1019 | 1020 | void jesd_update_status(const char *path) 1021 | { 1022 | struct jesd204b_jesd204_status info; 1023 | float measured, reported, div40; 1024 | GdkColor color; 1025 | 1026 | read_jesd204_status(path, &info); 1027 | 1028 | set_lable_text(link_state,(char *) &info.link_state, "enabled", 0); 1029 | set_lable_text(link_status, (char *)&info.link_status, "DATA", 0); 1030 | set_lable_text(measured_link_clock, (char *)&info.measured_link_clock, NULL, 0); 1031 | set_lable_text(reported_link_clock, (char *)&info.reported_link_clock, NULL, 0); 1032 | set_lable_text(lane_rate, (char *)&info.lane_rate, NULL, 0); 1033 | set_lable_text(lane_rate_div,(char *) &info.lane_rate_div, NULL, 0); 1034 | set_lable_text(lmfc_rate,(char *) &info.lmfc_rate, NULL, 0); 1035 | 1036 | set_lable_text(sync_state, (char *)&info.sync_state, "deasserted", 0); 1037 | set_lable_text(sysref_captured, (char *)&info.sysref_captured, "No", 1); 1038 | set_lable_text(sysref_alignment_error, (char *)&info.sysref_alignment_error, 1039 | "Yes", 1); 1040 | 1041 | sscanf((char *)&info.measured_link_clock, "%f", &measured); 1042 | sscanf((char *)&info.reported_link_clock, "%f", &reported); 1043 | sscanf((char *)&info.lane_rate_div, "%f", &div40); 1044 | 1045 | if (measured > (reported * (1 + PPM(CLOCK_ACCURACY))) || 1046 | measured < (reported * (1 - PPM(CLOCK_ACCURACY)))) { 1047 | color = color_red; 1048 | } else { 1049 | color = color_green; 1050 | } 1051 | 1052 | gtk_widget_modify_fg(measured_link_clock, GTK_STATE_NORMAL, &color); 1053 | 1054 | if (reported > (div40 * (1 + PPM(CLOCK_ACCURACY))) || 1055 | reported < (div40 * (1 - PPM(CLOCK_ACCURACY)))) { 1056 | color = color_red; 1057 | } else { 1058 | color = color_green; 1059 | } 1060 | 1061 | gtk_widget_modify_fg(lane_rate_div, GTK_STATE_NORMAL, &color); 1062 | } 1063 | 1064 | static int update_status(GtkComboBoxText *combo_box) 1065 | { 1066 | int cnt = 0; 1067 | char *path; 1068 | 1069 | gchar *item = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo_box)); 1070 | 1071 | if (item == NULL) { 1072 | return cnt; 1073 | } 1074 | 1075 | g_mutex_lock(mutex); 1076 | path = get_full_device_path(basedir, item); 1077 | jesd_update_status(path); 1078 | cnt = read_all_laneinfo(path, lane_info); 1079 | grid = set_per_lane_status(lane_info, cnt); 1080 | g_mutex_unlock(mutex); 1081 | 1082 | return cnt; 1083 | } 1084 | 1085 | static gboolean update_page(void) 1086 | { 1087 | gint page = gtk_notebook_get_current_page(nbook); 1088 | 1089 | if (page == 0) { 1090 | update_status(GTK_COMBO_BOX_TEXT(jesd_core_selection)); 1091 | } 1092 | 1093 | return TRUE; 1094 | } 1095 | 1096 | void jesd_core_selection_cb(GtkComboBoxText *combo_box, gpointer user_data) 1097 | { 1098 | create_and_fill_model(update_status(combo_box)); 1099 | } 1100 | 1101 | int main(int argc, char *argv[]) 1102 | { 1103 | GtkWidget *box2; 1104 | GtkWidget *box3; 1105 | GtkWidget *view; 1106 | GtkImage *logo; 1107 | struct stat buf; 1108 | int ret, c, i, cnt = 0; 1109 | char *path = NULL; 1110 | opterr = 0; 1111 | 1112 | while ((c = getopt(argc, argv, "p:")) != -1) 1113 | switch (c) { 1114 | case 'p': 1115 | path = optarg; 1116 | remote = 1; 1117 | break; 1118 | 1119 | case '?': 1120 | if (optopt == 'd'|| optopt == 'p') { 1121 | fprintf(stderr, "Option -%c requires an argument.\n", optopt); 1122 | } else if (isprint(optopt)) 1123 | fprintf(stderr, "Unknown option `-%c'.\n%s [-p PATH] [-d DEVICEINDEX]\n", 1124 | optopt, argv[0]); 1125 | else 1126 | fprintf(stderr, 1127 | "Unknown option character `\\x%x'.\n", 1128 | optopt); 1129 | 1130 | return 1; 1131 | 1132 | default: 1133 | abort(); 1134 | } 1135 | 1136 | if (!path || !remote) { 1137 | path = ""; 1138 | } 1139 | 1140 | ret = snprintf(basedir, sizeof(basedir), "%s/sys/bus/platform/drivers", path); 1141 | 1142 | if (ret < 0) { 1143 | return EXIT_FAILURE; 1144 | } 1145 | 1146 | 1147 | setlocale(LC_NUMERIC, "C"); 1148 | mutex = g_mutex_new(); 1149 | 1150 | /* init threads */ 1151 | gdk_threads_init(); 1152 | gdk_threads_enter(); 1153 | 1154 | gtk_init(&argc, &argv); 1155 | 1156 | builder = gtk_builder_new(); 1157 | 1158 | if (!gtk_builder_add_from_file(builder, "./jesd.glade", NULL)) { 1159 | gtk_builder_add_from_file(builder, "/usr/local/share/jesd/jesd.glade", NULL); 1160 | } 1161 | 1162 | main_window = GTK_WIDGET(gtk_builder_get_object(builder, "window1")); 1163 | 1164 | nbook = GTK_NOTEBOOK(gtk_builder_get_object(builder, "notebook1")); 1165 | 1166 | 1167 | for (i = 0; i < MAX_LANES; i++) { 1168 | char text[32]; 1169 | g_snprintf(text, sizeof(text), "checkbutton%d", i + 1); 1170 | lane[i] = GTK_WIDGET(gtk_builder_get_object(builder, text)); 1171 | } 1172 | 1173 | gdk_color_parse("red", &color_red); 1174 | gdk_color_parse("green", &color_green); 1175 | gdk_color_parse("orange", &color_orange); 1176 | 1177 | link_state = GTK_WIDGET(gtk_builder_get_object(builder, "link_state")); 1178 | measured_link_clock = GTK_WIDGET(gtk_builder_get_object(builder, 1179 | "measured_link_clock")); 1180 | reported_link_clock = GTK_WIDGET(gtk_builder_get_object(builder, 1181 | "reported_link_clock")); 1182 | lane_rate = GTK_WIDGET(gtk_builder_get_object(builder, "lane_rate")); 1183 | lane_rate_div = GTK_WIDGET(gtk_builder_get_object(builder, "lane_rate_div")); 1184 | lmfc_rate = GTK_WIDGET(gtk_builder_get_object(builder, "lmfc_rate")); 1185 | sync_state = GTK_WIDGET(gtk_builder_get_object(builder, "sync_state")); 1186 | link_status = GTK_WIDGET(gtk_builder_get_object(builder, "link_status")); 1187 | sysref_captured = GTK_WIDGET(gtk_builder_get_object(builder, 1188 | "sysref_captured")); 1189 | sysref_alignment_error = GTK_WIDGET(gtk_builder_get_object(builder, 1190 | "sysref_alignment_error")); 1191 | 1192 | tview = GTK_WIDGET(gtk_builder_get_object(builder, "textview1")); 1193 | 1194 | buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tview)); 1195 | gtk_text_buffer_get_iter_at_offset(buffer, &iter, 0); 1196 | gtk_text_buffer_create_tag(buffer, "lmarg", "left_margin", 5, NULL); 1197 | gtk_text_buffer_create_tag(buffer, "blue_fg", "foreground", "blue", 1198 | NULL); 1199 | gtk_text_buffer_create_tag(buffer, "red_bg", "background", "red", NULL); 1200 | gtk_text_buffer_create_tag(buffer, "italic", "style", 1201 | PANGO_STYLE_ITALIC, NULL); 1202 | gtk_text_buffer_create_tag(buffer, "bold", "weight", PANGO_WEIGHT_BOLD, 1203 | NULL); 1204 | 1205 | progressbar1 = 1206 | GTK_WIDGET(gtk_builder_get_object(builder, "progressbar1")); 1207 | 1208 | box2 = GTK_WIDGET(gtk_builder_get_object(builder, "box2")); 1209 | sock = gtk_socket_new(); 1210 | gtk_widget_set_hexpand(sock, TRUE); 1211 | gtk_widget_set_halign(sock, GTK_ALIGN_FILL); 1212 | gtk_widget_set_vexpand(sock, TRUE); 1213 | gtk_widget_set_valign(sock, GTK_ALIGN_FILL); 1214 | gtk_widget_show(sock); 1215 | gtk_container_add(GTK_CONTAINER(box2), sock); 1216 | gtk_widget_set_size_request(GTK_WIDGET(sock), 480, 360); 1217 | 1218 | box3 = GTK_WIDGET(gtk_builder_get_object(builder, "jesd_info")); 1219 | view = create_view_and_model(cnt); 1220 | gtk_container_add(GTK_CONTAINER(box3), view); 1221 | 1222 | finished_eyes = 1223 | GTK_WIDGET(gtk_builder_get_object(builder, "comboboxtext1")); 1224 | gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(finished_eyes), 0); 1225 | 1226 | min_ber = GTK_WIDGET(gtk_builder_get_object(builder, "comboboxtext2")); 1227 | gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(min_ber), 0); 1228 | 1229 | max_ber = GTK_WIDGET(gtk_builder_get_object(builder, "comboboxtext3")); 1230 | gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(max_ber), 0); 1231 | 1232 | device_select = GTK_WIDGET(gtk_builder_get_object(builder, 1233 | "comboboxtext_device_select")); 1234 | gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(device_select), 0); 1235 | 1236 | jesd_core_selection = GTK_WIDGET(gtk_builder_get_object(builder, 1237 | "jesd_core_selection")); 1238 | gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(jesd_core_selection), 0); 1239 | 1240 | lane_status = GTK_WIDGET(gtk_builder_get_object(builder, "lane_status")); 1241 | 1242 | gtk_builder_connect_signals(builder, NULL); 1243 | 1244 | g_signal_connect(G_OBJECT(main_window), "destroy", 1245 | G_CALLBACK(gtk_main_quit), NULL); 1246 | 1247 | if (!get_devices(basedir, XCVR_DRIVER_NAME, "eyescan_info", device_select)) { 1248 | get_devices(basedir, XCVR_NEW_DRIVER_NAME, "eyescan_info", device_select); 1249 | } 1250 | get_devices(basedir, JESD204_RX_DRIVER_NAME, "status", jesd_core_selection); 1251 | get_devices(basedir, JESD204_TX_DRIVER_NAME, "status", jesd_core_selection); 1252 | 1253 | logo = GTK_IMAGE(gtk_builder_get_object(builder, "logo")); 1254 | 1255 | if (!stat("./icons/ADIlogo.png", &buf)) { 1256 | g_object_set(logo, "file", "./icons/ADIlogo.png", NULL); 1257 | } else { 1258 | g_object_set(logo, "file", "/usr/local/share/jesd/ADIlogo.png", NULL); 1259 | } 1260 | 1261 | gtk_widget_show_all(main_window); 1262 | 1263 | timer = g_timeout_add(1000, (GSourceFunc) update_page, NULL); 1264 | 1265 | /* enter the GTK main loop */ 1266 | gtk_main(); 1267 | gdk_threads_leave(); 1268 | 1269 | return 0; 1270 | } 1271 | -------------------------------------------------------------------------------- /jesd_eye_scan.desktop: -------------------------------------------------------------------------------- 1 | 2 | [Desktop Entry] 3 | Type=Application 4 | Exec=/usr/local/bin/jesd_eye_scan_autostart.sh 5 | Hidden=false 6 | NoDisplay=false 7 | X-GNOME-Autostart-enabled=true 8 | Name[C]=jesd_eye_scan 9 | Name=jesd_eye_scan 10 | Comment[C]=JESD EYE SCAN 11 | Comment=JESD EYE SCAN 12 | -------------------------------------------------------------------------------- /jesd_eye_scan_autostart.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if ls /sys/bus/platform/devices/*axi-jesd204* 1> /dev/null 2>&1; 4 | then 5 | sudo /usr/local/bin/jesd_eye_scan& 6 | fi 7 | -------------------------------------------------------------------------------- /jesd_status.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************//** 2 | * @file jesd_status.c 3 | * @brief JESD204 Status Information Utility 4 | * @author Michael Hennerich (michael.hennerich@analog.com) 5 | ******************************************************************************** 6 | * Copyright 2019 (c) Analog Devices, Inc. 7 | * 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are met: 12 | * - Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * - Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in 16 | * the documentation and/or other materials provided with the 17 | * distribution. 18 | * - Neither the name of Analog Devices, Inc. nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * - The use of this software may or may not infringe the patent rights 22 | * of one or more patent holders. This license does not release you 23 | * from the requirement that you obtain separate licenses from these 24 | * patent holders to use this software. 25 | * - Use of the software either in source or binary form, must be run 26 | * on or directly connected to an Analog Devices Inc. component. 27 | * 28 | * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR 29 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, 30 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 31 | * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, 32 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 33 | * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR 34 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 35 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 36 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | *******************************************************************************/ 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | #include "jesd_common.h" 52 | 53 | #define COL_SPACEING 3 54 | 55 | enum color_pairs { 56 | C_NORM = 1, 57 | C_GOOD = 2, 58 | C_ERR = 3, 59 | C_CRIT = 4, 60 | C_OPT = 5, 61 | }; 62 | 63 | static int encoder = 0; 64 | struct jesd204b_laneinfo lane_info[MAX_LANES]; 65 | char basedir[PATH_MAX]; 66 | char jesd_devices[MAX_DEVICES][PATH_MAX]; 67 | WINDOW *main_win, *stat_win, *dev_win, *lane_win; 68 | 69 | static const char *link_status_labels[] = { 70 | "Link is", 71 | "Link Status", 72 | "Measured Link Clock (MHz)", 73 | "Reported Link Clock (MHz)", 74 | "Measured Device Clock (MHz)", 75 | "Reported Device Clock (MHz)", 76 | "Desired Device Clock (MHz)", 77 | "Lane rate (MHz)", 78 | "Lane rate / 40 (MHz)", 79 | "LMFC rate (MHz)", 80 | "SYSREF captured", 81 | "SYSREF alignment error", 82 | "SYNC~", 83 | NULL 84 | }; 85 | 86 | static const char *link_status_labels_64b66b[] = { 87 | "Link is", 88 | "Link Status", 89 | "Measured Link Clock (MHz)", 90 | "Reported Link Clock (MHz)", 91 | "Measured Device Clock (MHz)", 92 | "Reported Device Clock (MHz)", 93 | "Desired Device Clock (MHz)", 94 | "Lane rate (MHz)", 95 | "Lane rate / 66 (MHz)", 96 | "LEMC rate (MHz)", 97 | "SYSREF captured", 98 | "SYSREF alignment error", 99 | NULL 100 | }; 101 | 102 | static const char *lane_status_labels[] = { 103 | "Lane#", 104 | "Errors", 105 | "Latency (Multiframes/Octets)", 106 | "CGS State", 107 | "Initial Frame Sync", 108 | "Initial Lane Alignment Sequence", 109 | NULL 110 | }; 111 | 112 | static const char *lane_status_labels_64b66b[] = { 113 | "Lane#", 114 | "Errors", 115 | "Extended multiblock alignment", 116 | NULL 117 | }; 118 | 119 | 120 | static void jesd_clear_line_from(WINDOW *win, int y, int x) 121 | { 122 | wmove(win, y, x); 123 | wclrtoeol(win); 124 | } 125 | 126 | void terminal_start() 127 | { 128 | initscr(); 129 | cbreak(); 130 | noecho(); 131 | keypad(stdscr, TRUE); 132 | nodelay(stdscr, TRUE); 133 | curs_set(0); 134 | } 135 | 136 | void terminal_stop() 137 | { 138 | endwin(); 139 | } 140 | 141 | int jesd_get_strlen(WINDOW *win, int x) 142 | { 143 | int x1, y1; 144 | 145 | getyx(win, y1, x1); 146 | 147 | return x1 - x; 148 | } 149 | 150 | int jesd_maxx(int x, int x1) 151 | { 152 | return MAX(x, x1); 153 | } 154 | 155 | void jesd_clear_win(WINDOW *win, int simple) 156 | { 157 | wclear(win); 158 | 159 | if (!simple) 160 | box(win, 0, 0); 161 | } 162 | 163 | #define jesd_print_win_args(win, y, x, c, fmt, args...) \ 164 | ({ \ 165 | int __x; \ 166 | \ 167 | wcolor_set(win, c, NULL); \ 168 | mvwprintw(win, y, x, fmt, ##args); \ 169 | wcolor_set(win, C_NORM, NULL); \ 170 | __x = jesd_get_strlen(win, x); \ 171 | __x; \ 172 | }) 173 | 174 | 175 | int jesd_print_win(WINDOW *win, int y, int x, enum color_pairs c, 176 | const char *str, const bool clear) 177 | { 178 | if (clear) 179 | jesd_clear_line_from(win, y, x); 180 | 181 | wcolor_set(win, c, NULL); 182 | mvwprintw(win, y, x, "%s", str); 183 | wcolor_set(win, C_NORM, NULL); 184 | 185 | return jesd_get_strlen(win, x); 186 | } 187 | 188 | int jesd_print_win_exp(WINDOW *win, int y, int x, const char *text, 189 | const char *expected, unsigned invert, const bool clear) 190 | { 191 | enum color_pairs c; 192 | 193 | if (strcmp(text, expected)) 194 | c = (invert ? C_GOOD : C_ERR); 195 | else 196 | c = (invert ? C_ERR : C_GOOD); 197 | 198 | return jesd_print_win(win, y, x, c, text, clear); 199 | } 200 | 201 | int update_lane_status(WINDOW *win, int x, struct jesd204b_laneinfo *info, 202 | unsigned lanes) 203 | { 204 | struct jesd204b_laneinfo *lane; 205 | enum color_pairs c; 206 | int octets_per_multifame, latency_min, latency, i, y, pos = 0; 207 | struct jesd204b_laneinfo *tmp = info; 208 | 209 | if (!lanes) 210 | return 0; 211 | 212 | for (i = 0, latency_min = INT_MAX; i < lanes; i++) { 213 | lane = tmp++; 214 | octets_per_multifame = lane->k * lane->f; 215 | 216 | latency_min = MIN(latency_min, octets_per_multifame * 217 | lane->lane_latency_multiframes + 218 | lane->lane_latency_octets); 219 | } 220 | 221 | for (i = 0; i < lanes; i++) { 222 | y = 1; 223 | 224 | lane = info++; 225 | octets_per_multifame = lane->k * lane->f; 226 | 227 | latency = octets_per_multifame * lane->lane_latency_multiframes + 228 | lane->lane_latency_octets; 229 | 230 | if ((latency - latency_min) >= octets_per_multifame) 231 | c = C_ERR; 232 | else if ((latency - latency_min) > (octets_per_multifame / 2)) 233 | c = C_CRIT; 234 | else 235 | c = C_GOOD; 236 | 237 | wcolor_set(win, C_NORM, NULL); 238 | 239 | jesd_clear_line_from(win, y, x); 240 | mvwprintw(win, y++, x, "%d", i); 241 | pos = jesd_maxx(pos, jesd_get_strlen(win, x)); 242 | 243 | 244 | if (lane->lane_errors) 245 | wcolor_set(win, C_ERR, NULL); 246 | else 247 | wcolor_set(win, C_GOOD, NULL); 248 | 249 | jesd_clear_line_from(win, y, x); 250 | mvwprintw(win, y++, x, "%d", lane->lane_errors); 251 | pos = jesd_maxx(pos, jesd_get_strlen(win, x)); 252 | 253 | if (encoder == JESD204_ENCODER_64B66B) { 254 | pos = jesd_maxx(pos, jesd_print_win_exp(win, y++, x, 255 | lane->ext_multiblock_align_state, 256 | "EMB_LOCK", 0, true)); 257 | x += pos + COL_SPACEING; 258 | continue; 259 | } 260 | 261 | wcolor_set(win, c, NULL); 262 | jesd_clear_line_from(win, y, x); 263 | mvwprintw(win, y++, x, "%d/%d", lane->lane_latency_multiframes, 264 | lane->lane_latency_octets); 265 | pos = jesd_maxx(pos, jesd_get_strlen(win, x)); 266 | 267 | pos = jesd_maxx(pos, jesd_print_win_exp(win, y++, x, lane->cgs_state, "DATA", 268 | 0, true)); 269 | pos = jesd_maxx(pos, jesd_print_win_exp(win, y++, x, lane->init_frame_sync, 270 | "Yes", 0, true)); 271 | pos = jesd_maxx(pos, jesd_print_win_exp(win, y++, x, lane->init_lane_align_seq, 272 | "Yes", 0, true)); 273 | 274 | x += pos + COL_SPACEING; 275 | } 276 | 277 | return x; 278 | } 279 | 280 | int jesd_update_status(WINDOW *win, int x, const char *device) 281 | { 282 | struct jesd204b_jesd204_status info; 283 | float measured, reported, div40; 284 | enum color_pairs c_measured_link_clock, c_lane_rate_div, 285 | c_measured_device_clock, c_reported_device_clock; 286 | int y = 1, pos = 0; 287 | 288 | read_jesd204_status(get_full_device_path(basedir, device), &info); 289 | 290 | sscanf((char *)&info.measured_link_clock, "%f", &measured); 291 | sscanf((char *)&info.reported_link_clock, "%f", &reported); 292 | sscanf((char *)&info.lane_rate_div, "%f", &div40); 293 | 294 | if (measured > (reported * (1 + PPM(CLOCK_ACCURACY))) || 295 | measured < (reported * (1 - PPM(CLOCK_ACCURACY)))) 296 | c_measured_link_clock = C_ERR; 297 | else 298 | c_measured_link_clock = C_GOOD; 299 | 300 | if (reported > (div40 * (1 + PPM(CLOCK_ACCURACY))) || 301 | reported < (div40 * (1 - PPM(CLOCK_ACCURACY)))) 302 | c_lane_rate_div = C_ERR; 303 | else 304 | c_lane_rate_div = C_GOOD; 305 | 306 | if (info.measured_device_clock[0] != 'N') { 307 | sscanf((char *)&info.measured_device_clock, "%f", &measured); 308 | sscanf((char *)&info.reported_device_clock, "%f", &reported); 309 | sscanf((char *)&info.desired_device_clock, "%f", &div40); 310 | 311 | if (measured > (reported * (1 + PPM(CLOCK_ACCURACY))) || 312 | measured < (reported * (1 - PPM(CLOCK_ACCURACY)))) 313 | c_measured_device_clock = C_ERR; 314 | else 315 | c_measured_device_clock = C_GOOD; 316 | 317 | if (reported > (div40 * (1 + PPM(CLOCK_ACCURACY))) || 318 | reported < (div40 * (1 - PPM(CLOCK_ACCURACY)))) 319 | c_reported_device_clock = C_ERR; 320 | else 321 | c_reported_device_clock = C_GOOD; 322 | } else { 323 | c_measured_device_clock = C_NORM; 324 | c_reported_device_clock = C_NORM; 325 | } 326 | 327 | pos = jesd_maxx(pos, jesd_print_win_exp(win, y++, x, (char *)&info.link_state, 328 | "enabled", 0, true)); 329 | pos = jesd_maxx(pos, jesd_print_win_exp(win, y++, x, (char *)&info.link_status, 330 | "DATA", 0, true)); 331 | pos = jesd_maxx(pos, jesd_print_win(win, y++, x, c_measured_link_clock, 332 | (char *)&info.measured_link_clock, true)); 333 | pos = jesd_maxx(pos, jesd_print_win(win, y++, x, C_NORM, 334 | (char *)&info.reported_link_clock, true)); 335 | pos = jesd_maxx(pos, jesd_print_win(win, y++, x, c_measured_device_clock, 336 | (char *)&info.measured_device_clock, true)); 337 | pos = jesd_maxx(pos, jesd_print_win(win, y++, x, c_reported_device_clock, 338 | (char *)&info.reported_device_clock, true)); 339 | pos = jesd_maxx(pos, jesd_print_win(win, y++, x, C_NORM, 340 | (char *)&info.desired_device_clock, true)); 341 | pos = jesd_maxx(pos, jesd_print_win(win, y++, x, C_NORM, 342 | (char *)&info.lane_rate, true)); 343 | pos = jesd_maxx(pos, jesd_print_win(win, y++, x, c_lane_rate_div, 344 | (char *)&info.lane_rate_div, true)); 345 | pos = jesd_maxx(pos, jesd_print_win(win, y++, x, C_NORM, 346 | (char *)&info.lmfc_rate, true)); 347 | pos = jesd_maxx(pos, jesd_print_win_exp(win, y++, x, 348 | (char *)&info.sysref_captured, "No", 1, true)); 349 | pos = jesd_maxx(pos, jesd_print_win_exp(win, y++, x, 350 | (char *)&info.sysref_alignment_error, "Yes", 1, true)); 351 | if (encoder == JESD204_ENCODER_8B10B) 352 | pos = jesd_maxx(pos, jesd_print_win_exp(win, y++, x, (char *)&info.sync_state, 353 | "deasserted", 0, true)); 354 | 355 | return pos + COL_SPACEING; 356 | } 357 | 358 | int jesd_setup_subwin(WINDOW *win, const char *name, const char **labels) 359 | { 360 | int i = 0, pos = 0; 361 | 362 | mvwprintw(win, 0, 1, "%s", name); 363 | 364 | while (labels[i]) { 365 | pos = jesd_maxx(pos, jesd_print_win(win, i + 1, 1, C_NORM, labels[i], false)); 366 | i++; 367 | } 368 | 369 | return pos + COL_SPACEING; 370 | } 371 | 372 | static void jesd_set_current_device(const int dev_idx) 373 | { 374 | wcolor_set(dev_win, C_GOOD, NULL); 375 | mvwprintw(dev_win, 2 + dev_idx, strlen(jesd_devices[dev_idx]) + 8, "[*]"); 376 | wcolor_set(dev_win, C_NORM, NULL); 377 | wrefresh(dev_win); 378 | } 379 | 380 | /* 381 | * This is a workaround to redraw the right line in the windows boxes/borders. 382 | * This happens because `jesd_clear_line_from()` will clear the current line 383 | * till the EOL which removes part of the box vertical line. 384 | */ 385 | static void jesd_redo_r_box(WINDOW *win, const int simple) 386 | { 387 | int x, y; 388 | 389 | if(simple) 390 | return; 391 | 392 | getmaxyx(win, y, x); 393 | wmove(win, 1, x - 1); 394 | /* redraw vertical line */ 395 | wvline(win, 0, y - 2); 396 | } 397 | 398 | static void jesd_move_device(const int old_idx, const int new_idx, 399 | const int simple) 400 | { 401 | if (old_idx == new_idx) 402 | return; 403 | /* clear the old selected dev */ 404 | jesd_clear_line_from(dev_win, 2 + old_idx, strlen(jesd_devices[old_idx]) + 6); 405 | jesd_redo_r_box(dev_win, simple); 406 | jesd_set_current_device(new_idx); 407 | /* Clear the lane window since the next device might not have lane info */ 408 | jesd_clear_win(lane_win, true); 409 | wrefresh(lane_win); 410 | jesd_clear_win(stat_win, simple); 411 | } 412 | 413 | int main(int argc, char *argv[]) 414 | { 415 | int c, cnt = 0, x = 1, i, simple = 0; 416 | int up_key = 'a', down_key = 'd'; 417 | int termx, termy, dev_num = 0; 418 | char *path = NULL; 419 | int dev_idx = 0; 420 | 421 | opterr = 0; 422 | 423 | while ((c = getopt(argc, argv, "svp:")) != -1) 424 | switch (c) { 425 | case 'p': 426 | path = optarg; 427 | break; 428 | case 's': /* Simple mode */ 429 | simple = 1; 430 | break; 431 | case 'v': 432 | up_key = 'k'; 433 | down_key = 'j'; 434 | break; 435 | case '?': 436 | if (optopt == 'd' || optopt == 'p') 437 | fprintf(stderr, "Option -%c requires an argument.\n", optopt); 438 | else if (isprint(optopt)) 439 | fprintf(stderr, "Unknown option `-%c'.\n%s [-p PATH]\n", 440 | optopt, argv[0]); 441 | else 442 | fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); 443 | 444 | return 1; 445 | 446 | default: 447 | abort(); 448 | } 449 | 450 | if (!path) 451 | path = ""; 452 | 453 | snprintf(basedir, sizeof(basedir), "%s/sys/bus/platform/drivers", path); 454 | 455 | dev_num = jesd_find_devices(basedir, JESD204_RX_DRIVER_NAME, "status", jesd_devices, 0); 456 | dev_num = jesd_find_devices(basedir, JESD204_TX_DRIVER_NAME, "status", jesd_devices, dev_num); 457 | if (!dev_num) { 458 | fprintf(stderr, "Failed to find JESD devices\n"); 459 | return 0; 460 | } 461 | 462 | terminal_start(); 463 | 464 | if (has_colors() /*&& COLOR_PAIRS >= 3*/) { 465 | start_color(); 466 | init_pair(C_NORM, COLOR_WHITE, COLOR_BLACK); 467 | init_pair(C_GOOD, COLOR_GREEN, COLOR_BLACK); 468 | init_pair(C_ERR, COLOR_RED, COLOR_BLACK); 469 | init_pair(C_CRIT, COLOR_YELLOW, COLOR_BLACK); 470 | init_pair(C_OPT, COLOR_WHITE, COLOR_CYAN); 471 | bkgd(COLOR_PAIR(1)); 472 | } 473 | 474 | refresh(); 475 | 476 | getmaxyx(stdscr, termy, termx); 477 | main_win = newwin(termy, termx, 0, 0); 478 | dev_win = newwin(dev_num + 3, termx - 2, 1, 1); 479 | stat_win = newwin(ARRAY_SIZE(link_status_labels) + 1, termx - 2, dev_num + 4, 480 | 1); 481 | lane_win = newwin(ARRAY_SIZE(lane_status_labels) + 1, termx - 2, 482 | dev_num + ARRAY_SIZE(link_status_labels) + 5, 1); 483 | 484 | if (!simple) { 485 | box(dev_win, 0, 0); 486 | box(main_win, 0, 0); 487 | box(stat_win, 0, 0); 488 | box(lane_win, 0, 0); 489 | } 490 | 491 | mvwprintw(dev_win, 0, 1, "(DEVICES) Found %d JESD204 Link Layer peripherals", 492 | dev_num); 493 | 494 | for (i = 0; i < dev_num; i++) { 495 | mvwprintw(dev_win, 2 + i, 1, "(%d): %s", i, jesd_devices[i]); 496 | x += jesd_print_win_args(main_win, termy - 2, x, C_NORM, "F%d", i + 1); 497 | x += jesd_print_win_args(main_win, termy - 2, x, C_OPT, "%s", jesd_devices[i]); 498 | } 499 | /* add quit option */ 500 | x += jesd_print_win_args(main_win, termy - 2, x, C_NORM, "F%d", 501 | MAX_DEVICES + 1); 502 | jesd_print_win(main_win, termy - 2, x, C_OPT, "Quit", false); 503 | 504 | jesd_print_win(main_win, termy - 3, 1, C_OPT, 505 | "You can also use 'q' to quit and 'a' or 'd' to move between devices!", 506 | false); 507 | 508 | wrefresh(main_win); 509 | wrefresh(dev_win); 510 | 511 | /* defaut to first device */ 512 | jesd_set_current_device(0); 513 | 514 | while (true) { 515 | 516 | encoder = read_encoding(get_full_device_path(basedir, jesd_devices[dev_idx])); 517 | if (encoder == JESD204_ENCODER_8B10B) 518 | x = jesd_setup_subwin(stat_win, "(STATUS)", link_status_labels); 519 | else 520 | x = jesd_setup_subwin(stat_win, "(STATUS)", link_status_labels_64b66b); 521 | 522 | jesd_update_status(stat_win, x, jesd_devices[dev_idx]); 523 | jesd_redo_r_box(stat_win, simple); 524 | 525 | cnt = read_all_laneinfo(get_full_device_path(basedir, jesd_devices[dev_idx]), 526 | lane_info); 527 | if (cnt) { 528 | if (!simple) 529 | box(lane_win, 0, 0); 530 | 531 | if (encoder == JESD204_ENCODER_8B10B) 532 | x = jesd_setup_subwin(lane_win, "(LANE STATUS)", lane_status_labels); 533 | else 534 | x = jesd_setup_subwin(lane_win, "(LANE STATUS)", lane_status_labels_64b66b); 535 | 536 | update_lane_status(lane_win, x + 1, lane_info, cnt); 537 | jesd_redo_r_box(lane_win, simple); 538 | wrefresh(lane_win); 539 | } 540 | 541 | wrefresh(stat_win); 542 | usleep(1000 * 250); /* 250 ms */ 543 | 544 | c = getch(); 545 | if (c >= KEY_F(1) && c <= KEY_F0 + dev_num) { 546 | int old_idx = dev_idx; 547 | dev_idx = c - KEY_F0 - 1; 548 | jesd_move_device(old_idx, dev_idx, simple); 549 | } else if (c == down_key) { 550 | int old_idx = dev_idx; 551 | 552 | if (dev_idx + 1 >= dev_num) 553 | dev_idx = 0; 554 | else 555 | dev_idx++; 556 | jesd_move_device(old_idx, dev_idx, simple); 557 | } else if (c == up_key) { 558 | int old_idx = dev_idx; 559 | if (!dev_idx) 560 | dev_idx = dev_num - 1; 561 | else 562 | dev_idx--; 563 | jesd_move_device(old_idx, dev_idx, simple); 564 | } else if (c == KEY_F0 + MAX_DEVICES + 1 || c == 'q') 565 | break; 566 | 567 | } 568 | 569 | terminal_stop(); 570 | 571 | return 0; 572 | } 573 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | DESTDIR=/usr/local 2 | CFLAGS= -g -O2 -Wall 3 | CFLAGS+= `pkg-config --cflags gtk+-3.0` -Wl,--export-dynamic 4 | LIBS= `pkg-config --libs gtk+-3.0` 5 | src = $(wildcard *.c) 6 | obj = $(src:.c=.o) 7 | 8 | 9 | all: jesd_status jesd_eye_scan 10 | 11 | jesd_status: jesd_status.o jesd_common.o 12 | $(CC) -o $@ $^ -lncurses 13 | 14 | jesd_eye_scan: jesd_eye_scan.o jesd_common.o 15 | $(CC) -o $@ $^ $(CFLAGS) $(LIBS) -lm 16 | 17 | install: 18 | install -d $(DESTDIR)/bin 19 | install -d $(DESTDIR)/share/jesd/ 20 | install ./jesd_status $(DESTDIR)/bin/ 21 | install ./jesd_eye_scan $(DESTDIR)/bin/ 22 | install ./jesd_eye_scan_autostart.sh $(DESTDIR)/bin/ 23 | install ./jesd.glade $(DESTDIR)/share/jesd/ 24 | install ./icons/ADIlogo.png $(DESTDIR)/share/jesd/ 25 | mkdir -p ${HOME}/.config/autostart 26 | install jesd_eye_scan.desktop $(HOME)/.config/autostart/jesd_eye_scan.desktop 27 | 28 | clean: 29 | rm -f $(obj) jesd_status jesd_eye_scan 30 | rm -rf *.png *.eye 31 | --------------------------------------------------------------------------------