1 |
// MLAB Xilinx Virtual Cable Network Server |
1 |
// MLAB Xilinx Virtual Cable Network Server |
2 |
// ---------------------------------------- |
2 |
// ---------------------------------------- |
3 |
// |
3 |
// |
4 |
// (c) miho 2012 http://www.mlab.cz/PermaLink/XVC_SOFTWARE |
4 |
// (c) miho 2012 http://www.mlab.cz/PermaLink/XVC_SOFTWARE |
5 |
// |
5 |
// |
6 |
// This program if free. |
6 |
// This program if free. |
7 |
// |
7 |
// |
8 |
// |
8 |
// |
9 |
// History: |
9 |
// History: |
10 |
// |
10 |
// |
11 |
// 1.00 2012_09 Proof of concept (no configuration, not for public release) |
11 |
// 1.00 2012_09 Proof of concept (no configuration, not for public release) |
12 |
// 1.01 2012_09 Added parameter for device selection |
12 |
// 1.01 2012_09 Added parameter for device selection |
13 |
// 1.02 2012_12 Error handling and debugged |
13 |
// 1.02 2012_12 Error handling and debugged |
14 |
// 1.03 2012_12 Release version ready to publish |
14 |
// 1.03 2012_12 Release version ready to publish |
- |
|
15 |
// 1.04 2013_04 Socket Bind Error with eplanation (multiple instance of XVC Server) |
15 |
// |
16 |
// |
16 |
// |
17 |
// |
17 |
// Purpose: |
18 |
// Purpose: |
18 |
// |
19 |
// |
19 |
// XILINX development software (ISE, WebPack) supports several types of JTAG programming |
20 |
// XILINX development software (ISE, WebPack) supports several types of JTAG programming |
20 |
// cables. Among them there is one particularly interesting. It is Xilinx Virtual Cable |
21 |
// cables. Among them there is one particularly interesting. It is Xilinx Virtual Cable |
21 |
// which uses (documented) XVC network protocol to send JTAG commands across TCP/IP network. |
22 |
// which uses (documented) XVC network protocol to send JTAG commands across TCP/IP network. |
22 |
// So it is possible to realize own hardware/software and have it directly supported by |
23 |
// So it is possible to realize own hardware/software and have it directly supported by |
23 |
// XILINX development software (both IMPACT and ChipScope). |
24 |
// XILINX development software (both IMPACT and ChipScope). |
24 |
// |
25 |
// |
25 |
// This program listens TCP data send by XILINX ISE IMAPACT (or ChipScope) and sends it |
26 |
// This program listens TCP data send by XILINX ISE IMAPACT (or ChipScope) and sends it |
26 |
// to the JTAG device (typically FPGA) connected to FTDI USB Chip. You can use ordinary |
27 |
// to the JTAG device (typically FPGA) connected to FTDI USB Chip. You can use ordinary |
27 |
// USB/RS232 translator based on FT232R chip or you can use our own module from |
28 |
// USB/RS232 translator based on FT232R chip or you can use our own module from |
28 |
// http://www.mlab.cz/PermaLink/XVC_FT220X |
29 |
// http://www.mlab.cz/PermaLink/XVC_FT220X |
29 |
// |
30 |
// |
30 |
// Target device JTAG port is connected to pins on FTDI USB chip. Program writes to standard |
31 |
// Target device JTAG port is connected to pins on FTDI USB chip. Program writes to standard |
31 |
// output Which pins are used. Program writes what to set in ISE to enable XVC plugin. |
32 |
// output Which pins are used. Program writes what to set in ISE to enable XVC plugin. |
32 |
// |
33 |
// |
33 |
// |
34 |
// |
34 |
// Environment: |
35 |
// Environment: |
35 |
// |
36 |
// |
36 |
// This is Win32 Console Application and run in WinXP / Win7 / Win8 both 32 and 64 bit. |
37 |
// This is Win32 Console Application and run in WinXP / Win7 / Win8 both 32 and 64 bit. |
37 |
// |
38 |
// |
38 |
// Program needs to listen to the network so it is necessary to allow doing so. In Windows |
39 |
// Program needs to listen to the network so it is necessary to allow doing so. In Windows |
39 |
// firewall configuration enable networking for the exe file. |
40 |
// firewall configuration enable networking for the exe file. |
40 |
// WinXP: run as Administrator c:\WINDOWS\System32\firewall.cpl and add the exe file |
41 |
// WinXP: run as Administrator c:\WINDOWS\System32\firewall.cpl and add the exe file |
41 |
// Win7: the system asks directly to do so |
42 |
// Win7: the system asks directly to do so |
42 |
// |
43 |
// |
43 |
// |
44 |
// |
44 |
// Technology: |
45 |
// Technology: |
45 |
// |
46 |
// |
46 |
// The program uses Windows WINSOCK2 library for network communication |
47 |
// The program uses Windows WINSOCK2 library for network communication |
47 |
// and FTDI ftd2xx library for communication with FTDI USB chip. |
48 |
// and FTDI ftd2xx library for communication with FTDI USB chip. |
48 |
// It can be staticly linked to minimize dependencies on libraries. |
49 |
// It can be staticly linked to minimize dependencies on libraries. |
49 |
// Program requires FTDI drivers installed. |
50 |
// Program requires FTDI drivers installed. |
50 |
// Because of the usage of standard libraries you don't need to solve how to sign drivers. |
51 |
// Because of the usage of standard libraries you don't need to solve how to sign drivers. |
51 |
// |
52 |
// |
52 |
// The program was debug with FT232R and FT220X device. |
53 |
// The program was debug with FT232R and FT220X device. |
53 |
// It should work with any similar FTDI USB chip. |
54 |
// It should work with any similar FTDI USB chip. |
54 |
// |
55 |
// |
55 |
// XVC protocol is documented (you have to ask XILINX support to gain access). |
56 |
// XVC protocol is documented (you have to ask XILINX support to gain access). |
56 |
// The program is inspired by the work http://debugmo.de/2012/02/xvcd-the-xilinx-virtual-cable-daemon/ |
57 |
// The program is inspired by the work http://debugmo.de/2012/02/xvcd-the-xilinx-virtual-cable-daemon/ |
57 |
// Ask Google about Xilinx Virtual Cable. |
58 |
// Ask Google about Xilinx Virtual Cable. |
58 |
// |
59 |
// |
59 |
// |
60 |
// |
60 |
// Translation: |
61 |
// Translation: |
61 |
// |
62 |
// |
62 |
// MS Visual C++ 2010 Express (free, registration required) |
63 |
// MS Visual C++ 2010 Express (free, registration required) |
63 |
// Create new empty project for Win32 Console Application and name project mlab_xvcd (to build mlab_xvcd.exe) |
64 |
// Create new empty project for Win32 Console Application and name project mlab_xvcd (to build mlab_xvcd.exe) |
64 |
// Header Files / Add / Existing Items - all .h files |
65 |
// Header Files / Add / Existing Items - all .h files |
65 |
// Resource Files / Add / Existing Items - all .lib files |
66 |
// Resource Files / Add / Existing Items - all .lib files |
66 |
// Source Files / Add / Existing Items - all .cpp files |
67 |
// Source Files / Add / Existing Items - all .cpp files |
67 |
// Select Release version (no debug info) |
68 |
// Select Release version (no debug info) |
68 |
// Set static linkage Project Properties / Configuration Release / Configuration Properties |
69 |
// Set static linkage Project Properties / Configuration Release / Configuration Properties |
69 |
// / Code Generation / Runtime Library = Multithreaded (/MT) |
70 |
// / Code Generation / Runtime Library = Multithreaded (/MT) |
70 |
// |
71 |
// |
71 |
// |
72 |
// |
72 |
// Problems: |
73 |
// Problems: |
73 |
// |
74 |
// |
74 |
// Programming of SPI FLASH configuration memory connected to FPGA does not work. No idea why. |
75 |
// Programming of SPI FLASH configuration memory connected to FPGA does not work. No idea why. |
75 |
// It does not work for internal FLASH of Spartan XC3SxxAN either. |
76 |
// It does not work for internal FLASH of Spartan XC3SxxAN either. |
76 |
// |
77 |
// |
77 |
// |
78 |
// |
78 |
// Possible improvements: |
79 |
// Possible improvements: |
79 |
// |
80 |
// |
80 |
// Linux version (Winsock library differs). |
81 |
// Linux version (Winsock library differs). |
81 |
// External definition of JTAG pins. |
82 |
// External definition of JTAG pins. |
- |
|
83 |
// Enable Socket Number (to be able to run multiple XVC Servers), now it is constant XVC_TCP_PORT (should be only a default) |
82 |
|
84 |
|
83 |
|
85 |
|
84 |
// Library Definitions |
86 |
// Library Definitions |
85 |
// ------------------- |
87 |
// ------------------- |
86 |
|
88 |
|
87 |
#undef UNICODE |
89 |
#undef UNICODE |
88 |
#define WIN32_LEAN_AND_MEAN |
90 |
#define WIN32_LEAN_AND_MEAN |
89 |
|
91 |
|
90 |
#include "mlab_xvcd.h" // Program Configuration |
92 |
#include "mlab_xvcd.h" // Program Configuration |
91 |
#include <windows.h> // Windows Console Application |
93 |
#include <windows.h> // Windows Console Application |
92 |
#include <winsock2.h> // Windows WinSock2 |
94 |
#include <winsock2.h> // Windows WinSock2 |
93 |
#include <ws2tcpip.h> // Windows WinSock2 |
95 |
#include <ws2tcpip.h> // Windows WinSock2 |
94 |
#include <stdlib.h> // Standard Library (exit, atoi, ...) |
96 |
#include <stdlib.h> // Standard Library (exit, atoi, ...) |
95 |
#include <stdio.h> // Standard IO (printf, ...) |
97 |
#include <stdio.h> // Standard IO (printf, ...) |
96 |
#include <signal.h> // CTRL+C handling |
98 |
#include <signal.h> // CTRL+C handling |
97 |
|
99 |
|
98 |
// Link with library |
100 |
// Link with library |
99 |
#pragma comment (lib, "Ws2_32.lib") |
101 |
#pragma comment (lib, "Ws2_32.lib") |
100 |
|
102 |
|
101 |
#define XVC_RX_BUFLEN (XVC_JTAG_LEN/8*2+20) // Length of receive buffer in bytes (command+length+TMSbuffer+TDIbuffer) |
103 |
#define XVC_RX_BUFLEN (XVC_JTAG_LEN/8*2+20) // Length of receive buffer in bytes (command+length+TMSbuffer+TDIbuffer) |
102 |
#define XVC_TX_BUFLEN (XVC_JTAG_LEN/8) // Length of transmit buffer in bytes (TDObuffer) |
104 |
#define XVC_TX_BUFLEN (XVC_JTAG_LEN/8) // Length of transmit buffer in bytes (TDObuffer) |
103 |
|
105 |
|
104 |
|
106 |
|
105 |
// JTAG state machine |
107 |
// JTAG state machine |
106 |
// ------------------ |
108 |
// ------------------ |
107 |
|
109 |
|
108 |
// JTAG States |
110 |
// JTAG States |
109 |
enum |
111 |
enum |
110 |
{ |
112 |
{ |
111 |
test_logic_reset, run_test_idle, // Starts from 0 |
113 |
test_logic_reset, run_test_idle, // Starts from 0 |
112 |
|
114 |
|
113 |
select_dr_scan, capture_dr, shift_dr, |
115 |
select_dr_scan, capture_dr, shift_dr, |
114 |
exit1_dr, pause_dr, exit2_dr, update_dr, |
116 |
exit1_dr, pause_dr, exit2_dr, update_dr, |
115 |
|
117 |
|
116 |
select_ir_scan, capture_ir, shift_ir, |
118 |
select_ir_scan, capture_ir, shift_ir, |
117 |
exit1_ir, pause_ir, exit2_ir, update_ir, |
119 |
exit1_ir, pause_ir, exit2_ir, update_ir, |
118 |
|
120 |
|
119 |
num_states |
121 |
num_states |
120 |
}; |
122 |
}; |
121 |
|
123 |
|
122 |
|
124 |
|
123 |
// JTAG State Machine transfer Function |
125 |
// JTAG State Machine transfer Function |
124 |
static int jtagStep(int state, int tms) |
126 |
static int jtagStep(int state, int tms) |
125 |
{ |
127 |
{ |
126 |
static const int next_state[num_states][2] = |
128 |
static const int next_state[num_states][2] = |
127 |
{ |
129 |
{ |
128 |
/* JTAG State -->> New State */ |
130 |
/* JTAG State -->> New State */ |
129 |
/* -------------------------------------------------------------*/ |
131 |
/* -------------------------------------------------------------*/ |
130 |
/* | TMS=0 | TMS=1 */ |
132 |
/* | TMS=0 | TMS=1 */ |
131 |
/* -------------------------------------------------------------*/ |
133 |
/* -------------------------------------------------------------*/ |
132 |
/* [test_logic_reset] -> */ { run_test_idle, test_logic_reset }, |
134 |
/* [test_logic_reset] -> */ { run_test_idle, test_logic_reset }, |
133 |
/* [run_test_idle] -> */ { run_test_idle, select_dr_scan }, |
135 |
/* [run_test_idle] -> */ { run_test_idle, select_dr_scan }, |
134 |
/* [select_dr_scan] -> */ { capture_dr, select_ir_scan }, |
136 |
/* [select_dr_scan] -> */ { capture_dr, select_ir_scan }, |
135 |
/* [capture_dr] -> */ { shift_dr, exit1_dr }, |
137 |
/* [capture_dr] -> */ { shift_dr, exit1_dr }, |
136 |
/* [shift_dr] -> */ { shift_dr, exit1_dr }, |
138 |
/* [shift_dr] -> */ { shift_dr, exit1_dr }, |
137 |
/* [exit1_dr] -> */ { pause_dr, update_dr }, |
139 |
/* [exit1_dr] -> */ { pause_dr, update_dr }, |
138 |
/* [pause_dr] -> */ { pause_dr, exit2_dr }, |
140 |
/* [pause_dr] -> */ { pause_dr, exit2_dr }, |
139 |
/* [exit2_dr] -> */ { shift_dr, update_dr }, |
141 |
/* [exit2_dr] -> */ { shift_dr, update_dr }, |
140 |
/* [update_dr] -> */ { run_test_idle, select_dr_scan }, |
142 |
/* [update_dr] -> */ { run_test_idle, select_dr_scan }, |
141 |
/* [select_ir_scan] -> */ { capture_ir, test_logic_reset }, |
143 |
/* [select_ir_scan] -> */ { capture_ir, test_logic_reset }, |
142 |
/* [capture_ir] -> */ { shift_ir, exit1_ir }, |
144 |
/* [capture_ir] -> */ { shift_ir, exit1_ir }, |
143 |
/* [shift_ir] -> */ { shift_ir, exit1_ir }, |
145 |
/* [shift_ir] -> */ { shift_ir, exit1_ir }, |
144 |
/* [exit1_ir] -> */ { pause_ir, update_ir }, |
146 |
/* [exit1_ir] -> */ { pause_ir, update_ir }, |
145 |
/* [pause_ir] -> */ { pause_ir, exit2_ir }, |
147 |
/* [pause_ir] -> */ { pause_ir, exit2_ir }, |
146 |
/* [exit2_ir] -> */ { shift_ir, update_ir }, |
148 |
/* [exit2_ir] -> */ { shift_ir, update_ir }, |
147 |
/* [update_ir] -> */ { run_test_idle, select_dr_scan } |
149 |
/* [update_ir] -> */ { run_test_idle, select_dr_scan } |
148 |
}; |
150 |
}; |
149 |
|
151 |
|
150 |
return next_state[state][tms]; |
152 |
return next_state[state][tms]; |
151 |
} |
153 |
} |
152 |
|
154 |
|
153 |
|
155 |
|
154 |
int handleData(SOCKET ClientSocket) |
156 |
int handleData(SOCKET ClientSocket) |
155 |
{ |
157 |
{ |
156 |
|
158 |
|
157 |
bool seen_tlr = false; |
159 |
bool seen_tlr = false; |
158 |
bool jtagError = false; |
160 |
bool jtagError = false; |
159 |
|
161 |
|
160 |
static int jtag_state; |
162 |
static int jtag_state; |
161 |
|
163 |
|
162 |
do |
164 |
do |
163 |
{ |
165 |
{ |
164 |
int iResult; |
166 |
int iResult; |
165 |
|
167 |
|
166 |
// Read Command |
168 |
// Read Command |
167 |
char command[16]; |
169 |
char command[16]; |
168 |
int commandLen = 0; |
170 |
int commandLen = 0; |
169 |
|
171 |
|
170 |
// Read String terminated by ':' |
172 |
// Read String terminated by ':' |
171 |
do |
173 |
do |
172 |
{ |
174 |
{ |
173 |
iResult = recv(ClientSocket, command+commandLen, 1, 0); |
175 |
iResult = recv(ClientSocket, command+commandLen, 1, 0); |
174 |
if (iResult==0) |
176 |
if (iResult==0) |
175 |
{ |
177 |
{ |
176 |
printf("\n Connection Closed\n\n"); |
178 |
printf("\n Connection Closed\n\n"); |
177 |
return -1; |
179 |
return -1; |
178 |
} |
180 |
} |
179 |
else if (iResult==1) |
181 |
else if (iResult==1) |
180 |
{ |
182 |
{ |
181 |
commandLen++; |
183 |
commandLen++; |
182 |
} |
184 |
} |
183 |
else |
185 |
else |
184 |
{ |
186 |
{ |
185 |
fprintf(stderr, "Error Reading Command\n"); |
187 |
fprintf(stderr, "Error Reading Command\n"); |
186 |
return -2; |
188 |
return -2; |
187 |
} |
189 |
} |
188 |
} |
190 |
} |
189 |
while (command[commandLen-1]!=':' && commandLen<sizeof(command)-1 ); |
191 |
while (command[commandLen-1]!=':' && commandLen<sizeof(command)-1 ); |
190 |
command[commandLen] = char(0); |
192 |
command[commandLen] = char(0); |
191 |
|
193 |
|
192 |
if (0==strncmp(command, "shift:", sizeof(command))) |
194 |
if (0==strncmp(command, "shift:", sizeof(command))) |
193 |
{ |
195 |
{ |
194 |
|
196 |
|
195 |
} |
197 |
} |
196 |
else |
198 |
else |
197 |
{ |
199 |
{ |
198 |
fprintf(stderr, "Invalid Command '%s'\n", command); |
200 |
fprintf(stderr, "Invalid Command '%s'\n", command); |
199 |
return -2; |
201 |
return -2; |
200 |
} |
202 |
} |
201 |
|
203 |
|
202 |
// Read Length (in bits, 32bit integer) |
204 |
// Read Length (in bits, 32bit integer) |
203 |
int len; |
205 |
int len; |
204 |
|
206 |
|
205 |
iResult = recv(ClientSocket, (char *)&len, 4, 0); // pøepsat pøenositelnì |
207 |
iResult = recv(ClientSocket, (char *)&len, 4, 0); // pøepsat pøenositelnì |
206 |
if (iResult==0) |
208 |
if (iResult==0) |
207 |
{ |
209 |
{ |
208 |
printf("\n Connection Closed\n\n"); |
210 |
printf("\n Connection Closed\n\n"); |
209 |
return -1; |
211 |
return -1; |
210 |
} |
212 |
} |
211 |
if (iResult != 4) |
213 |
if (iResult != 4) |
212 |
{ |
214 |
{ |
213 |
fprintf(stderr, "Reading Length Failed\n"); |
215 |
fprintf(stderr, "Reading Length Failed\n"); |
214 |
return -2; |
216 |
return -2; |
215 |
} |
217 |
} |
216 |
|
218 |
|
217 |
char buffer[2048]; |
219 |
char buffer[2048]; |
218 |
|
220 |
|
219 |
// Read Data (data string for TMS and TDI) |
221 |
// Read Data (data string for TMS and TDI) |
220 |
int nr_bytes = (len + 7) / 8; |
222 |
int nr_bytes = (len + 7) / 8; |
221 |
if (nr_bytes * 2 > sizeof(buffer)) |
223 |
if (nr_bytes * 2 > sizeof(buffer)) |
222 |
{ |
224 |
{ |
223 |
fprintf(stderr, "Buffer Size Exceeded\n"); |
225 |
fprintf(stderr, "Buffer Size Exceeded\n"); |
224 |
return -2; |
226 |
return -2; |
225 |
} |
227 |
} |
226 |
|
228 |
|
227 |
int iReceivedBytes=0; |
229 |
int iReceivedBytes=0; |
228 |
while (iReceivedBytes<nr_bytes * 2) |
230 |
while (iReceivedBytes<nr_bytes * 2) |
229 |
{ |
231 |
{ |
230 |
iResult = recv(ClientSocket, buffer+iReceivedBytes, nr_bytes * 2 - iReceivedBytes, 0); |
232 |
iResult = recv(ClientSocket, buffer+iReceivedBytes, nr_bytes * 2 - iReceivedBytes, 0); |
231 |
if (iResult==0) |
233 |
if (iResult==0) |
232 |
{ |
234 |
{ |
233 |
printf("\n Connection Closed\n\n"); |
235 |
printf("\n Connection Closed\n\n"); |
234 |
return -1; |
236 |
return -1; |
235 |
} |
237 |
} |
236 |
if (iResult<=0) |
238 |
if (iResult<=0) |
237 |
{ |
239 |
{ |
238 |
fprintf(stderr, "Reading Data Failed %d %d\n", iResult, nr_bytes * 2); |
240 |
fprintf(stderr, "Reading Data Failed %d %d\n", iResult, nr_bytes * 2); |
239 |
return -2; |
241 |
return -2; |
240 |
} |
242 |
} |
241 |
iReceivedBytes += iResult; |
243 |
iReceivedBytes += iResult; |
242 |
} |
244 |
} |
243 |
|
245 |
|
244 |
char result[1024]; |
246 |
char result[1024]; |
245 |
memset(result, 0, nr_bytes); |
247 |
memset(result, 0, nr_bytes); |
246 |
|
248 |
|
247 |
// Deal with JTAG |
249 |
// Deal with JTAG |
248 |
|
250 |
|
249 |
// Only allow exiting if the state is rti and the IR |
251 |
// Only allow exiting if the state is rti and the IR |
250 |
// has the default value (IDCODE) by going through test_logic_reset. |
252 |
// has the default value (IDCODE) by going through test_logic_reset. |
251 |
// As soon as going through capture_dr or capture_ir no exit is |
253 |
// As soon as going through capture_dr or capture_ir no exit is |
252 |
// allowed as this will change DR/IR. |
254 |
// allowed as this will change DR/IR. |
253 |
seen_tlr = (seen_tlr || jtag_state == test_logic_reset) && (jtag_state != capture_dr) && (jtag_state != capture_ir); |
255 |
seen_tlr = (seen_tlr || jtag_state == test_logic_reset) && (jtag_state != capture_dr) && (jtag_state != capture_ir); |
254 |
|
256 |
|
255 |
// Due to a weird bug(??) xilinx impacts goes through another "capture_ir"/"capture_dr" cycle after |
257 |
// Due to a weird bug(??) xilinx impacts goes through another "capture_ir"/"capture_dr" cycle after |
256 |
// reading IR/DR which unfortunately sets IR to the read-out IR value. |
258 |
// reading IR/DR which unfortunately sets IR to the read-out IR value. |
257 |
// Just ignore these transactions. |
259 |
// Just ignore these transactions. |
258 |
if ((jtag_state == exit1_ir && len == 5 && buffer[0] == 0x17) || (jtag_state == exit1_dr && len == 4 && buffer[0] == 0x0b)) |
260 |
if ((jtag_state == exit1_ir && len == 5 && buffer[0] == 0x17) || (jtag_state == exit1_dr && len == 4 && buffer[0] == 0x0b)) |
259 |
{ |
261 |
{ |
260 |
// printf("Ignoring Bogus jtag State movement at jtag_state %d\n", jtag_state); |
262 |
// printf("Ignoring Bogus jtag State movement at jtag_state %d\n", jtag_state); |
261 |
} |
263 |
} |
262 |
else |
264 |
else |
263 |
{ |
265 |
{ |
264 |
for (int i = 0; i < len; ++i) |
266 |
for (int i = 0; i < len; ++i) |
265 |
{ |
267 |
{ |
266 |
// |
268 |
// |
267 |
// Do the actual cycle. |
269 |
// Do the actual cycle. |
268 |
// |
270 |
// |
269 |
int tms = !!(buffer[i/8] & (1<<(i&7))); |
271 |
int tms = !!(buffer[i/8] & (1<<(i&7))); |
270 |
// |
272 |
// |
271 |
// Track the state. |
273 |
// Track the state. |
272 |
// |
274 |
// |
273 |
jtag_state = jtagStep(jtag_state, tms); |
275 |
jtag_state = jtagStep(jtag_state, tms); |
274 |
} |
276 |
} |
275 |
if (jtagScan((unsigned char *) buffer, (unsigned char *) buffer + nr_bytes, (unsigned char *) result, len) < 0) |
277 |
if (jtagScan((unsigned char *) buffer, (unsigned char *) buffer + nr_bytes, (unsigned char *) result, len) < 0) |
276 |
{ |
278 |
{ |
277 |
//fprintf(stderr, "jtagScan failed\n"); |
279 |
//fprintf(stderr, "jtagScan failed\n"); |
278 |
// Can't stop now, have to sent (any) answer not to hung the IMPACT |
280 |
// Can't stop now, have to sent (any) answer not to hung the IMPACT |
279 |
jtagError = true; |
281 |
jtagError = true; |
280 |
} |
282 |
} |
281 |
} |
283 |
} |
282 |
|
284 |
|
283 |
// Send the Ansver |
285 |
// Send the Ansver |
284 |
iResult = send(ClientSocket, result, nr_bytes, 0 ); |
286 |
iResult = send(ClientSocket, result, nr_bytes, 0 ); |
285 |
if (iResult == SOCKET_ERROR) |
287 |
if (iResult == SOCKET_ERROR) |
286 |
{ |
288 |
{ |
287 |
printf("Send Failed with Error: %d\n", WSAGetLastError()); |
289 |
printf("Send Failed with Error: %d\n", WSAGetLastError()); |
288 |
closesocket(ClientSocket); |
290 |
closesocket(ClientSocket); |
289 |
WSACleanup(); |
291 |
WSACleanup(); |
290 |
return -2; |
292 |
return -2; |
291 |
} |
293 |
} |
292 |
// printf("Bytes Sent: %d\n", iSendResult); |
294 |
// printf("Bytes Sent: %d\n", iSendResult); |
293 |
// printf("jtag state %d\n", jtag_state); |
295 |
// printf("jtag state %d\n", jtag_state); |
294 |
} |
296 |
} |
295 |
while (!(seen_tlr && jtag_state == run_test_idle)); |
297 |
while (!(seen_tlr && jtag_state == run_test_idle)); |
296 |
|
298 |
|
297 |
return jtagError ? -2 : 0; |
299 |
return jtagError ? -2 : 0; |
298 |
} |
300 |
} |
299 |
|
301 |
|
300 |
|
302 |
|
301 |
// Stop Handler - switch JTAG port off and stop program |
303 |
// Stop Handler - switch JTAG port off and stop program |
302 |
void stopHandler(int sig) |
304 |
void stopHandler(int sig) |
303 |
{ |
305 |
{ |
304 |
jtagClosePort(); |
306 |
jtagClosePort(); |
305 |
exit(1); |
307 |
exit(1); |
306 |
} |
308 |
} |
307 |
|
309 |
|
308 |
|
310 |
|
309 |
// Print help and stop program with error |
311 |
// Print help and stop program with error |
310 |
void Help(char *progName) |
312 |
void Help(char *progName) |
311 |
{ |
313 |
{ |
312 |
fprintf(stderr, "Bad Parameters\n"); |
314 |
fprintf(stderr, "Bad Parameters\n"); |
313 |
fprintf(stderr, "\n"); |
315 |
fprintf(stderr, "\n"); |
314 |
fprintf(stderr, "Usage: %s [arg]\n", progName); |
316 |
fprintf(stderr, "Usage: %s [arg]\n", progName); |
315 |
fprintf(stderr, "\n"); |
317 |
fprintf(stderr, "\n"); |
316 |
fprintf(stderr, " Where [arg] is one of: \n"); |
318 |
fprintf(stderr, " Where [arg] is one of: \n"); |
317 |
fprintf(stderr, " -d Description Fing FTDI device by Description\n"); |
319 |
fprintf(stderr, " -d Description Fing FTDI device by Description\n"); |
318 |
fprintf(stderr, " -l Location Fing FTDI device by Loaction\n"); |
320 |
fprintf(stderr, " -l Location Fing FTDI device by Loaction\n"); |
319 |
fprintf(stderr, " -s Serial_number Fing FTDI device by it's SN\n"); |
321 |
fprintf(stderr, " -s Serial_number Fing FTDI device by it's SN\n"); |
320 |
fprintf(stderr, " -n Number Use N-th FTDI device\n"); |
322 |
fprintf(stderr, " -n Number Use N-th FTDI device\n"); |
321 |
fprintf(stderr, " The first FTDI device is used if no argument\n"); |
323 |
fprintf(stderr, " The first FTDI device is used if no argument\n"); |
322 |
exit(2); |
324 |
exit(2); |
323 |
} |
325 |
} |
324 |
|
326 |
|
325 |
|
327 |
|
326 |
int __cdecl main(int argc, char *argv[]) |
328 |
int __cdecl main(int argc, char *argv[]) |
327 |
{ |
329 |
{ |
328 |
// Variables |
330 |
// Variables |
329 |
bool verbose = true; |
331 |
bool verbose = true; |
330 |
|
332 |
|
331 |
// Program Info |
333 |
// Program Info |
332 |
printf("\n"); |
334 |
printf("\n"); |
333 |
printf("Xilinx Virtual Cable Network Server\n"); |
335 |
printf("Xilinx Virtual Cable Network Server\n"); |
334 |
printf("===================================\n"); |
336 |
printf("===================================\n"); |
335 |
printf("(c) miho 2012 v " VERSION "\n\n"); |
337 |
printf("(c) miho 2012 v " VERSION "\n\n"); |
336 |
|
338 |
|
337 |
// Get program name |
339 |
// Get program name |
338 |
char *cp; |
340 |
char *cp; |
339 |
char *progName; |
341 |
char *progName; |
340 |
cp = argv[0]; |
342 |
cp = argv[0]; |
341 |
progName=cp; |
343 |
progName=cp; |
342 |
while (cp[0]!='\0') |
344 |
while (cp[0]!='\0') |
343 |
{ |
345 |
{ |
344 |
if (cp[0]=='/' || cp[0]=='\\') |
346 |
if (cp[0]=='/' || cp[0]=='\\') |
345 |
progName=cp+1; |
347 |
progName=cp+1; |
346 |
cp++; |
348 |
cp++; |
347 |
} |
349 |
} |
348 |
|
350 |
|
349 |
// Process command line params |
351 |
// Process command line params |
350 |
char *findDeviceByStr = 0; // String parameter |
352 |
char *findDeviceByStr = 0; // String parameter |
351 |
int findDeviceBy = 0; // What does the string means |
353 |
int findDeviceBy = 0; // What does the string means |
352 |
|
354 |
|
353 |
if (argc>1) |
355 |
if (argc>1) |
354 |
{ |
356 |
{ |
355 |
if (argc==3) |
357 |
if (argc==3) |
356 |
{ |
358 |
{ |
357 |
findDeviceByStr = argv[2]; |
359 |
findDeviceByStr = argv[2]; |
358 |
if (strcmp(argv[1], "-d")==0) |
360 |
if (strcmp(argv[1], "-d")==0) |
359 |
{ |
361 |
{ |
360 |
findDeviceBy = OPEN_BY_DESCRIPTION; |
362 |
findDeviceBy = OPEN_BY_DESCRIPTION; |
361 |
} |
363 |
} |
362 |
else if (strcmp(argv[1], "-l")==0) |
364 |
else if (strcmp(argv[1], "-l")==0) |
363 |
{ |
365 |
{ |
364 |
findDeviceBy = OPEN_BY_LOCATION; |
366 |
findDeviceBy = OPEN_BY_LOCATION; |
365 |
} |
367 |
} |
366 |
else if (strcmp(argv[1], "-s")==0) |
368 |
else if (strcmp(argv[1], "-s")==0) |
367 |
{ |
369 |
{ |
368 |
findDeviceBy = OPEN_BY_SERIAL_NUMBER; |
370 |
findDeviceBy = OPEN_BY_SERIAL_NUMBER; |
369 |
} |
371 |
} |
370 |
else if (strcmp(argv[1], "-n")==0) |
372 |
else if (strcmp(argv[1], "-n")==0) |
371 |
{ |
373 |
{ |
372 |
findDeviceBy = 0; |
374 |
findDeviceBy = 0; |
373 |
} |
375 |
} |
374 |
else |
376 |
else |
375 |
{ |
377 |
{ |
376 |
Help(progName); |
378 |
Help(progName); |
377 |
} |
379 |
} |
378 |
} |
380 |
} |
379 |
else |
381 |
else |
380 |
{ |
382 |
{ |
381 |
Help(progName); |
383 |
Help(progName); |
382 |
} |
384 |
} |
383 |
} |
385 |
} |
384 |
else |
386 |
else |
385 |
{ |
387 |
{ |
386 |
// Empty String - find device by number and number is empty |
388 |
// Empty String - find device by number and number is empty |
387 |
findDeviceBy = 0; |
389 |
findDeviceBy = 0; |
388 |
findDeviceByStr = ""; |
390 |
findDeviceByStr = ""; |
389 |
} |
391 |
} |
390 |
|
392 |
|
391 |
// Find, Init and Open FTDI USB Chip |
393 |
// Find, Init and Open FTDI USB Chip |
392 |
if (jtagOpenPort(findDeviceBy, findDeviceByStr)<0) { |
394 |
if (jtagOpenPort(findDeviceBy, findDeviceByStr)<0) { |
393 |
// No Device Found |
395 |
// No Device Found |
394 |
fprintf(stderr, "ERROR: No Device Found\n"); |
396 |
fprintf(stderr, "ERROR: No Device Found\n"); |
395 |
return -1; |
397 |
return -1; |
396 |
} |
398 |
} |
397 |
|
399 |
|
398 |
// Signal Handler (for CRTL+C) |
400 |
// Signal Handler (for CRTL+C) |
399 |
signal(SIGINT, &stopHandler); |
401 |
signal(SIGINT, &stopHandler); |
400 |
|
402 |
|
401 |
printf("Starting Network Server\n"); |
403 |
printf("Starting Network Server\n"); |
402 |
WSADATA wsaData; |
404 |
WSADATA wsaData; |
403 |
int iResult; |
405 |
int iResult; |
404 |
|
406 |
|
405 |
SOCKET ListenSocket = INVALID_SOCKET; |
407 |
SOCKET ListenSocket = INVALID_SOCKET; |
406 |
SOCKET ClientSocket = INVALID_SOCKET; |
408 |
SOCKET ClientSocket = INVALID_SOCKET; |
407 |
|
409 |
|
408 |
// Initialize Winsock |
410 |
// Initialize Winsock |
409 |
iResult = WSAStartup(MAKEWORD(2,2), &wsaData); |
411 |
iResult = WSAStartup(MAKEWORD(2,2), &wsaData); |
410 |
if (iResult != 0) |
412 |
if (iResult != 0) |
411 |
{ |
413 |
{ |
412 |
fprintf(stderr, "WSAStartup failed with error: %d\n", iResult); |
414 |
fprintf(stderr, "WSAStartup failed with error: %d\n", iResult); |
413 |
jtagClosePort(); |
415 |
jtagClosePort(); |
414 |
return -2; |
416 |
return -2; |
415 |
} |
417 |
} |
416 |
|
418 |
|
417 |
// Display HostName and Address |
419 |
// Display HostName and Address |
418 |
char sMyName[255]; |
420 |
char sMyName[255]; |
419 |
gethostname(sMyName, sizeof(sMyName)); |
421 |
gethostname(sMyName, sizeof(sMyName)); |
420 |
printf(" Host Name %s\n", sMyName); |
422 |
printf(" Host Name %s\n", sMyName); |
421 |
hostent * pHostInfo; |
423 |
hostent * pHostInfo; |
422 |
pHostInfo = gethostbyname(sMyName); |
424 |
pHostInfo = gethostbyname(sMyName); |
423 |
printf(" Network Name %s\n", pHostInfo->h_name); |
425 |
printf(" Network Name %s\n", pHostInfo->h_name); |
424 |
if (pHostInfo->h_length>0 && pHostInfo->h_length<=16) |
426 |
if (pHostInfo->h_length>0 && pHostInfo->h_length<=16) |
425 |
{ |
427 |
{ |
426 |
printf(" Host Address "); |
428 |
printf(" Host Address "); |
427 |
for (int i=0; i<pHostInfo->h_length-1; i++) |
429 |
for (int i=0; i<pHostInfo->h_length-1; i++) |
428 |
{ |
430 |
{ |
429 |
printf("%d.", (unsigned char)pHostInfo->h_addr_list[0][i]); |
431 |
printf("%d.", (unsigned char)pHostInfo->h_addr_list[0][i]); |
430 |
} |
432 |
} |
431 |
printf("%d\n", (unsigned char)pHostInfo->h_addr_list[0][pHostInfo->h_length-1]); |
433 |
printf("%d\n", (unsigned char)pHostInfo->h_addr_list[0][pHostInfo->h_length-1]); |
432 |
} |
434 |
} |
433 |
|
435 |
|
434 |
// Create Protocol Structure |
436 |
// Create Protocol Structure |
435 |
struct addrinfo hints; |
437 |
struct addrinfo hints; |
436 |
ZeroMemory(&hints, sizeof(hints)); |
438 |
ZeroMemory(&hints, sizeof(hints)); |
437 |
hints.ai_family = AF_INET; // IP6 |
439 |
hints.ai_family = AF_INET; // IP6 |
438 |
hints.ai_socktype = SOCK_STREAM; // Reliable two-way connection |
440 |
hints.ai_socktype = SOCK_STREAM; // Reliable two-way connection |
439 |
hints.ai_protocol = IPPROTO_TCP; // Protocol TCP |
441 |
hints.ai_protocol = IPPROTO_TCP; // Protocol TCP |
440 |
hints.ai_flags = AI_PASSIVE; |
442 |
hints.ai_flags = AI_PASSIVE; |
441 |
|
443 |
|
442 |
// Resolve the server address and port (allocate structure "result") |
444 |
// Resolve the server address and port (allocate structure "result") |
443 |
struct addrinfo *result = NULL; |
445 |
struct addrinfo *result = NULL; |
444 |
iResult = getaddrinfo(NULL, XVC_TCP_PORT, &hints, &result); |
446 |
iResult = getaddrinfo(NULL, XVC_TCP_PORT, &hints, &result); |
445 |
if ( iResult != 0 ) |
447 |
if ( iResult != 0 ) |
446 |
{ |
448 |
{ |
447 |
fprintf(stderr, "getaddrinfo failed with error: %d\n", iResult); |
449 |
fprintf(stderr, "getaddrinfo failed with error: %d\n", iResult); |
448 |
WSACleanup(); |
450 |
WSACleanup(); |
449 |
jtagClosePort(); |
451 |
jtagClosePort(); |
450 |
return -2; |
452 |
return -2; |
451 |
} |
453 |
} |
452 |
|
454 |
|
453 |
// Create a SOCKET |
455 |
// Create a SOCKET |
454 |
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); |
456 |
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); |
455 |
if (ListenSocket == INVALID_SOCKET) |
457 |
if (ListenSocket == INVALID_SOCKET) |
456 |
{ |
458 |
{ |
457 |
fprintf(stderr, "socket failed with error: %ld\n", WSAGetLastError()); |
459 |
fprintf(stderr, "socket failed with error: %ld\n", WSAGetLastError()); |
458 |
freeaddrinfo(result); |
460 |
freeaddrinfo(result); |
459 |
WSACleanup(); |
461 |
WSACleanup(); |
460 |
jtagClosePort(); |
462 |
jtagClosePort(); |
461 |
return -2; |
463 |
return -2; |
462 |
} |
464 |
} |
463 |
|
465 |
|
464 |
// Bind the SOCKED (assign the address) |
466 |
// Bind the SOCKED (assign the address) |
465 |
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen); |
467 |
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen); |
466 |
if (iResult == SOCKET_ERROR) |
468 |
if (iResult == SOCKET_ERROR) |
467 |
{ |
469 |
{ |
- |
|
470 |
int LastError=WSAGetLastError(); |
468 |
fprintf(stderr, "Bind failed with error: %d\n", WSAGetLastError()); |
471 |
fprintf(stderr, "Bind failed with error: %d\n", LastError); |
- |
|
472 |
if (LastError==10048) fprintf(stderr, "Trying to start second instance of XVC Server?\n"); |
469 |
freeaddrinfo(result); |
473 |
freeaddrinfo(result); |
470 |
closesocket(ListenSocket); |
474 |
closesocket(ListenSocket); |
471 |
WSACleanup(); |
475 |
WSACleanup(); |
472 |
jtagClosePort(); |
476 |
jtagClosePort(); |
473 |
return -2; |
477 |
return -2; |
474 |
} |
478 |
} |
475 |
|
479 |
|
476 |
if (verbose) |
480 |
if (verbose) |
477 |
{ |
481 |
{ |
478 |
printf(" Bound Socket %s\n", XVC_TCP_PORT); |
482 |
printf(" Bound Socket %s\n", XVC_TCP_PORT); |
479 |
} |
483 |
} |
480 |
|
484 |
|
481 |
// Help for user |
485 |
// Help for user |
482 |
printf(" Set in IMPACT xilinx_xvc host=%s:%s disableversioncheck=true\n", sMyName, XVC_TCP_PORT); |
486 |
printf(" Set in IMPACT xilinx_xvc host=%s:%s disableversioncheck=true\n", sMyName, XVC_TCP_PORT); |
483 |
|
487 |
|
484 |
freeaddrinfo(result); |
488 |
freeaddrinfo(result); |
485 |
|
489 |
|
486 |
// Listen SOCKET |
490 |
// Listen SOCKET |
487 |
iResult = listen(ListenSocket, SOMAXCONN); |
491 |
iResult = listen(ListenSocket, SOMAXCONN); |
488 |
if (iResult == SOCKET_ERROR) |
492 |
if (iResult == SOCKET_ERROR) |
489 |
{ |
493 |
{ |
490 |
printf("listen failed with error: %d\n", WSAGetLastError()); |
494 |
fprintf(stderr, "listen failed with error: %d\n", WSAGetLastError()); |
491 |
closesocket(ListenSocket); |
495 |
closesocket(ListenSocket); |
492 |
WSACleanup(); |
496 |
WSACleanup(); |
493 |
jtagClosePort(); |
497 |
jtagClosePort(); |
494 |
return -2; |
498 |
return -2; |
495 |
} |
499 |
} |
496 |
|
500 |
|
497 |
printf("\n"); |
501 |
printf("\n"); |
498 |
|
502 |
|
499 |
do |
503 |
do |
500 |
{ |
504 |
{ |
501 |
printf(" Listen\n"); |
505 |
printf(" Listen\n"); |
502 |
jtagSetLED(true); |
506 |
jtagSetLED(true); |
503 |
|
507 |
|
504 |
// Accept a client SOCKET |
508 |
// Accept a client SOCKET |
505 |
sockaddr ClientSocetAddr; |
509 |
sockaddr ClientSocetAddr; |
506 |
int ClientSocetAddrLen = sizeof(sockaddr); |
510 |
int ClientSocetAddrLen = sizeof(sockaddr); |
507 |
ClientSocket = accept(ListenSocket, &ClientSocetAddr, &ClientSocetAddrLen); |
511 |
ClientSocket = accept(ListenSocket, &ClientSocetAddr, &ClientSocetAddrLen); |
508 |
if (ClientSocket == INVALID_SOCKET) |
512 |
if (ClientSocket == INVALID_SOCKET) |
509 |
{ |
513 |
{ |
510 |
printf("accept failed with error: %d\n", WSAGetLastError()); |
514 |
fprintf(stderr, "accept failed with error: %d\n", WSAGetLastError()); |
511 |
closesocket(ListenSocket); |
515 |
closesocket(ListenSocket); |
512 |
WSACleanup(); |
516 |
WSACleanup(); |
513 |
jtagClosePort(); |
517 |
jtagClosePort(); |
514 |
return -2; |
518 |
return -2; |
515 |
} |
519 |
} |
516 |
|
520 |
|
517 |
// Print Accepted + Address |
521 |
// Print Accepted + Address |
518 |
printf(" Accepted "); |
522 |
printf(" Accepted "); |
519 |
jtagSetLED(false); |
523 |
jtagSetLED(false); |
520 |
for (int i=2; i<2+4-1; i++) |
524 |
for (int i=2; i<2+4-1; i++) |
521 |
{ |
525 |
{ |
522 |
printf("%d.", (unsigned char)ClientSocetAddr.sa_data[i]); |
526 |
printf("%d.", (unsigned char)ClientSocetAddr.sa_data[i]); |
523 |
} |
527 |
} |
524 |
printf("%d:%d\n", (unsigned char)ClientSocetAddr.sa_data[2+4-1], (unsigned char)ClientSocetAddr.sa_data[0]*256+(unsigned char)ClientSocetAddr.sa_data[1]); |
528 |
printf("%d:%d\n", (unsigned char)ClientSocetAddr.sa_data[2+4-1], (unsigned char)ClientSocetAddr.sa_data[0]*256+(unsigned char)ClientSocetAddr.sa_data[1]); |
525 |
|
529 |
|
526 |
// Process Data until the peer shuts down the connection |
530 |
// Process Data until the peer shuts down the connection |
527 |
int Cnt = 0; |
531 |
int Cnt = 0; |
528 |
printf(" Handle Data "); |
532 |
printf(" Handle Data "); |
529 |
do |
533 |
do |
530 |
{ |
534 |
{ |
531 |
iResult = handleData(ClientSocket); |
535 |
iResult = handleData(ClientSocket); |
532 |
if (iResult>=0) |
536 |
if (iResult>=0) |
533 |
{ |
537 |
{ |
534 |
printf("."); |
538 |
printf("."); |
535 |
Cnt++; |
539 |
Cnt++; |
536 |
if (Cnt>40) |
540 |
if (Cnt>40) |
537 |
{ |
541 |
{ |
538 |
Cnt = 0; |
542 |
Cnt = 0; |
539 |
printf("\n "); |
543 |
printf("\n "); |
540 |
} |
544 |
} |
541 |
} |
545 |
} |
542 |
} |
546 |
} |
543 |
while (iResult >= 0); |
547 |
while (iResult >= 0); |
544 |
|
548 |
|
545 |
// Connection Closed by peer |
549 |
// Connection Closed by peer |
546 |
if (iResult==-1) |
550 |
if (iResult==-1) |
547 |
{ |
551 |
{ |
548 |
// JTAG port |
552 |
// JTAG port |
549 |
jtagSetIdle(); |
553 |
jtagSetIdle(); |
550 |
} |
554 |
} |
551 |
|
555 |
|
552 |
// Error - shutdown the connection |
556 |
// Error - shutdown the connection |
553 |
if (iResult==-2) |
557 |
if (iResult==-2) |
554 |
{ |
558 |
{ |
555 |
fprintf(stderr, " Disconnect\n"); |
559 |
fprintf(stderr, " Disconnect\n"); |
556 |
iResult = shutdown(ClientSocket, SD_SEND); |
560 |
iResult = shutdown(ClientSocket, SD_SEND); |
557 |
if (iResult == SOCKET_ERROR) |
561 |
if (iResult == SOCKET_ERROR) |
558 |
{ |
562 |
{ |
559 |
fprintf(stderr, "shutdown failed with error: %d\n", WSAGetLastError()); |
563 |
fprintf(stderr, "shutdown failed with error: %d\n", WSAGetLastError()); |
560 |
} |
564 |
} |
561 |
iResult=-2; // Error |
565 |
iResult=-2; // Error |
562 |
} |
566 |
} |
563 |
|
567 |
|
564 |
// cleanup |
568 |
// cleanup |
565 |
closesocket(ClientSocket); |
569 |
closesocket(ClientSocket); |
566 |
|
570 |
|
567 |
} |
571 |
} |
568 |
// If not Error Listen Again |
572 |
// If not Error Listen Again |
569 |
while (iResult!=-2); |
573 |
while (iResult!=-2); |
570 |
|
574 |
|
571 |
// cleanup |
575 |
// cleanup |
572 |
closesocket(ListenSocket); |
576 |
closesocket(ListenSocket); |
573 |
WSACleanup(); |
577 |
WSACleanup(); |
574 |
jtagClosePort(); |
578 |
jtagClosePort(); |
575 |
|
579 |
|
576 |
return 1; |
580 |
return 1; |
577 |
} |
581 |
} |