1 |
// MLAB Xilinx Virtual Cable Network Server |
1 |
// MLAB Xilinx Virtual Cable Network Server |
2 |
// ---------------------------------------- |
2 |
// ---------------------------------------- |
3 |
// |
3 |
// |
4 |
// (c) miho 2012, 2013 http://www.mlab.cz/PermaLink/XVC_SOFTWARE |
4 |
// (c) miho 2012, 2013 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 explanation (multiple instance of XVC Server) |
15 |
// 1.04 2013_04 Socket Bind Error with explanation (multiple instance of XVC Server) |
16 |
// 1.05 2013_04 Test FTDI cable during wait for Accept (to stop the server immediately when cable is disconnected) |
16 |
// 1.05 2013_04 Test FTDI cable during wait for Accept (to stop the server immediately when cable is disconnected) |
17 |
// 1.06 2013_04 Added support for Linux (thanks to Martin Poviser) |
17 |
// 1.06 2013_04 Added support for Linux (thanks to Martin Poviser) |
18 |
// 1.07 2013_04 Rewritten Host Address function for Linux (function gethostbyname returns 127.0.1.1 on Debian systems) |
18 |
// 1.07 2013_04 Rewritten Host Address function for Linux (function gethostbyname returns 127.0.1.1 on Debian systems) |
19 |
// Solved compatibility problems on Linux (FT_SetLatncyTimer requires delay, udev problem with ftdi_sio driver) |
19 |
// Solved compatibility problems on Linux (FT_SetLatncyTimer requires delay, udev problem with ftdi_sio driver) |
20 |
// 1.08 2013_06 Added linux x86_64 variant |
20 |
// 1.08 2013_06 Added linux x86_64 variant |
21 |
// |
21 |
// |
22 |
// |
22 |
// |
23 |
// Purpose: |
23 |
// Purpose: |
24 |
// |
24 |
// |
25 |
// XILINX development software (ISE, WebPack) supports several types of JTAG programming |
25 |
// XILINX development software (ISE, WebPack) supports several types of JTAG programming |
26 |
// cables. Among them there is one particularly interesting. It is Xilinx Virtual Cable |
26 |
// cables. Among them there is one particularly interesting. It is Xilinx Virtual Cable |
27 |
// which uses (documented) XVC network protocol to send JTAG commands across TCP/IP network. |
27 |
// which uses (documented) XVC network protocol to send JTAG commands across TCP/IP network. |
28 |
// So it is possible to realize own hardware/software and have it directly supported by |
28 |
// So it is possible to realize own hardware/software and have it directly supported by |
29 |
// XILINX development software (both IMPACT and ChipScope). |
29 |
// XILINX development software (both IMPACT and ChipScope). |
30 |
// |
30 |
// |
31 |
// This program listens TCP data send by XILINX ISE IMAPACT (or ChipScope) and sends it |
31 |
// This program listens TCP data send by XILINX ISE IMAPACT (or ChipScope) and sends it |
32 |
// to the JTAG device (typically FPGA) connected to FTDI USB Chip. You can use ordinary |
32 |
// to the JTAG device (typically FPGA) connected to FTDI USB Chip. You can use ordinary |
33 |
// USB/RS232 translator based on FT232R chip or you can use our own module from |
33 |
// USB/RS232 translator based on FT232R chip or you can use our own module from |
34 |
// http://www.mlab.cz/PermaLink/XVC_FT220X |
34 |
// http://www.mlab.cz/PermaLink/XVC_FT220X |
35 |
// |
35 |
// |
36 |
// Target device JTAG port is connected to pins on FTDI USB chip. Program writes to standard |
36 |
// Target device JTAG port is connected to pins on FTDI USB chip. Program writes to standard |
37 |
// output Which pins are used. Program writes what to set in ISE to enable XVC plugin. |
37 |
// output Which pins are used. Program writes what to set in ISE to enable XVC plugin. |
38 |
// |
38 |
// |
39 |
// |
39 |
// |
40 |
// Environment: |
40 |
// Environment: |
41 |
// |
41 |
// |
42 |
// This is Win32 Console Application and run in WinXP / Win7 / Win8 both 32 and 64 bit. |
42 |
// This is Win32 Console Application and run in WinXP / Win7 / Win8 both 32 and 64 bit. |
43 |
// |
43 |
// |
44 |
// Program needs to listen to the network so it is necessary to allow doing so. In Windows |
44 |
// Program needs to listen to the network so it is necessary to allow doing so. In Windows |
45 |
// firewall configuration enable networking for the exe file. |
45 |
// firewall configuration enable networking for the exe file. |
46 |
// WinXP: run as Administrator c:\WINDOWS\System32\firewall.cpl and add the exe file |
46 |
// WinXP: run as Administrator c:\WINDOWS\System32\firewall.cpl and add the exe file |
47 |
// Win7: the system asks directly to do so |
47 |
// Win7: the system asks directly to do so |
48 |
// |
48 |
// |
49 |
// |
49 |
// |
50 |
// Technology: |
50 |
// Technology: |
51 |
// |
51 |
// |
52 |
// The program uses Windows WINSOCK2 library for network communication |
52 |
// The program uses Windows WINSOCK2 library for network communication |
53 |
// and FTDI ftd2xx library for communication with FTDI USB chip. |
53 |
// and FTDI ftd2xx library for communication with FTDI USB chip. |
54 |
// It can be staticly linked to minimize dependencies on libraries. |
54 |
// It can be staticly linked to minimize dependencies on libraries. |
55 |
// Program requires FTDI drivers installed. |
55 |
// Program requires FTDI drivers installed. |
56 |
// Because of the usage of standard libraries you don't need to solve how to sign drivers. |
56 |
// Because of the usage of standard libraries you don't need to solve how to sign drivers. |
57 |
// |
57 |
// |
58 |
// The program was debug with FT232R and FT220X device. |
58 |
// The program was debug with FT232R and FT220X device. |
59 |
// It should work with any similar FTDI USB chip. |
59 |
// It should work with any similar FTDI USB chip. |
60 |
// |
60 |
// |
61 |
// XVC protocol is documented (you have to ask XILINX support to gain access). |
61 |
// XVC protocol is documented (you have to ask XILINX support to gain access). |
62 |
// The program is inspired by the work http://debugmo.de/2012/02/xvcd-the-xilinx-virtual-cable-daemon/ |
62 |
// The program is inspired by the work http://debugmo.de/2012/02/xvcd-the-xilinx-virtual-cable-daemon/ |
63 |
// Ask Google about Xilinx Virtual Cable. |
63 |
// Ask Google about Xilinx Virtual Cable. |
64 |
// |
64 |
// |
65 |
// |
65 |
// |
66 |
// Compilation for Windows: |
66 |
// Compilation for Windows: |
67 |
// |
67 |
// |
68 |
// MS Visual C++ 2010 Express (free, registration required) |
68 |
// MS Visual C++ 2010 Express (free, registration required) |
69 |
// Create new empty project for Win32 Console Application and name project mlab_xvcd (to build mlab_xvcd.exe) |
69 |
// Create new empty project for Win32 Console Application and name project mlab_xvcd (to build mlab_xvcd.exe) |
70 |
// Header Files / Add / Existing Items - all .h files |
70 |
// Header Files / Add / Existing Items - all .h files |
71 |
// Source Files / Add / Existing Items - all .cpp files |
71 |
// Source Files / Add / Existing Items - all .cpp files |
72 |
// Library Files / Add / Existing Items - all .lib .h files from lib_win32 directory |
72 |
// Library Files / Add / Existing Items - all .lib .h files from lib_win32 directory |
73 |
// Select Release version (no debug info) |
73 |
// Select Release version (no debug info) |
74 |
// Set static linkage Project Properties / Configuration Release / Configuration Properties |
74 |
// Set static linkage Project Properties / Configuration Release / Configuration Properties |
75 |
// / Code Generation / Runtime Library = Multithreaded (/MT) |
75 |
// / Code Generation / Runtime Library = Multithreaded (/MT) |
76 |
// |
76 |
// |
77 |
// Compilation for Linux: |
77 |
// Compilation for Linux: |
78 |
// |
78 |
// |
79 |
// On Ubuntu 12.04LTS just run the .sh file |
79 |
// On Ubuntu 12.04LTS just run the .sh file |
80 |
// |
80 |
// |
81 |
// Problems: |
81 |
// Problems: |
82 |
// |
82 |
// |
83 |
// Programming of SPI FLASH configuration memory connected to FPGA does not work. No idea why. |
83 |
// Programming of SPI FLASH configuration memory connected to FPGA does not work. No idea why. |
84 |
// It does not work for internal FLASH of Spartan XC3SxxAN either. |
84 |
// It does not work for internal FLASH of Spartan XC3SxxAN either. |
85 |
// |
85 |
// |
86 |
// |
86 |
// |
87 |
// Possible improvements: |
87 |
// Possible improvements: |
88 |
// |
88 |
// |
89 |
// External definition of JTAG pins. |
89 |
// External definition of JTAG pins. |
90 |
// Enable Socket Number (to be able to run multiple XVC Servers), now it is constant XVC_TCP_PORT (should be only a default) |
90 |
// Enable Socket Number (to be able to run multiple XVC Servers), now it is constant XVC_TCP_PORT (should be only a default) |
91 |
|
91 |
|
92 |
|
92 |
|
93 |
// Library Definitions |
93 |
// Library Definitions |
94 |
// ------------------- |
94 |
// ------------------- |
95 |
|
95 |
|
96 |
#undef UNICODE |
96 |
#undef UNICODE |
97 |
#define WIN32_LEAN_AND_MEAN |
97 |
#define WIN32_LEAN_AND_MEAN |
98 |
|
98 |
|
99 |
#include "mlab_xvcd.h" // Program Configuration |
99 |
#include "mlab_xvcd.h" // Program Configuration |
100 |
#include <stdlib.h> // Standard Library (exit, atoi, ...) |
100 |
#include <stdlib.h> // Standard Library (exit, atoi, ...) |
101 |
#include <stdio.h> // Standard IO (printf, ...) |
101 |
#include <stdio.h> // Standard IO (printf, ...) |
102 |
#include <signal.h> // CTRL+C handling |
102 |
#include <signal.h> // CTRL+C handling |
103 |
|
103 |
|
104 |
#ifdef WIN32 |
104 |
#ifdef WIN32 |
105 |
|
105 |
|
106 |
#include <windows.h> // Windows Console Application |
106 |
#include <windows.h> // Windows Console Application |
107 |
#include <winsock2.h> // Windows WinSock2 |
107 |
#include <winsock2.h> // Windows WinSock2 |
108 |
#include <ws2tcpip.h> // Windows WinSock2 |
108 |
#include <ws2tcpip.h> // Windows WinSock2 |
109 |
|
109 |
|
110 |
// Link with library |
110 |
// Link with library |
111 |
#pragma comment (lib, "Ws2_32.lib") |
111 |
#pragma comment (lib, "Ws2_32.lib") |
112 |
//#pragma comment (lib, "../lib_win32/ftd2xx.lib") // Add this file to Resources |
112 |
//#pragma comment (lib, "../lib_win32/ftd2xx.lib") // Add this file to Resources |
113 |
|
113 |
|
114 |
#else // not WIN32 |
114 |
#else // not WIN32 |
115 |
|
115 |
|
116 |
#include "lib_linux/WinTypes.h" |
116 |
#include "lib_linux/WinTypes.h" |
117 |
#include <sys/types.h> |
117 |
#include <sys/types.h> |
118 |
#include <sys/socket.h> |
118 |
#include <sys/socket.h> |
119 |
#include <fcntl.h> |
119 |
#include <fcntl.h> |
120 |
#include <errno.h> |
120 |
#include <errno.h> |
121 |
#include <unistd.h> |
121 |
#include <unistd.h> |
122 |
#include <netdb.h> |
122 |
#include <netdb.h> |
123 |
#include <net/if.h> |
123 |
#include <net/if.h> |
124 |
#include <sys/ioctl.h> |
124 |
#include <sys/ioctl.h> |
125 |
#include <arpa/inet.h> |
125 |
#include <arpa/inet.h> |
126 |
|
126 |
|
127 |
#endif |
127 |
#endif |
128 |
|
128 |
|
129 |
#define XVC_RX_BUFLEN (XVC_JTAG_LEN/8*2+20) // Length of receive buffer in bytes (command+length+TMSbuffer+TDIbuffer) |
129 |
#define XVC_RX_BUFLEN (XVC_JTAG_LEN/8*2+20) // Length of receive buffer in bytes (command+length+TMSbuffer+TDIbuffer) |
130 |
#define XVC_TX_BUFLEN (XVC_JTAG_LEN/8) // Length of transmit buffer in bytes (TDObuffer) |
130 |
#define XVC_TX_BUFLEN (XVC_JTAG_LEN/8) // Length of transmit buffer in bytes (TDObuffer) |
131 |
|
131 |
|
132 |
#ifdef WIN32 |
132 |
#ifdef WIN32 |
133 |
|
133 |
|
134 |
typedef int socklen_t; |
134 |
typedef int socklen_t; |
135 |
|
135 |
|
136 |
#else //not WIN32 |
136 |
#else //not WIN32 |
137 |
|
137 |
|
138 |
typedef int SOCKET; |
138 |
typedef int SOCKET; |
139 |
|
139 |
|
140 |
#define SOCKET_ERROR -1 |
140 |
#define SOCKET_ERROR -1 |
141 |
#define INVALID_SOCKET -1 |
141 |
#define INVALID_SOCKET -1 |
142 |
|
142 |
|
143 |
void closesocket(int socket) |
143 |
void closesocket(int socket) |
144 |
{ |
144 |
{ |
145 |
close(socket); |
145 |
close(socket); |
146 |
} |
146 |
} |
147 |
|
147 |
|
148 |
void WSACleanup() |
148 |
void WSACleanup() |
149 |
{ |
149 |
{ |
150 |
} |
150 |
} |
151 |
|
151 |
|
152 |
int WSAGetLastError() |
152 |
int WSAGetLastError() |
153 |
{ |
153 |
{ |
154 |
return errno; |
154 |
return errno; |
155 |
} |
155 |
} |
156 |
|
156 |
|
157 |
#endif |
157 |
#endif |
158 |
|
158 |
|
159 |
// JTAG state machine |
159 |
// JTAG state machine |
160 |
// ------------------ |
160 |
// ------------------ |
161 |
|
161 |
|
162 |
// JTAG States |
162 |
// JTAG States |
163 |
enum |
163 |
enum |
164 |
{ |
164 |
{ |
165 |
test_logic_reset, run_test_idle, // Starts from 0 |
165 |
test_logic_reset, run_test_idle, // Starts from 0 |
166 |
|
166 |
|
167 |
select_dr_scan, capture_dr, shift_dr, |
167 |
select_dr_scan, capture_dr, shift_dr, |
168 |
exit1_dr, pause_dr, exit2_dr, update_dr, |
168 |
exit1_dr, pause_dr, exit2_dr, update_dr, |
169 |
|
169 |
|
170 |
select_ir_scan, capture_ir, shift_ir, |
170 |
select_ir_scan, capture_ir, shift_ir, |
171 |
exit1_ir, pause_ir, exit2_ir, update_ir, |
171 |
exit1_ir, pause_ir, exit2_ir, update_ir, |
172 |
|
172 |
|
173 |
num_states |
173 |
num_states |
174 |
}; |
174 |
}; |
175 |
|
175 |
|
176 |
|
176 |
|
177 |
// JTAG State Machine transfer Function |
177 |
// JTAG State Machine transfer Function |
178 |
static int jtagStep(int state, int tms) |
178 |
static int jtagStep(int state, int tms) |
179 |
{ |
179 |
{ |
180 |
static const int next_state[num_states][2] = |
180 |
static const int next_state[num_states][2] = |
181 |
{ |
181 |
{ |
182 |
/* JTAG State -->> New State */ |
182 |
/* JTAG State -->> New State */ |
183 |
/* -------------------------------------------------------------*/ |
183 |
/* -------------------------------------------------------------*/ |
184 |
/* | TMS=0 | TMS=1 */ |
184 |
/* | TMS=0 | TMS=1 */ |
185 |
/* -------------------------------------------------------------*/ |
185 |
/* -------------------------------------------------------------*/ |
186 |
/* [test_logic_reset] -> */ { run_test_idle, test_logic_reset }, |
186 |
/* [test_logic_reset] -> */ { run_test_idle, test_logic_reset }, |
187 |
/* [run_test_idle] -> */ { run_test_idle, select_dr_scan }, |
187 |
/* [run_test_idle] -> */ { run_test_idle, select_dr_scan }, |
188 |
/* [select_dr_scan] -> */ { capture_dr, select_ir_scan }, |
188 |
/* [select_dr_scan] -> */ { capture_dr, select_ir_scan }, |
189 |
/* [capture_dr] -> */ { shift_dr, exit1_dr }, |
189 |
/* [capture_dr] -> */ { shift_dr, exit1_dr }, |
190 |
/* [shift_dr] -> */ { shift_dr, exit1_dr }, |
190 |
/* [shift_dr] -> */ { shift_dr, exit1_dr }, |
191 |
/* [exit1_dr] -> */ { pause_dr, update_dr }, |
191 |
/* [exit1_dr] -> */ { pause_dr, update_dr }, |
192 |
/* [pause_dr] -> */ { pause_dr, exit2_dr }, |
192 |
/* [pause_dr] -> */ { pause_dr, exit2_dr }, |
193 |
/* [exit2_dr] -> */ { shift_dr, update_dr }, |
193 |
/* [exit2_dr] -> */ { shift_dr, update_dr }, |
194 |
/* [update_dr] -> */ { run_test_idle, select_dr_scan }, |
194 |
/* [update_dr] -> */ { run_test_idle, select_dr_scan }, |
195 |
/* [select_ir_scan] -> */ { capture_ir, test_logic_reset }, |
195 |
/* [select_ir_scan] -> */ { capture_ir, test_logic_reset }, |
196 |
/* [capture_ir] -> */ { shift_ir, exit1_ir }, |
196 |
/* [capture_ir] -> */ { shift_ir, exit1_ir }, |
197 |
/* [shift_ir] -> */ { shift_ir, exit1_ir }, |
197 |
/* [shift_ir] -> */ { shift_ir, exit1_ir }, |
198 |
/* [exit1_ir] -> */ { pause_ir, update_ir }, |
198 |
/* [exit1_ir] -> */ { pause_ir, update_ir }, |
199 |
/* [pause_ir] -> */ { pause_ir, exit2_ir }, |
199 |
/* [pause_ir] -> */ { pause_ir, exit2_ir }, |
200 |
/* [exit2_ir] -> */ { shift_ir, update_ir }, |
200 |
/* [exit2_ir] -> */ { shift_ir, update_ir }, |
201 |
/* [update_ir] -> */ { run_test_idle, select_dr_scan } |
201 |
/* [update_ir] -> */ { run_test_idle, select_dr_scan } |
202 |
}; |
202 |
}; |
203 |
|
203 |
|
204 |
return next_state[state][tms]; |
204 |
return next_state[state][tms]; |
205 |
} |
205 |
} |
206 |
|
206 |
|
207 |
|
207 |
|
208 |
int handleData(SOCKET ClientSocket) |
208 |
int handleData(SOCKET ClientSocket) |
209 |
{ |
209 |
{ |
210 |
|
210 |
|
211 |
bool seen_tlr = false; |
211 |
bool seen_tlr = false; |
212 |
bool jtagError = false; |
212 |
bool jtagError = false; |
213 |
|
213 |
|
214 |
static int jtag_state; |
214 |
static int jtag_state; |
215 |
|
215 |
|
216 |
do |
216 |
do |
217 |
{ |
217 |
{ |
218 |
int iResult; |
218 |
int iResult; |
219 |
|
219 |
|
220 |
// Read Command |
220 |
// Read Command |
221 |
char command[16]; |
221 |
char command[16]; |
222 |
unsigned int commandLen = 0; |
222 |
unsigned int commandLen = 0; |
223 |
|
223 |
|
224 |
// Read String terminated by ':' |
224 |
// Read String terminated by ':' |
225 |
do |
225 |
do |
226 |
{ |
226 |
{ |
227 |
iResult = recv(ClientSocket, command+commandLen, 1, 0); |
227 |
iResult = recv(ClientSocket, command+commandLen, 1, 0); |
228 |
if (iResult==0) |
228 |
if (iResult==0) |
229 |
{ |
229 |
{ |
230 |
printf("\n Connection Closed\n\n"); |
230 |
printf("\n Connection Closed\n\n"); |
231 |
return -1; |
231 |
return -1; |
232 |
} |
232 |
} |
233 |
else if (iResult==1) |
233 |
else if (iResult==1) |
234 |
{ |
234 |
{ |
235 |
commandLen++; |
235 |
commandLen++; |
236 |
} |
236 |
} |
237 |
else |
237 |
else |
238 |
{ |
238 |
{ |
239 |
fprintf(stderr, "Error Reading Command\n"); |
239 |
fprintf(stderr, "Error Reading Command\n"); |
240 |
return -2; |
240 |
return -2; |
241 |
} |
241 |
} |
242 |
} |
242 |
} |
243 |
while (command[commandLen-1]!=':' && commandLen<sizeof(command)-1 ); |
243 |
while (command[commandLen-1]!=':' && commandLen<sizeof(command)-1 ); |
244 |
command[commandLen] = char(0); |
244 |
command[commandLen] = char(0); |
245 |
|
245 |
|
246 |
if (0==strncmp(command, "shift:", sizeof(command))) |
246 |
if (0==strncmp(command, "shift:", sizeof(command))) |
247 |
{ |
247 |
{ |
248 |
|
248 |
|
249 |
} |
249 |
} |
250 |
else |
250 |
else |
251 |
{ |
251 |
{ |
252 |
fprintf(stderr, "Invalid Command '%s'\n", command); |
252 |
fprintf(stderr, "Invalid Command '%s'\n", command); |
253 |
return -2; |
253 |
return -2; |
254 |
} |
254 |
} |
255 |
|
255 |
|
256 |
// Read Length (in bits, 32bit integer) |
256 |
// Read Length (in bits, 32bit integer) |
257 |
int len; |
257 |
int len; |
258 |
|
258 |
|
259 |
iResult = recv(ClientSocket, (char *)&len, 4, 0); // pøepsat pøenositelnì |
259 |
iResult = recv(ClientSocket, (char *)&len, 4, 0); // TODO: rewrite for multiplatform use |
260 |
if (iResult==0) |
260 |
if (iResult==0) |
261 |
{ |
261 |
{ |
262 |
printf("\n Connection Closed\n\n"); |
262 |
printf("\n Connection Closed\n\n"); |
263 |
return -1; |
263 |
return -1; |
264 |
} |
264 |
} |
265 |
if (iResult != 4) |
265 |
if (iResult != 4) |
266 |
{ |
266 |
{ |
267 |
fprintf(stderr, "Reading Length Failed\n"); |
267 |
fprintf(stderr, "Reading Length Failed\n"); |
268 |
return -2; |
268 |
return -2; |
269 |
} |
269 |
} |
270 |
|
270 |
|
271 |
char buffer[2048]; |
271 |
char buffer[2048]; |
272 |
|
272 |
|
273 |
// Read Data (data string for TMS and TDI) |
273 |
// Read Data (data string for TMS and TDI) |
274 |
unsigned int nr_bytes = (len + 7) / 8; |
274 |
unsigned int nr_bytes = (len + 7) / 8; |
275 |
if (nr_bytes * 2 > sizeof(buffer)) |
275 |
if (nr_bytes * 2 > sizeof(buffer)) |
276 |
{ |
276 |
{ |
277 |
fprintf(stderr, "Buffer Size Exceeded\n"); |
277 |
fprintf(stderr, "Buffer Size Exceeded\n"); |
278 |
return -2; |
278 |
return -2; |
279 |
} |
279 |
} |
280 |
|
280 |
|
281 |
unsigned int iReceivedBytes=0; |
281 |
unsigned int iReceivedBytes=0; |
282 |
while (iReceivedBytes<nr_bytes * 2) |
282 |
while (iReceivedBytes<nr_bytes * 2) |
283 |
{ |
283 |
{ |
284 |
iResult = recv(ClientSocket, buffer+iReceivedBytes, nr_bytes * 2 - iReceivedBytes, 0); |
284 |
iResult = recv(ClientSocket, buffer+iReceivedBytes, nr_bytes * 2 - iReceivedBytes, 0); |
285 |
if (iResult==0) |
285 |
if (iResult==0) |
286 |
{ |
286 |
{ |
287 |
printf("\n Connection Closed\n\n"); |
287 |
printf("\n Connection Closed\n\n"); |
288 |
return -1; |
288 |
return -1; |
289 |
} |
289 |
} |
290 |
if (iResult<=0) |
290 |
if (iResult<=0) |
291 |
{ |
291 |
{ |
292 |
fprintf(stderr, "Reading Data Failed %d %d\n", iResult, nr_bytes * 2); |
292 |
fprintf(stderr, "Reading Data Failed %d %d\n", iResult, nr_bytes * 2); |
293 |
return -2; |
293 |
return -2; |
294 |
} |
294 |
} |
295 |
iReceivedBytes += iResult; |
295 |
iReceivedBytes += iResult; |
296 |
} |
296 |
} |
297 |
|
297 |
|
298 |
char result[1024]; |
298 |
char result[1024]; |
299 |
memset(result, 0, nr_bytes); |
299 |
memset(result, 0, nr_bytes); |
300 |
|
300 |
|
301 |
// Deal with JTAG |
301 |
// Deal with JTAG |
302 |
|
302 |
|
303 |
// Only allow exiting if the state is rti and the IR |
303 |
// Only allow exiting if the state is rti and the IR |
304 |
// has the default value (IDCODE) by going through test_logic_reset. |
304 |
// has the default value (IDCODE) by going through test_logic_reset. |
305 |
// As soon as going through capture_dr or capture_ir no exit is |
305 |
// As soon as going through capture_dr or capture_ir no exit is |
306 |
// allowed as this will change DR/IR. |
306 |
// allowed as this will change DR/IR. |
307 |
seen_tlr = (seen_tlr || jtag_state == test_logic_reset) && (jtag_state != capture_dr) && (jtag_state != capture_ir); |
307 |
seen_tlr = (seen_tlr || jtag_state == test_logic_reset) && (jtag_state != capture_dr) && (jtag_state != capture_ir); |
308 |
|
308 |
|
309 |
// Due to a weird bug(??) xilinx impacts goes through another "capture_ir"/"capture_dr" cycle after |
309 |
// Due to a weird bug(??) xilinx impacts goes through another "capture_ir"/"capture_dr" cycle after |
310 |
// reading IR/DR which unfortunately sets IR to the read-out IR value. |
310 |
// reading IR/DR which unfortunately sets IR to the read-out IR value. |
311 |
// Just ignore these transactions. |
311 |
// Just ignore these transactions. |
312 |
if ((jtag_state == exit1_ir && len == 5 && buffer[0] == 0x17) || (jtag_state == exit1_dr && len == 4 && buffer[0] == 0x0b)) |
312 |
if ((jtag_state == exit1_ir && len == 5 && buffer[0] == 0x17) || (jtag_state == exit1_dr && len == 4 && buffer[0] == 0x0b)) |
313 |
{ |
313 |
{ |
314 |
// printf("Ignoring Bogus jtag State movement at jtag_state %d\n", jtag_state); |
314 |
// printf("Ignoring Bogus jtag State movement at jtag_state %d\n", jtag_state); |
315 |
} |
315 |
} |
316 |
else |
316 |
else |
317 |
{ |
317 |
{ |
318 |
for (int i = 0; i < len; ++i) |
318 |
for (int i = 0; i < len; ++i) |
319 |
{ |
319 |
{ |
320 |
// |
320 |
// |
321 |
// Do the actual cycle. |
321 |
// Do the actual cycle. |
322 |
// |
322 |
// |
323 |
int tms = !!(buffer[i/8] & (1<<(i&7))); |
323 |
int tms = !!(buffer[i/8] & (1<<(i&7))); |
324 |
// |
324 |
// |
325 |
// Track the state. |
325 |
// Track the state. |
326 |
// |
326 |
// |
327 |
jtag_state = jtagStep(jtag_state, tms); |
327 |
jtag_state = jtagStep(jtag_state, tms); |
328 |
} |
328 |
} |
329 |
if (jtagScan((unsigned char *) buffer, (unsigned char *) buffer + nr_bytes, (unsigned char *) result, len) < 0) |
329 |
if (jtagScan((unsigned char *) buffer, (unsigned char *) buffer + nr_bytes, (unsigned char *) result, len) < 0) |
330 |
{ |
330 |
{ |
331 |
//fprintf(stderr, "jtagScan failed\n"); |
331 |
//fprintf(stderr, "jtagScan failed\n"); |
332 |
// Can't stop now, have to sent (any) answer not to hung the IMPACT |
332 |
// Can't stop now, have to sent (any) answer not to hung the IMPACT |
333 |
jtagError = true; |
333 |
jtagError = true; |
334 |
} |
334 |
} |
335 |
} |
335 |
} |
336 |
|
336 |
|
337 |
// Send the Ansver |
337 |
// Send the Ansver |
338 |
iResult = send(ClientSocket, result, nr_bytes, 0 ); |
338 |
iResult = send(ClientSocket, result, nr_bytes, 0 ); |
339 |
if (iResult == SOCKET_ERROR) |
339 |
if (iResult == SOCKET_ERROR) |
340 |
{ |
340 |
{ |
341 |
printf("Send Failed with Error: %d\n", WSAGetLastError()); |
341 |
printf("Send Failed with Error: %d\n", WSAGetLastError()); |
342 |
closesocket(ClientSocket); |
342 |
closesocket(ClientSocket); |
343 |
WSACleanup(); |
343 |
WSACleanup(); |
344 |
return -2; |
344 |
return -2; |
345 |
} |
345 |
} |
346 |
// printf("Bytes Sent: %d\n", iSendResult); |
346 |
// printf("Bytes Sent: %d\n", iSendResult); |
347 |
// printf("jtag state %d\n", jtag_state); |
347 |
// printf("jtag state %d\n", jtag_state); |
348 |
} |
348 |
} |
349 |
while (!(seen_tlr && jtag_state == run_test_idle)); |
349 |
while (!(seen_tlr && jtag_state == run_test_idle)); |
350 |
|
350 |
|
351 |
return jtagError ? -2 : 0; |
351 |
return jtagError ? -2 : 0; |
352 |
} |
352 |
} |
353 |
|
353 |
|
354 |
|
354 |
|
355 |
// Stop Handler - switch JTAG port off and stop program |
355 |
// Stop Handler - switch JTAG port off and stop program |
356 |
void stopHandler(int) |
356 |
void stopHandler(int) |
357 |
{ |
357 |
{ |
358 |
jtagClosePort(); |
358 |
jtagClosePort(); |
359 |
exit(1); |
359 |
exit(1); |
360 |
} |
360 |
} |
361 |
|
361 |
|
362 |
|
362 |
|
363 |
// Print help and stop program with error |
363 |
// Print help and stop program with error |
364 |
void Help(char *progName) |
364 |
void Help(char *progName) |
365 |
{ |
365 |
{ |
366 |
fprintf(stderr, "Bad Parameters\n"); |
366 |
fprintf(stderr, "Bad Parameters\n"); |
367 |
fprintf(stderr, "\n"); |
367 |
fprintf(stderr, "\n"); |
368 |
fprintf(stderr, "Usage: %s [arg]\n", progName); |
368 |
fprintf(stderr, "Usage: %s [arg]\n", progName); |
369 |
fprintf(stderr, "\n"); |
369 |
fprintf(stderr, "\n"); |
370 |
fprintf(stderr, " Where [arg] is one of: \n"); |
370 |
fprintf(stderr, " Where [arg] is one of: \n"); |
371 |
fprintf(stderr, " -d Description Fing FTDI device by Description\n"); |
371 |
fprintf(stderr, " -d Description Fing FTDI device by Description\n"); |
372 |
fprintf(stderr, " -l Location Fing FTDI device by Loaction\n"); |
372 |
fprintf(stderr, " -l Location Fing FTDI device by Loaction\n"); |
373 |
fprintf(stderr, " -s Serial_number Fing FTDI device by it's SN\n"); |
373 |
fprintf(stderr, " -s Serial_number Fing FTDI device by it's SN\n"); |
374 |
fprintf(stderr, " -n Number Use N-th FTDI device\n"); |
374 |
fprintf(stderr, " -n Number Use N-th FTDI device\n"); |
375 |
fprintf(stderr, " The first FTDI device is used if no argument\n"); |
375 |
fprintf(stderr, " The first FTDI device is used if no argument\n"); |
376 |
exit(2); |
376 |
exit(2); |
377 |
} |
377 |
} |
378 |
|
378 |
|
379 |
|
379 |
|
380 |
int main(int argc, char *argv[]) |
380 |
int main(int argc, char *argv[]) |
381 |
{ |
381 |
{ |
382 |
// Variables |
382 |
// Variables |
383 |
bool verbose = true; |
383 |
bool verbose = true; |
384 |
|
384 |
|
385 |
// Program Info |
385 |
// Program Info |
386 |
printf("\n"); |
386 |
printf("\n"); |
387 |
printf("Xilinx Virtual Cable Network Server\n"); |
387 |
printf("Xilinx Virtual Cable Network Server\n"); |
388 |
printf("===================================\n"); |
388 |
printf("===================================\n"); |
389 |
printf("(c) miho " YEAR " v " VERSION "\n\n"); |
389 |
printf("(c) miho " YEAR " v " VERSION "\n\n"); |
390 |
|
390 |
|
391 |
// Get program name |
391 |
// Get program name |
392 |
char *cp; |
392 |
char *cp; |
393 |
char *progName; |
393 |
char *progName; |
394 |
cp = argv[0]; |
394 |
cp = argv[0]; |
395 |
progName=cp; |
395 |
progName=cp; |
396 |
while (cp[0]!='\0') |
396 |
while (cp[0]!='\0') |
397 |
{ |
397 |
{ |
398 |
if (cp[0]=='/' || cp[0]=='\\') |
398 |
if (cp[0]=='/' || cp[0]=='\\') |
399 |
progName=cp+1; |
399 |
progName=cp+1; |
400 |
cp++; |
400 |
cp++; |
401 |
} |
401 |
} |
402 |
|
402 |
|
403 |
// Process command line params |
403 |
// Process command line params |
404 |
char *findDeviceByStr = 0; // String parameter |
404 |
char *findDeviceByStr = 0; // String parameter |
405 |
int findDeviceBy = 0; // What does the string means |
405 |
int findDeviceBy = 0; // What does the string means |
406 |
|
406 |
|
407 |
if (argc>1) |
407 |
if (argc>1) |
408 |
{ |
408 |
{ |
409 |
if (argc==3) |
409 |
if (argc==3) |
410 |
{ |
410 |
{ |
411 |
findDeviceByStr = argv[2]; |
411 |
findDeviceByStr = argv[2]; |
412 |
if (strcmp(argv[1], "-d")==0) |
412 |
if (strcmp(argv[1], "-d")==0) |
413 |
{ |
413 |
{ |
414 |
findDeviceBy = OPEN_BY_DESCRIPTION; |
414 |
findDeviceBy = OPEN_BY_DESCRIPTION; |
415 |
} |
415 |
} |
416 |
else if (strcmp(argv[1], "-l")==0) |
416 |
else if (strcmp(argv[1], "-l")==0) |
417 |
{ |
417 |
{ |
418 |
findDeviceBy = OPEN_BY_LOCATION; |
418 |
findDeviceBy = OPEN_BY_LOCATION; |
419 |
} |
419 |
} |
420 |
else if (strcmp(argv[1], "-s")==0) |
420 |
else if (strcmp(argv[1], "-s")==0) |
421 |
{ |
421 |
{ |
422 |
findDeviceBy = OPEN_BY_SERIAL_NUMBER; |
422 |
findDeviceBy = OPEN_BY_SERIAL_NUMBER; |
423 |
} |
423 |
} |
424 |
else if (strcmp(argv[1], "-n")==0) |
424 |
else if (strcmp(argv[1], "-n")==0) |
425 |
{ |
425 |
{ |
426 |
findDeviceBy = 0; |
426 |
findDeviceBy = 0; |
427 |
} |
427 |
} |
428 |
else |
428 |
else |
429 |
{ |
429 |
{ |
430 |
Help(progName); |
430 |
Help(progName); |
431 |
} |
431 |
} |
432 |
} |
432 |
} |
433 |
else |
433 |
else |
434 |
{ |
434 |
{ |
435 |
Help(progName); |
435 |
Help(progName); |
436 |
} |
436 |
} |
437 |
} |
437 |
} |
438 |
else |
438 |
else |
439 |
{ |
439 |
{ |
440 |
// Empty String - find device by number and number is empty |
440 |
// Empty String - find device by number and number is empty |
441 |
findDeviceBy = 0; |
441 |
findDeviceBy = 0; |
442 |
findDeviceByStr = (char *)""; |
442 |
findDeviceByStr = (char *)""; |
443 |
} |
443 |
} |
444 |
|
444 |
|
445 |
// Find, Init and Open FTDI USB Chip |
445 |
// Find, Init and Open FTDI USB Chip |
446 |
if (jtagOpenPort(findDeviceBy, findDeviceByStr)<0) { |
446 |
if (jtagOpenPort(findDeviceBy, findDeviceByStr)<0) { |
447 |
// No Device Found |
447 |
// No Device Found |
448 |
fprintf(stderr, "ERROR: No Device Found\n"); |
448 |
fprintf(stderr, "ERROR: No Device Found\n"); |
449 |
return -1; |
449 |
return -1; |
450 |
} |
450 |
} |
451 |
|
451 |
|
452 |
// Signal Handler (for CRTL+C) |
452 |
// Signal Handler (for CRTL+C) |
453 |
signal(SIGINT, &stopHandler); |
453 |
signal(SIGINT, &stopHandler); |
454 |
|
454 |
|
455 |
printf("Starting Network Server\n"); |
455 |
printf("Starting Network Server\n"); |
456 |
int iResult; |
456 |
int iResult; |
457 |
|
457 |
|
458 |
SOCKET ListenSocket = INVALID_SOCKET; |
458 |
SOCKET ListenSocket = INVALID_SOCKET; |
459 |
SOCKET ClientSocket = INVALID_SOCKET; |
459 |
SOCKET ClientSocket = INVALID_SOCKET; |
460 |
|
460 |
|
461 |
#ifdef WIN32 |
461 |
#ifdef WIN32 |
462 |
// Initialize Winsock |
462 |
// Initialize Winsock |
463 |
WSADATA wsaData; |
463 |
WSADATA wsaData; |
464 |
iResult = WSAStartup(MAKEWORD(2,2), &wsaData); |
464 |
iResult = WSAStartup(MAKEWORD(2,2), &wsaData); |
465 |
if (iResult != 0) |
465 |
if (iResult != 0) |
466 |
{ |
466 |
{ |
467 |
fprintf(stderr, "WSAStartup failed with error: %d\n", iResult); |
467 |
fprintf(stderr, "WSAStartup failed with error: %d\n", iResult); |
468 |
jtagClosePort(); |
468 |
jtagClosePort(); |
469 |
return -2; |
469 |
return -2; |
470 |
} |
470 |
} |
471 |
#endif |
471 |
#endif |
472 |
|
472 |
|
473 |
// Display HostName |
473 |
// Display HostName |
474 |
char sMyName[255]; |
474 |
char sMyName[255]; |
475 |
gethostname(sMyName, sizeof(sMyName)); |
475 |
gethostname(sMyName, sizeof(sMyName)); |
476 |
printf(" Host Name %s\n", sMyName); |
476 |
printf(" Host Name %s\n", sMyName); |
477 |
|
477 |
|
478 |
// Display Address |
478 |
// Display Address |
479 |
#ifdef WIN32 |
479 |
#ifdef WIN32 |
480 |
hostent * pHostInfo; |
480 |
hostent * pHostInfo; |
481 |
pHostInfo = gethostbyname(sMyName); |
481 |
pHostInfo = gethostbyname(sMyName); |
482 |
printf(" Network Name %s\n", pHostInfo->h_name); |
482 |
printf(" Network Name %s\n", pHostInfo->h_name); |
483 |
if (pHostInfo->h_length>0 && pHostInfo->h_length<=16) |
483 |
if (pHostInfo->h_length>0 && pHostInfo->h_length<=16) |
484 |
{ |
484 |
{ |
485 |
printf(" Host Address "); |
485 |
printf(" Host Address "); |
486 |
for (int i=0; i<pHostInfo->h_length-1; i++) |
486 |
for (int i=0; i<pHostInfo->h_length-1; i++) |
487 |
{ |
487 |
{ |
488 |
printf("%d.", (unsigned char)pHostInfo->h_addr_list[0][i]); |
488 |
printf("%d.", (unsigned char)pHostInfo->h_addr_list[0][i]); |
489 |
} |
489 |
} |
490 |
printf("%d\n", (unsigned char)pHostInfo->h_addr_list[0][pHostInfo->h_length-1]); |
490 |
printf("%d\n", (unsigned char)pHostInfo->h_addr_list[0][pHostInfo->h_length-1]); |
491 |
} |
491 |
} |
492 |
#else |
492 |
#else |
493 |
int TempSocket; |
493 |
int TempSocket; |
494 |
struct ifreq ifreqs[20]; |
494 |
struct ifreq ifreqs[20]; |
495 |
struct ifconf ic; |
495 |
struct ifconf ic; |
496 |
|
496 |
|
497 |
ic.ifc_len = sizeof ifreqs; |
497 |
ic.ifc_len = sizeof ifreqs; |
498 |
ic.ifc_req = ifreqs; |
498 |
ic.ifc_req = ifreqs; |
499 |
|
499 |
|
500 |
TempSocket = socket(AF_INET, SOCK_DGRAM, 0); |
500 |
TempSocket = socket(AF_INET, SOCK_DGRAM, 0); |
501 |
if (TempSocket < 0) { |
501 |
if (TempSocket < 0) { |
502 |
perror("socket"); |
502 |
perror("socket"); |
503 |
return -2; |
503 |
return -2; |
504 |
} |
504 |
} |
505 |
|
505 |
|
506 |
if (ioctl(TempSocket, SIOCGIFCONF, &ic) < 0) { |
506 |
if (ioctl(TempSocket, SIOCGIFCONF, &ic) < 0) { |
507 |
perror("SIOCGIFCONF"); |
507 |
perror("SIOCGIFCONF"); |
508 |
return -2; |
508 |
return -2; |
509 |
} |
509 |
} |
510 |
|
510 |
|
511 |
for (int i = 0; i < ic.ifc_len/sizeof(struct ifreq); ++i) |
511 |
for (int i = 0; i < ic.ifc_len/sizeof(struct ifreq); ++i) |
512 |
{ |
512 |
{ |
513 |
if (ifreqs[i].ifr_name[0]!='l')// remove lo |
513 |
if (ifreqs[i].ifr_name[0]!='l')// remove lo |
514 |
printf(" Host Address %s: %s\n", |
514 |
printf(" Host Address %s: %s\n", |
515 |
ifreqs[i].ifr_name, |
515 |
ifreqs[i].ifr_name, |
516 |
inet_ntoa(((struct sockaddr_in*)&ifreqs[i].ifr_addr)->sin_addr)); |
516 |
inet_ntoa(((struct sockaddr_in*)&ifreqs[i].ifr_addr)->sin_addr)); |
517 |
} |
517 |
} |
518 |
#endif |
518 |
#endif |
519 |
|
519 |
|
520 |
// Create Protocol Structure |
520 |
// Create Protocol Structure |
521 |
struct addrinfo hints; |
521 |
struct addrinfo hints; |
522 |
memset(&hints, 0, sizeof(hints)); |
522 |
memset(&hints, 0, sizeof(hints)); |
523 |
hints.ai_family = AF_INET; // IP6 |
523 |
hints.ai_family = AF_INET; // IP6 |
524 |
hints.ai_socktype = SOCK_STREAM; // Reliable two-way connection |
524 |
hints.ai_socktype = SOCK_STREAM; // Reliable two-way connection |
525 |
hints.ai_protocol = IPPROTO_TCP; // Protocol TCP |
525 |
hints.ai_protocol = IPPROTO_TCP; // Protocol TCP |
526 |
hints.ai_flags = AI_PASSIVE; |
526 |
hints.ai_flags = AI_PASSIVE; |
527 |
|
527 |
|
528 |
// Resolve the server address and port (allocate structure "result") |
528 |
// Resolve the server address and port (allocate structure "result") |
529 |
struct addrinfo *result = NULL; |
529 |
struct addrinfo *result = NULL; |
530 |
iResult = getaddrinfo(NULL, XVC_TCP_PORT, &hints, &result); |
530 |
iResult = getaddrinfo(NULL, XVC_TCP_PORT, &hints, &result); |
531 |
if ( iResult != 0 ) |
531 |
if ( iResult != 0 ) |
532 |
{ |
532 |
{ |
533 |
fprintf(stderr, "getaddrinfo failed with error: %d\n", iResult); |
533 |
fprintf(stderr, "getaddrinfo failed with error: %d\n", iResult); |
534 |
WSACleanup(); |
534 |
WSACleanup(); |
535 |
jtagClosePort(); |
535 |
jtagClosePort(); |
536 |
return -2; |
536 |
return -2; |
537 |
} |
537 |
} |
538 |
|
538 |
|
539 |
// Create a SOCKET |
539 |
// Create a SOCKET |
540 |
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); |
540 |
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); |
541 |
if (ListenSocket == INVALID_SOCKET) |
541 |
if (ListenSocket == INVALID_SOCKET) |
542 |
{ |
542 |
{ |
543 |
fprintf(stderr, "socket failed with error: %d\n", WSAGetLastError()); |
543 |
fprintf(stderr, "socket failed with error: %d\n", WSAGetLastError()); |
544 |
freeaddrinfo(result); |
544 |
freeaddrinfo(result); |
545 |
WSACleanup(); |
545 |
WSACleanup(); |
546 |
jtagClosePort(); |
546 |
jtagClosePort(); |
547 |
return -2; |
547 |
return -2; |
548 |
} |
548 |
} |
549 |
|
549 |
|
550 |
// Bind the SOCKED (assign the address) |
550 |
// Bind the SOCKED (assign the address) |
551 |
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen); |
551 |
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen); |
552 |
if (iResult == SOCKET_ERROR) |
552 |
if (iResult == SOCKET_ERROR) |
553 |
{ |
553 |
{ |
554 |
int LastError=WSAGetLastError(); |
554 |
int LastError=WSAGetLastError(); |
555 |
fprintf(stderr, "Bind failed with error: %d\n", LastError); |
555 |
fprintf(stderr, "Bind failed with error: %d\n", LastError); |
556 |
#ifdef WIN32 |
556 |
#ifdef WIN32 |
557 |
if (LastError==WSAEADDRINUSE) |
557 |
if (LastError==WSAEADDRINUSE) |
558 |
#else |
558 |
#else |
559 |
if (LastError==EADDRINUSE) |
559 |
if (LastError==EADDRINUSE) |
560 |
#endif |
560 |
#endif |
561 |
fprintf(stderr, "Trying to start second instance of XVC Server?\n"); |
561 |
fprintf(stderr, "Trying to start second instance of XVC Server?\n"); |
562 |
freeaddrinfo(result); |
562 |
freeaddrinfo(result); |
563 |
closesocket(ListenSocket); |
563 |
closesocket(ListenSocket); |
564 |
WSACleanup(); |
564 |
WSACleanup(); |
565 |
jtagClosePort(); |
565 |
jtagClosePort(); |
566 |
return -2; |
566 |
return -2; |
567 |
} |
567 |
} |
568 |
|
568 |
|
569 |
if (verbose) |
569 |
if (verbose) |
570 |
{ |
570 |
{ |
571 |
printf(" Bound Socket %s\n", XVC_TCP_PORT); |
571 |
printf(" Bound Socket %s\n", XVC_TCP_PORT); |
572 |
} |
572 |
} |
573 |
|
573 |
|
574 |
// Help for user |
574 |
// Help for user |
575 |
printf(" Set in IMPACT xilinx_xvc host=%s:%s disableversioncheck=true\n", sMyName, XVC_TCP_PORT); |
575 |
printf(" Set in IMPACT xilinx_xvc host=%s:%s disableversioncheck=true\n", sMyName, XVC_TCP_PORT); |
576 |
|
576 |
|
577 |
freeaddrinfo(result); |
577 |
freeaddrinfo(result); |
578 |
|
578 |
|
579 |
// Listen SOCKET |
579 |
// Listen SOCKET |
580 |
iResult = listen(ListenSocket, SOMAXCONN); |
580 |
iResult = listen(ListenSocket, SOMAXCONN); |
581 |
if (iResult == SOCKET_ERROR) |
581 |
if (iResult == SOCKET_ERROR) |
582 |
{ |
582 |
{ |
583 |
fprintf(stderr, "listen failed with error: %d\n", WSAGetLastError()); |
583 |
fprintf(stderr, "listen failed with error: %d\n", WSAGetLastError()); |
584 |
closesocket(ListenSocket); |
584 |
closesocket(ListenSocket); |
585 |
WSACleanup(); |
585 |
WSACleanup(); |
586 |
jtagClosePort(); |
586 |
jtagClosePort(); |
587 |
return -2; |
587 |
return -2; |
588 |
} |
588 |
} |
589 |
|
589 |
|
590 |
printf("\n"); |
590 |
printf("\n"); |
591 |
|
591 |
|
592 |
do |
592 |
do |
593 |
{ |
593 |
{ |
594 |
printf(" Listen\n"); |
594 |
printf(" Listen\n"); |
595 |
jtagSetLED(true); |
595 |
jtagSetLED(true); |
596 |
|
596 |
|
597 |
// Set ListenSocket to non-blocking mode |
597 |
// Set ListenSocket to non-blocking mode |
598 |
// We need during waiting for Accept to detect FTDI disconnect |
598 |
// We need during waiting for Accept to detect FTDI disconnect |
599 |
|
599 |
|
600 |
#ifdef WIN32 |
600 |
#ifdef WIN32 |
601 |
u_long iMode = 1; |
601 |
u_long iMode = 1; |
602 |
iResult = ioctlsocket(ListenSocket, FIONBIO, &iMode); |
602 |
iResult = ioctlsocket(ListenSocket, FIONBIO, &iMode); |
603 |
if (iResult != NO_ERROR) |
603 |
if (iResult != NO_ERROR) |
604 |
{ |
604 |
{ |
605 |
fprintf(stderr, "ioctlsocket failed with error: %ld\n", iResult); |
605 |
fprintf(stderr, "ioctlsocket failed with error: %ld\n", iResult); |
606 |
WSACleanup(); |
606 |
WSACleanup(); |
607 |
jtagClosePort(); |
607 |
jtagClosePort(); |
608 |
return -2; |
608 |
return -2; |
609 |
} |
609 |
} |
610 |
#else |
610 |
#else |
611 |
iResult = fcntl(ListenSocket, F_GETFL, 0); |
611 |
iResult = fcntl(ListenSocket, F_GETFL, 0); |
612 |
if (iResult < 0 || fcntl(ListenSocket, F_SETFL, iResult | O_NONBLOCK) < 0) |
612 |
if (iResult < 0 || fcntl(ListenSocket, F_SETFL, iResult | O_NONBLOCK) < 0) |
613 |
{ |
613 |
{ |
614 |
fprintf(stderr, "fcntl failed with error: %d\n", errno); |
614 |
fprintf(stderr, "fcntl failed with error: %d\n", errno); |
615 |
jtagClosePort(); |
615 |
jtagClosePort(); |
616 |
return -2; |
616 |
return -2; |
617 |
} |
617 |
} |
618 |
#endif |
618 |
#endif |
619 |
|
619 |
|
620 |
// Accept a client SOCKET (wait for Accept) |
620 |
// Accept a client SOCKET (wait for Accept) |
621 |
sockaddr ClientSocetAddr; |
621 |
sockaddr ClientSocetAddr; |
622 |
socklen_t ClientSocetAddrLen = sizeof(sockaddr); |
622 |
socklen_t ClientSocetAddrLen = sizeof(sockaddr); |
623 |
do |
623 |
do |
624 |
{ |
624 |
{ |
625 |
// Try Accept (non-blocking) |
625 |
// Try Accept (non-blocking) |
626 |
ClientSocket = accept(ListenSocket, &ClientSocetAddr, &ClientSocetAddrLen); |
626 |
ClientSocket = accept(ListenSocket, &ClientSocetAddr, &ClientSocetAddrLen); |
627 |
if (ClientSocket == INVALID_SOCKET) |
627 |
if (ClientSocket == INVALID_SOCKET) |
628 |
{ |
628 |
{ |
629 |
// Accept Error |
629 |
// Accept Error |
630 |
#ifdef WIN32 |
630 |
#ifdef WIN32 |
631 |
if (WSAGetLastError() != WSAEWOULDBLOCK) |
631 |
if (WSAGetLastError() != WSAEWOULDBLOCK) |
632 |
#else |
632 |
#else |
633 |
if (WSAGetLastError() != EAGAIN && WSAGetLastError() != EWOULDBLOCK) |
633 |
if (WSAGetLastError() != EAGAIN && WSAGetLastError() != EWOULDBLOCK) |
634 |
#endif |
634 |
#endif |
635 |
{ |
635 |
{ |
636 |
fprintf(stderr, "accept failed with error: %d\n", WSAGetLastError()); |
636 |
fprintf(stderr, "accept failed with error: %d\n", WSAGetLastError()); |
637 |
closesocket(ListenSocket); |
637 |
closesocket(ListenSocket); |
638 |
WSACleanup(); |
638 |
WSACleanup(); |
639 |
jtagClosePort(); |
639 |
jtagClosePort(); |
640 |
return -2; |
640 |
return -2; |
641 |
} |
641 |
} |
642 |
// Not yet Accepted |
642 |
// Not yet Accepted |
643 |
{ |
643 |
{ |
644 |
// Check FTDI |
644 |
// Check FTDI |
645 |
if (!CheckCable()) |
645 |
if (!CheckCable()) |
646 |
{ |
646 |
{ |
647 |
fprintf(stderr, "XVC Cable unexpectedly disconnected\n"); |
647 |
fprintf(stderr, "XVC Cable unexpectedly disconnected\n"); |
648 |
closesocket(ListenSocket); |
648 |
closesocket(ListenSocket); |
649 |
WSACleanup(); |
649 |
WSACleanup(); |
650 |
jtagClosePort(); |
650 |
jtagClosePort(); |
651 |
return -2; |
651 |
return -2; |
652 |
} |
652 |
} |
653 |
// Sleep some time (do not eat CPU time for nothong) |
653 |
// Sleep some time (do not eat CPU time for nothong) |
654 |
#ifdef WIN32 |
654 |
#ifdef WIN32 |
655 |
Sleep(100); //ms |
655 |
Sleep(100); //ms |
656 |
#else |
656 |
#else |
657 |
usleep(100000); //us |
657 |
usleep(100000); //us |
658 |
#endif |
658 |
#endif |
659 |
} |
659 |
} |
660 |
} |
660 |
} |
661 |
} |
661 |
} |
662 |
while (ClientSocket == INVALID_SOCKET); |
662 |
while (ClientSocket == INVALID_SOCKET); |
663 |
|
663 |
|
664 |
// Set (Accepted) Socket to blocking mode |
664 |
// Set (Accepted) Socket to blocking mode |
665 |
|
665 |
|
666 |
#ifdef WIN32 |
666 |
#ifdef WIN32 |
667 |
iMode = 0; |
667 |
iMode = 0; |
668 |
iResult = ioctlsocket(ClientSocket, FIONBIO, &iMode); |
668 |
iResult = ioctlsocket(ClientSocket, FIONBIO, &iMode); |
669 |
if (iResult != NO_ERROR) |
669 |
if (iResult != NO_ERROR) |
670 |
{ |
670 |
{ |
671 |
fprintf(stderr, "ioctlsocket failed with error: %ld\n", iResult); |
671 |
fprintf(stderr, "ioctlsocket failed with error: %ld\n", iResult); |
672 |
WSACleanup(); |
672 |
WSACleanup(); |
673 |
jtagClosePort(); |
673 |
jtagClosePort(); |
674 |
return -2; |
674 |
return -2; |
675 |
} |
675 |
} |
676 |
#else |
676 |
#else |
677 |
iResult = fcntl(ListenSocket, F_GETFL, 0); |
677 |
iResult = fcntl(ListenSocket, F_GETFL, 0); |
678 |
if (iResult < 0 || fcntl(ListenSocket, F_SETFL, iResult & ~O_NONBLOCK) < 0) |
678 |
if (iResult < 0 || fcntl(ListenSocket, F_SETFL, iResult & ~O_NONBLOCK) < 0) |
679 |
{ |
679 |
{ |
680 |
fprintf(stderr, "fcntl failed with error: %d\n", errno); |
680 |
fprintf(stderr, "fcntl failed with error: %d\n", errno); |
681 |
jtagClosePort(); |
681 |
jtagClosePort(); |
682 |
return -2; |
682 |
return -2; |
683 |
} |
683 |
} |
684 |
#endif |
684 |
#endif |
685 |
|
685 |
|
686 |
// Print Accepted + Address |
686 |
// Print Accepted + Address |
687 |
printf(" Accepted "); |
687 |
printf(" Accepted "); |
688 |
jtagSetLED(false); |
688 |
jtagSetLED(false); |
689 |
for (int i=2; i<2+4-1; i++) |
689 |
for (int i=2; i<2+4-1; i++) |
690 |
{ |
690 |
{ |
691 |
printf("%d.", (unsigned char)ClientSocetAddr.sa_data[i]); |
691 |
printf("%d.", (unsigned char)ClientSocetAddr.sa_data[i]); |
692 |
} |
692 |
} |
693 |
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]); |
693 |
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]); |
694 |
|
694 |
|
695 |
// Process Data until the peer shuts down the connection |
695 |
// Process Data until the peer shuts down the connection |
696 |
int Cnt = 0; |
696 |
int Cnt = 0; |
697 |
printf(" Handle Data "); |
697 |
printf(" Handle Data "); |
698 |
do |
698 |
do |
699 |
{ |
699 |
{ |
700 |
iResult = handleData(ClientSocket); |
700 |
iResult = handleData(ClientSocket); |
701 |
if (iResult>=0) |
701 |
if (iResult>=0) |
702 |
{ |
702 |
{ |
703 |
printf("."); |
703 |
printf("."); |
704 |
fflush(stdout); |
704 |
fflush(stdout); |
705 |
Cnt++; |
705 |
Cnt++; |
706 |
if (Cnt>40) |
706 |
if (Cnt>40) |
707 |
{ |
707 |
{ |
708 |
Cnt = 0; |
708 |
Cnt = 0; |
709 |
printf("\n "); |
709 |
printf("\n "); |
710 |
} |
710 |
} |
711 |
} |
711 |
} |
712 |
} |
712 |
} |
713 |
while (iResult >= 0); |
713 |
while (iResult >= 0); |
714 |
|
714 |
|
715 |
// Connection Closed by peer |
715 |
// Connection Closed by peer |
716 |
if (iResult==-1) |
716 |
if (iResult==-1) |
717 |
{ |
717 |
{ |
718 |
// JTAG port |
718 |
// JTAG port |
719 |
jtagSetIdle(); |
719 |
jtagSetIdle(); |
720 |
} |
720 |
} |
721 |
|
721 |
|
722 |
// Error - shutdown the connection |
722 |
// Error - shutdown the connection |
723 |
if (iResult==-2) |
723 |
if (iResult==-2) |
724 |
{ |
724 |
{ |
725 |
fprintf(stderr, " Disconnect\n"); |
725 |
fprintf(stderr, " Disconnect\n"); |
726 |
#ifdef WIN32 |
726 |
#ifdef WIN32 |
727 |
iResult = shutdown(ClientSocket, SD_SEND); |
727 |
iResult = shutdown(ClientSocket, SD_SEND); |
728 |
#else |
728 |
#else |
729 |
iResult = shutdown(ClientSocket, SHUT_WR); |
729 |
iResult = shutdown(ClientSocket, SHUT_WR); |
730 |
#endif |
730 |
#endif |
731 |
if (iResult == SOCKET_ERROR) |
731 |
if (iResult == SOCKET_ERROR) |
732 |
{ |
732 |
{ |
733 |
fprintf(stderr, "shutdown failed with error: %d\n", WSAGetLastError()); |
733 |
fprintf(stderr, "shutdown failed with error: %d\n", WSAGetLastError()); |
734 |
} |
734 |
} |
735 |
iResult=-2; // Error |
735 |
iResult=-2; // Error |
736 |
} |
736 |
} |
737 |
|
737 |
|
738 |
// cleanup |
738 |
// cleanup |
739 |
closesocket(ClientSocket); |
739 |
closesocket(ClientSocket); |
740 |
|
740 |
|
741 |
} |
741 |
} |
742 |
// If not Error Listen Again |
742 |
// If not Error Listen Again |
743 |
while (iResult!=-2); |
743 |
while (iResult!=-2); |
744 |
|
744 |
|
745 |
// cleanup |
745 |
// cleanup |
746 |
closesocket(ListenSocket); |
746 |
closesocket(ListenSocket); |
747 |
WSACleanup(); |
747 |
WSACleanup(); |
748 |
jtagClosePort(); |
748 |
jtagClosePort(); |
749 |
|
749 |
|
750 |
return 1; |
750 |
return 1; |
751 |
} |
751 |
} |