OpenCores
URL https://opencores.org/ocsvn/adv_debug_sys/adv_debug_sys/trunk

Subversion Repositories adv_debug_sys

[/] [adv_debug_sys/] [trunk/] [Software/] [adv_jtag_bridge/] [jsp_server.c] - Blame information for rev 51

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.