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 42

Go to most recent revision | 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
 
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
  struct fd_set  readset;
233
  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
}

powered by: WebSVN 2.1.0

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