1 |
42 |
nyawn |
/* jsp_server.c -- Server for the JTAG serial port
|
2 |
|
|
Copyright(C) 2010 Nathan Yawn <nyawn@opencores.org>
|
3 |
|
|
|
4 |
|
|
This file is part the advanced debug unit / bridge. It acts as a
|
5 |
|
|
telnet server, to send and receive data for the JTAG Serial Port
|
6 |
|
|
(JSP)
|
7 |
|
|
|
8 |
|
|
This program is free software; you can redistribute it and/or modify
|
9 |
|
|
it under the terms of the GNU General Public License as published by
|
10 |
|
|
the Free Software Foundation; either version 2 of the License, or
|
11 |
|
|
(at your option) any later version.
|
12 |
|
|
|
13 |
|
|
This program is distributed in the hope that it will be useful,
|
14 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16 |
|
|
GNU General Public License for more details.
|
17 |
|
|
|
18 |
|
|
You should have received a copy of the GNU General Public License
|
19 |
|
|
along with this program; if not, write to the Free Software
|
20 |
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
21 |
|
|
|
22 |
|
|
|
23 |
|
|
#include <stdio.h>
|
24 |
|
|
#include <sys/unistd.h>
|
25 |
|
|
#include <sys/types.h>
|
26 |
|
|
#include <sys/fcntl.h>
|
27 |
|
|
#include <sys/socket.h>
|
28 |
|
|
#include <arpa/inet.h>
|
29 |
|
|
#include <netdb.h>
|
30 |
|
|
#include <string.h>
|
31 |
|
|
#include <pthread.h>
|
32 |
|
|
#include <errno.h>
|
33 |
|
|
|
34 |
|
|
#include "dbg_api.h"
|
35 |
|
|
#include "hardware_monitor.h"
|
36 |
|
|
#include "errcodes.h"
|
37 |
|
|
|
38 |
|
|
|
39 |
|
|
#define debug(...) // fprintf(stderr, __VA_ARGS__ )
|
40 |
|
|
|
41 |
|
|
int jsp_server_fd = -1;
|
42 |
|
|
int jsp_client_fd = -1;
|
43 |
|
|
int jsp_pipe_fds[2];
|
44 |
|
|
|
45 |
|
|
/* Some convenient net address info to have around */
|
46 |
|
|
char jsp_ipstr[INET6_ADDRSTRLEN];
|
47 |
|
|
char *jsp_ipver;
|
48 |
|
|
int jsp_portnum;
|
49 |
|
|
char jsp_hostname[256];
|
50 |
|
|
|
51 |
|
|
/* Buffers for network data. Simple, static char arrays. */
|
52 |
|
|
#define JSP_BUFFER_SIZE 256
|
53 |
|
|
char jsp_tohw_buf[JSP_BUFFER_SIZE];
|
54 |
|
|
int jsp_tohw_rd_idx = 0;
|
55 |
|
|
int jsp_tohw_wr_idx = 0;
|
56 |
|
|
int jsp_tohw_count = 0;
|
57 |
|
|
|
58 |
|
|
char jsp_fromhw_buf[JSP_BUFFER_SIZE];
|
59 |
|
|
int jsp_fromhw_rd_idx = 0;
|
60 |
|
|
int jsp_fromhw_wr_idx = 0;
|
61 |
|
|
int jsp_fromhw_count = 0;
|
62 |
|
|
|
63 |
|
|
/* Other local data */
|
64 |
|
|
int jsp_server_running = 0;
|
65 |
|
|
int jsp_target_is_running = 0;
|
66 |
|
|
|
67 |
|
|
pthread_t jsp_server_thread;
|
68 |
|
|
void *jsp_server(void *arg);
|
69 |
|
|
|
70 |
|
|
void jsp_server_close(void);
|
71 |
|
|
void jsp_client_close(void);
|
72 |
|
|
|
73 |
|
|
void jsp_print_welcome(int fd);
|
74 |
|
|
void jsp_queue_data_from_client(int fd);
|
75 |
|
|
void jsp_send_data_to_client(int fd);
|
76 |
|
|
void jsp_hardware_transact(void);
|
77 |
|
|
void jsp_send_all(int fd, char *buf, int len);
|
78 |
|
|
|
79 |
|
|
/*----------------------------------------------------------*/
|
80 |
|
|
/* Public API */
|
81 |
|
|
/*----------------------------------------------------------*/
|
82 |
|
|
|
83 |
|
|
void jsp_init(int portNum)
|
84 |
|
|
{
|
85 |
|
|
int status;
|
86 |
|
|
struct addrinfo hints;
|
87 |
|
|
struct addrinfo *servinfo; // will point to the results of getaddrinfo
|
88 |
|
|
int optval; /* Socket options */
|
89 |
|
|
char portnum[6]; /* portNum as a string */
|
90 |
|
|
void *addr;
|
91 |
|
|
|
92 |
|
|
debug("JSP Server initializing\n");
|
93 |
|
|
|
94 |
|
|
jsp_server_fd = -1;
|
95 |
|
|
jsp_client_fd = -1;
|
96 |
|
|
jsp_portnum = portNum;
|
97 |
|
|
|
98 |
|
|
memset(portnum, '\0', sizeof(portnum));
|
99 |
|
|
snprintf(portnum, 5, "%i", portNum);
|
100 |
|
|
|
101 |
|
|
/* Get the address info for the local host */
|
102 |
|
|
memset(&hints, 0, sizeof hints); // make sure the struct is empty
|
103 |
|
|
hints.ai_family = AF_UNSPEC; // don't care IPv4 or IPv6
|
104 |
|
|
hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
|
105 |
|
|
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
|
106 |
|
|
|
107 |
|
|
if ((status = getaddrinfo(NULL, portnum, &hints, &servinfo)) != 0) {
|
108 |
|
|
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
|
109 |
|
|
return;
|
110 |
|
|
}
|
111 |
|
|
|
112 |
|
|
|
113 |
|
|
/* *** TODO: Select the appropriate servinfo in the linked list
|
114 |
|
|
* For now, we just use the first entry in servinfo.
|
115 |
|
|
struct addrinfo *servinfo, *p;
|
116 |
|
|
for(p = servinfo;p != NULL; p = p->ai_next) {
|
117 |
|
|
if (p->ai_family == AF_INET) { // IPv4
|
118 |
|
|
} else { // IPv6
|
119 |
|
|
}
|
120 |
|
|
}
|
121 |
|
|
*/
|
122 |
|
|
|
123 |
|
|
|
124 |
|
|
/* Save the IP address, for convenience (different fields in IPv4 and IPv6) */
|
125 |
|
|
if (servinfo->ai_family == AF_INET) { // IPv4
|
126 |
|
|
struct sockaddr_in *ipv4 = (struct sockaddr_in *)servinfo->ai_addr;
|
127 |
|
|
addr = &(ipv4->sin_addr);
|
128 |
|
|
jsp_ipver = "IPv4";
|
129 |
|
|
} else { // IPv6
|
130 |
|
|
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)servinfo->ai_addr;
|
131 |
|
|
addr = &(ipv6->sin6_addr);
|
132 |
|
|
jsp_ipver = "IPv6";
|
133 |
|
|
}
|
134 |
|
|
|
135 |
|
|
/* convert the IP to a string */
|
136 |
|
|
inet_ntop(servinfo->ai_family, addr, jsp_ipstr, sizeof(jsp_ipstr));
|
137 |
|
|
|
138 |
|
|
/* Find out what our name is, save for convenience */
|
139 |
|
|
if (gethostname (jsp_hostname, sizeof(jsp_hostname)) < 0)
|
140 |
|
|
{
|
141 |
|
|
fprintf (stderr, "Warning: Unable to get hostname for JSP server: %s\n", strerror(errno));
|
142 |
|
|
jsp_hostname[0] = '\0'; /* This is not a fatal error. */
|
143 |
|
|
}
|
144 |
|
|
|
145 |
|
|
/* Create the socket */
|
146 |
|
|
jsp_server_fd = socket (servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
|
147 |
|
|
if (jsp_server_fd < 0)
|
148 |
|
|
{
|
149 |
|
|
fprintf (stderr, "Error: JSP could not create server socket: %s\n", strerror(errno));
|
150 |
|
|
return;
|
151 |
|
|
}
|
152 |
|
|
|
153 |
|
|
/* Set this socket to reuse its address. */
|
154 |
|
|
optval = 1;
|
155 |
|
|
if (setsockopt(jsp_server_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval)) == -1)
|
156 |
|
|
{
|
157 |
|
|
fprintf (stderr, "Cannot set SO_REUSEADDR option on server socket %d: %s\n", jsp_server_fd, strerror(errno));
|
158 |
|
|
jsp_server_close();
|
159 |
|
|
return;
|
160 |
|
|
}
|
161 |
|
|
|
162 |
|
|
/* Bind the socket to the local address */
|
163 |
|
|
if (bind (jsp_server_fd, servinfo->ai_addr, servinfo->ai_addrlen) < 0)
|
164 |
|
|
{
|
165 |
|
|
fprintf (stderr, "Error: Unable to bind JSP server socket %d to port %d: %s\n", jsp_server_fd, portNum, strerror(errno));
|
166 |
|
|
jsp_server_close();
|
167 |
|
|
return;
|
168 |
|
|
}
|
169 |
|
|
|
170 |
|
|
/* Set us up as a server, with a maximum backlog of 1 connection */
|
171 |
|
|
if (listen (jsp_server_fd, 1) < 0)
|
172 |
|
|
{
|
173 |
|
|
fprintf (stderr, "Warning: Unable to set JSP backlog on server socket %d to %d: %s\n", jsp_server_fd, 1, strerror(errno));
|
174 |
|
|
jsp_server_close();
|
175 |
|
|
return;
|
176 |
|
|
}
|
177 |
|
|
|
178 |
|
|
fprintf(stderr, "JSP server listening on host %s (%s), port %i, address family %s\n",
|
179 |
|
|
jsp_hostname, jsp_ipstr, jsp_portnum, jsp_ipver);
|
180 |
|
|
|
181 |
|
|
/* Register for stall/unstall events from the target monitor thread. Also creates pipe
|
182 |
|
|
* for sending stall/unstall command to the target monitor, unused by us. */
|
183 |
|
|
if(0 > register_with_monitor_thread(jsp_pipe_fds)) { // pipe_fds[0] is for writing to monitor, [1] is to read from it
|
184 |
|
|
fprintf(stderr, "JSP server failed to register with monitor thread, exiting");
|
185 |
|
|
jsp_server_close();
|
186 |
|
|
return;
|
187 |
|
|
}
|
188 |
|
|
|
189 |
|
|
}
|
190 |
|
|
|
191 |
|
|
|
192 |
|
|
int jsp_server_start(void)
|
193 |
|
|
{
|
194 |
|
|
|
195 |
|
|
jsp_server_running = 1;
|
196 |
|
|
|
197 |
|
|
debug("Starting JSP server\n");
|
198 |
|
|
|
199 |
|
|
// Create the JSP server thread
|
200 |
|
|
if(pthread_create(&jsp_server_thread, NULL, jsp_server, NULL))
|
201 |
|
|
{
|
202 |
|
|
fprintf(stderr, "Failed to create JSP server thread!\n");
|
203 |
|
|
return 0;
|
204 |
|
|
}
|
205 |
|
|
|
206 |
|
|
return 1;
|
207 |
|
|
}
|
208 |
|
|
|
209 |
|
|
|
210 |
|
|
int jsp_server_stop(void)
|
211 |
|
|
{
|
212 |
|
|
/*** NOTE: Since we currently don't use select() in front of the accept()
|
213 |
|
|
*** in the server thread, this won't actually work unless/until a client
|
214 |
|
|
*** is connected. Otherwise, the server thread will be blocked on the
|
215 |
|
|
*** accept() (though closing the server socket may break it out.)
|
216 |
|
|
***/
|
217 |
|
|
|
218 |
|
|
jsp_server_running = 0;
|
219 |
|
|
jsp_server_close();
|
220 |
|
|
return 1;
|
221 |
|
|
}
|
222 |
|
|
|
223 |
|
|
/*--------------------------------------------------------------------*/
|
224 |
|
|
/* Main server thread */
|
225 |
|
|
/*--------------------------------------------------------------------*/
|
226 |
|
|
|
227 |
|
|
|
228 |
|
|
void *jsp_server(void *arg)
|
229 |
|
|
{
|
230 |
|
|
struct sockaddr_storage their_addr;
|
231 |
|
|
struct timeval tv, *tvp;
|
232 |
45 |
nyawn |
fd_set readset;
|
233 |
42 |
nyawn |
int addr_size;
|
234 |
|
|
int nfds, flags;
|
235 |
|
|
int ret;
|
236 |
|
|
char cmd;
|
237 |
|
|
|
238 |
|
|
fprintf(stderr, "JSP server thread running!\n");
|
239 |
|
|
|
240 |
|
|
while(jsp_server_running)
|
241 |
|
|
{
|
242 |
|
|
/* Listen for an incoming connection */
|
243 |
|
|
addr_size = sizeof their_addr;
|
244 |
|
|
jsp_client_fd = accept(jsp_server_fd, (struct sockaddr *)&their_addr, &addr_size);
|
245 |
|
|
|
246 |
|
|
if(jsp_client_fd == -1)
|
247 |
|
|
{
|
248 |
|
|
perror("Error in accept() in JSP server thread");
|
249 |
|
|
}
|
250 |
|
|
else
|
251 |
|
|
{
|
252 |
|
|
debug("JSP server got connection!\n");
|
253 |
|
|
|
254 |
|
|
// Clear the in/out buffers
|
255 |
|
|
jsp_tohw_rd_idx = 0;
|
256 |
|
|
jsp_tohw_wr_idx = 0;
|
257 |
|
|
jsp_tohw_count = 0;
|
258 |
|
|
jsp_fromhw_rd_idx = 0;
|
259 |
|
|
jsp_fromhw_wr_idx = 0;
|
260 |
|
|
jsp_fromhw_count = 0;
|
261 |
|
|
|
262 |
|
|
/* New client should be non-blocking. */
|
263 |
|
|
flags = fcntl (jsp_client_fd, F_GETFL);
|
264 |
|
|
if (flags < 0)
|
265 |
|
|
{
|
266 |
|
|
fprintf (stderr, "Warning: Unable to get flags for JSP client socket %d: %s\n", jsp_client_fd, strerror(errno));
|
267 |
|
|
// Not really fatal.
|
268 |
|
|
}
|
269 |
|
|
else {
|
270 |
|
|
flags |= O_NONBLOCK;
|
271 |
|
|
if (fcntl (jsp_client_fd, F_SETFL, flags) < 0)
|
272 |
|
|
{
|
273 |
|
|
fprintf (stderr, "Warning: Unable to set flags for JSP client socket %d to 0x%08x: %s\n", jsp_client_fd, flags, strerror(errno));
|
274 |
|
|
// Also not really fatal.
|
275 |
|
|
}
|
276 |
|
|
}
|
277 |
|
|
|
278 |
|
|
jsp_print_welcome(jsp_client_fd);
|
279 |
|
|
}
|
280 |
|
|
|
281 |
|
|
/* Send/receive data on the new connection for as long as it's valid */
|
282 |
|
|
while(jsp_server_running && (jsp_client_fd != -1))
|
283 |
|
|
{
|
284 |
|
|
/* if target not running, block on data from client or monitor thread */
|
285 |
|
|
/* if target running, just poll (don't block */
|
286 |
|
|
if(jsp_target_is_running) {
|
287 |
|
|
tv.tv_sec = 0; // Set this each loop, it may be changed by the select() call
|
288 |
|
|
tv.tv_usec = 0; // instant timeout when polling
|
289 |
|
|
tvp = &tv;
|
290 |
|
|
} else {
|
291 |
|
|
tvp = NULL;
|
292 |
|
|
}
|
293 |
|
|
|
294 |
|
|
FD_ZERO(&readset);
|
295 |
|
|
FD_SET(jsp_client_fd, &readset);
|
296 |
|
|
FD_SET(jsp_pipe_fds[1], &readset);
|
297 |
|
|
nfds = jsp_client_fd;
|
298 |
|
|
if(jsp_pipe_fds[1] > nfds) nfds = jsp_pipe_fds[1];
|
299 |
|
|
nfds++;
|
300 |
|
|
|
301 |
|
|
ret = select(nfds, &readset, NULL, NULL, tvp);
|
302 |
|
|
|
303 |
|
|
if(ret == -1) // error
|
304 |
|
|
{
|
305 |
|
|
perror("select()");
|
306 |
|
|
}
|
307 |
|
|
else if(ret != 0) // fd ready (ret == 0 on timeout)
|
308 |
|
|
{
|
309 |
|
|
debug("JSP thread got data\n");
|
310 |
|
|
|
311 |
|
|
if(FD_ISSET(jsp_pipe_fds[1], &readset))
|
312 |
|
|
{
|
313 |
|
|
ret = read(jsp_pipe_fds[1], &cmd, 1);
|
314 |
|
|
debug("JSP server got monitor status \'%c\' (0x%X)\n", cmd, cmd);
|
315 |
|
|
if(ret == 1)
|
316 |
|
|
{
|
317 |
|
|
if(cmd == 'H')
|
318 |
|
|
{
|
319 |
|
|
jsp_target_is_running = 0;
|
320 |
|
|
}
|
321 |
|
|
else if(cmd == 'R')
|
322 |
|
|
{
|
323 |
|
|
jsp_target_is_running = 1;
|
324 |
|
|
}
|
325 |
|
|
else
|
326 |
|
|
{
|
327 |
|
|
fprintf(stderr, "JSP server got unknown monitor status \'%c\' (0x%X)\n", cmd, cmd);
|
328 |
|
|
}
|
329 |
|
|
}
|
330 |
|
|
else
|
331 |
|
|
{
|
332 |
|
|
fprintf(stderr, "JSP server failed to read from ready monitor pipe!\n");
|
333 |
|
|
}
|
334 |
|
|
} // if FD_ISSET(jsp_pipe_fds[1])
|
335 |
|
|
|
336 |
|
|
if(FD_ISSET(jsp_client_fd, &readset))
|
337 |
|
|
{
|
338 |
|
|
jsp_queue_data_from_client(jsp_client_fd);
|
339 |
|
|
}
|
340 |
|
|
} // else if (ret != 0)
|
341 |
|
|
|
342 |
|
|
|
343 |
|
|
/* Send any buffered output data to the client */
|
344 |
|
|
jsp_send_data_to_client(jsp_client_fd);
|
345 |
|
|
|
346 |
|
|
/* If target running, transact with the JSP to send/receive buffered data */
|
347 |
|
|
if(jsp_target_is_running)
|
348 |
|
|
{
|
349 |
|
|
jsp_hardware_transact();
|
350 |
|
|
}
|
351 |
|
|
|
352 |
|
|
} /* while client connection is valid */
|
353 |
|
|
|
354 |
|
|
} /* while(jsp_server_running) */
|
355 |
|
|
|
356 |
|
|
jsp_client_close();
|
357 |
|
|
|
358 |
|
|
return arg; // unused
|
359 |
|
|
}
|
360 |
|
|
|
361 |
|
|
/*--------------------------------------------------------------------*/
|
362 |
|
|
/* Helper functions */
|
363 |
|
|
/*--------------------------------------------------------------------*/
|
364 |
|
|
|
365 |
|
|
void jsp_server_close(void)
|
366 |
|
|
{
|
367 |
|
|
if (jsp_server_fd != -1)
|
368 |
|
|
{
|
369 |
|
|
close(jsp_server_fd);
|
370 |
|
|
jsp_server_fd = -1;
|
371 |
|
|
}
|
372 |
|
|
}
|
373 |
|
|
|
374 |
|
|
|
375 |
|
|
void jsp_client_close(void)
|
376 |
|
|
{
|
377 |
|
|
if (jsp_client_fd != -1)
|
378 |
|
|
{
|
379 |
|
|
close (jsp_client_fd);
|
380 |
|
|
jsp_client_fd = -1;
|
381 |
|
|
}
|
382 |
|
|
} /* jsp_client_close () */
|
383 |
|
|
|
384 |
|
|
|
385 |
|
|
void jsp_print_welcome(int fd)
|
386 |
|
|
{
|
387 |
|
|
char msg[] = "Advanced Debug System JTAG Serial Port Server\n\r";
|
388 |
|
|
char msg2[] = " (";
|
389 |
|
|
char msg3[] = "), port ";
|
390 |
|
|
char portnum[24];
|
391 |
|
|
|
392 |
|
|
jsp_send_all(fd, msg, sizeof(msg));
|
393 |
|
|
jsp_send_all(fd, jsp_hostname, strlen(jsp_hostname));
|
394 |
|
|
jsp_send_all(fd, msg2, sizeof(msg2));
|
395 |
|
|
jsp_send_all(fd, jsp_ipstr, strlen(jsp_ipstr));
|
396 |
|
|
jsp_send_all(fd, msg3, sizeof(msg3));
|
397 |
|
|
|
398 |
|
|
memset(portnum, '\0', sizeof(portnum));
|
399 |
|
|
snprintf(portnum, 23, "%i\n\n\r", jsp_portnum);
|
400 |
|
|
jsp_send_all(fd, portnum, strlen(portnum));
|
401 |
|
|
}
|
402 |
|
|
|
403 |
|
|
|
404 |
|
|
void jsp_queue_data_from_client(int fd)
|
405 |
|
|
{
|
406 |
|
|
int space_available;
|
407 |
|
|
int bytes_received;
|
408 |
|
|
|
409 |
|
|
debug("JSP queueing data from client; Tohw count now %i\n", jsp_tohw_count);
|
410 |
|
|
|
411 |
|
|
// First, try to fill from the write index to the end of the array, or the read index, whichever is less
|
412 |
|
|
// This keeps the buffer that recv() writes to linear
|
413 |
|
|
space_available = JSP_BUFFER_SIZE - jsp_tohw_wr_idx;
|
414 |
|
|
if(space_available > (JSP_BUFFER_SIZE - jsp_tohw_count))
|
415 |
|
|
space_available = JSP_BUFFER_SIZE - jsp_tohw_count;
|
416 |
|
|
|
417 |
|
|
bytes_received = recv(fd, &jsp_tohw_buf[jsp_tohw_wr_idx], space_available, 0);
|
418 |
|
|
if(bytes_received < 0)
|
419 |
|
|
{
|
420 |
|
|
perror("JSP client socket read failed");
|
421 |
|
|
return;
|
422 |
|
|
}
|
423 |
|
|
else if(bytes_received > 0)
|
424 |
|
|
{
|
425 |
|
|
jsp_tohw_wr_idx = (jsp_tohw_wr_idx + bytes_received) % JSP_BUFFER_SIZE; // modulo will only happen if wrapping to 0
|
426 |
|
|
jsp_tohw_count += bytes_received;
|
427 |
|
|
}
|
428 |
|
|
|
429 |
|
|
// Now, do the same thing again, potentially filling the buffer from index 0 to the read index
|
430 |
|
|
space_available = JSP_BUFFER_SIZE - jsp_tohw_wr_idx;
|
431 |
|
|
if(space_available > (JSP_BUFFER_SIZE - jsp_tohw_count))
|
432 |
|
|
space_available = JSP_BUFFER_SIZE - jsp_tohw_count;
|
433 |
|
|
|
434 |
|
|
bytes_received = recv(fd, &jsp_tohw_buf[jsp_tohw_wr_idx], space_available, 0);
|
435 |
|
|
if(bytes_received < 0)
|
436 |
|
|
{
|
437 |
|
|
if(errno != EAGAIN) {
|
438 |
|
|
perror("JSP client socket read failed");
|
439 |
|
|
} else {
|
440 |
|
|
debug("Second JSP client socket read got EAGAIN.\n");
|
441 |
|
|
}
|
442 |
|
|
return;
|
443 |
|
|
}
|
444 |
|
|
else if(bytes_received > 0)
|
445 |
|
|
{
|
446 |
|
|
jsp_tohw_wr_idx = (jsp_tohw_wr_idx + bytes_received) % JSP_BUFFER_SIZE; // modulo will only happen if wrapping to 0
|
447 |
|
|
jsp_tohw_count += bytes_received;
|
448 |
|
|
}
|
449 |
|
|
|
450 |
|
|
debug("JSP queued data from client; Tohw count now %i\n", jsp_tohw_count);
|
451 |
|
|
}
|
452 |
|
|
|
453 |
|
|
void jsp_send_data_to_client(int fd)
|
454 |
|
|
{
|
455 |
|
|
int bytes_written;
|
456 |
|
|
int bytes_available;
|
457 |
|
|
|
458 |
|
|
// *** TODO: use sendvec()
|
459 |
|
|
debug("JSP will send data to client. Fromhw count now %i\n", jsp_fromhw_count);
|
460 |
|
|
|
461 |
|
|
if(jsp_fromhw_count > 0)
|
462 |
|
|
{
|
463 |
|
|
bytes_available = jsp_fromhw_count;
|
464 |
|
|
if(bytes_available > (JSP_BUFFER_SIZE - jsp_fromhw_rd_idx))
|
465 |
|
|
bytes_available = JSP_BUFFER_SIZE - jsp_fromhw_rd_idx;
|
466 |
|
|
|
467 |
|
|
bytes_written = send(fd, &jsp_fromhw_buf[jsp_fromhw_rd_idx], bytes_available, 0);
|
468 |
|
|
if(bytes_written < 0)
|
469 |
|
|
{
|
470 |
|
|
perror("JSP server failed client socket write");
|
471 |
|
|
}
|
472 |
|
|
else
|
473 |
|
|
{
|
474 |
|
|
jsp_fromhw_count -= bytes_written;
|
475 |
|
|
jsp_fromhw_rd_idx = (jsp_fromhw_rd_idx + bytes_written) % JSP_BUFFER_SIZE;
|
476 |
|
|
}
|
477 |
|
|
}
|
478 |
|
|
|
479 |
|
|
// Now do it again, in case of buffer wraparound
|
480 |
|
|
if(jsp_fromhw_count > 0)
|
481 |
|
|
{
|
482 |
|
|
bytes_available = jsp_fromhw_count;
|
483 |
|
|
if(bytes_available > (JSP_BUFFER_SIZE - jsp_fromhw_rd_idx))
|
484 |
|
|
bytes_available = JSP_BUFFER_SIZE - jsp_fromhw_rd_idx;
|
485 |
|
|
|
486 |
|
|
bytes_written = send(fd, &jsp_fromhw_buf[jsp_fromhw_rd_idx], bytes_available, 0);
|
487 |
|
|
if(bytes_written < 0)
|
488 |
|
|
{
|
489 |
|
|
perror("JSP server failed client socket write");
|
490 |
|
|
}
|
491 |
|
|
else
|
492 |
|
|
{
|
493 |
|
|
jsp_fromhw_count -= bytes_written;
|
494 |
|
|
jsp_fromhw_rd_idx = (jsp_fromhw_rd_idx + bytes_written) % JSP_BUFFER_SIZE;
|
495 |
|
|
}
|
496 |
|
|
}
|
497 |
|
|
|
498 |
|
|
debug("JSP sent data to client. Fromhw count now %i\n", jsp_fromhw_count);
|
499 |
|
|
}
|
500 |
|
|
|
501 |
|
|
|
502 |
|
|
void jsp_hardware_transact(void)
|
503 |
|
|
{
|
504 |
|
|
int bytes_to_send;
|
505 |
|
|
int bytes_received = 8; // can receive up to 8 bytes
|
506 |
|
|
char sendbuf[8];
|
507 |
|
|
char rcvbuf[8];
|
508 |
|
|
int i,j;
|
509 |
|
|
int ret;
|
510 |
|
|
|
511 |
|
|
debug("JSP about to transact; Tohw buf size now %i, fromhw buf size %i\n", jsp_tohw_count, jsp_fromhw_count);
|
512 |
|
|
|
513 |
|
|
// Get data to send, if any
|
514 |
|
|
bytes_to_send = jsp_tohw_count;
|
515 |
|
|
if(bytes_to_send > 8) bytes_to_send = 8;
|
516 |
|
|
|
517 |
|
|
j = jsp_tohw_rd_idx;
|
518 |
|
|
for(i = 0; i < bytes_to_send; i++)
|
519 |
|
|
{
|
520 |
|
|
sendbuf[i] = jsp_tohw_buf[j];
|
521 |
|
|
j = (j+1) % JSP_BUFFER_SIZE;
|
522 |
|
|
}
|
523 |
|
|
|
524 |
|
|
// Do the transaction
|
525 |
|
|
ret = dbg_serial_sndrcv(&bytes_to_send, sendbuf, &bytes_received, rcvbuf);
|
526 |
|
|
if(ret != APP_ERR_NONE)
|
527 |
|
|
{
|
528 |
|
|
fprintf(stderr, "Error in JSP transaction: %s\n", get_err_string(ret));
|
529 |
|
|
}
|
530 |
|
|
else
|
531 |
|
|
{
|
532 |
|
|
debug("Transacted, bytes sent = %i, received = %i\n", bytes_to_send, bytes_received);
|
533 |
|
|
|
534 |
|
|
// Adjust send buffer pointers as necessary - we may not have sent all 8 bytes
|
535 |
|
|
jsp_tohw_count -= bytes_to_send;
|
536 |
|
|
jsp_tohw_rd_idx = (jsp_tohw_rd_idx + bytes_to_send) % JSP_BUFFER_SIZE;
|
537 |
|
|
|
538 |
|
|
// Queue data received, if any, and adjust the pointers
|
539 |
|
|
for(i = 0; i < bytes_received; i++)
|
540 |
|
|
{
|
541 |
|
|
jsp_fromhw_buf[jsp_fromhw_wr_idx] = rcvbuf[i];
|
542 |
|
|
jsp_fromhw_wr_idx = (jsp_fromhw_wr_idx + 1) % JSP_BUFFER_SIZE;
|
543 |
|
|
jsp_fromhw_count++;
|
544 |
|
|
}
|
545 |
|
|
|
546 |
|
|
debug("JSP transacted; Tohw buf size now %i, fromhw buf size %i\n", jsp_tohw_count, jsp_fromhw_count);
|
547 |
|
|
}
|
548 |
|
|
}
|
549 |
|
|
|
550 |
|
|
void jsp_send_all(int fd, char *buf, int len)
|
551 |
|
|
{
|
552 |
|
|
int total_sent = 0;
|
553 |
|
|
int bytes_sent;
|
554 |
|
|
|
555 |
|
|
while(total_sent < len)
|
556 |
|
|
{
|
557 |
|
|
bytes_sent = send(fd, buf, len, 0);
|
558 |
|
|
if(bytes_sent < 0)
|
559 |
|
|
{
|
560 |
|
|
perror("JSP server socket send failed");
|
561 |
|
|
break;
|
562 |
|
|
}
|
563 |
|
|
total_sent += bytes_sent;
|
564 |
|
|
}
|
565 |
|
|
}
|