├── .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 |
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 |
--------------------------------------------------------------------------------