Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 65 | f9daq | 1 | /************************************************************************** |
| 2 | lecroy_tcp.c |
||
| 3 | Version 1.00 |
||
| 4 | Copyright (C) 2003 Steve D. Sharples |
||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or |
||
| 7 | modify it under the terms of the GNU General Public License |
||
| 8 | as published by the Free Software Foundation; either version 2 |
||
| 9 | of the License, or (at your option) any later version. |
||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, |
||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
| 14 | GNU General Public License for more details. |
||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License |
||
| 17 | along with this program; if not, write to the Free Software |
||
| 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||
| 19 | |||
| 20 | The author's email address is steve.sharples@nottingham.ac.uk |
||
| 21 | |||
| 22 | *************************************************************************** |
||
| 23 | |||
| 24 | Libraries for communicating with a LeCroy scope (and perhaps other things) |
||
| 25 | via TCP/IP. Based on "net_con.cpp" by LeCroy, also using bits of code from |
||
| 26 | an ariticle in October 2001 issue of "Linux Magazine" see: |
||
| 27 | http://www.linux-mag.com/2001-10/compile_01.html |
||
| 28 | |||
| 29 | The original "net_con.cpp" code was Copyright 1998 LeCroy Corporation, and |
||
| 30 | written by Ricardo Palacio. This code was passed on to me (Steve |
||
| 31 | Sharples) by LeCroy so that I could write drivers to communicate with my |
||
| 32 | new LT584L DSO from my Linux machine. LeCroy corporation have agreed to |
||
| 33 | allow the release of the UNIX/Linux code (since it is based on their code) |
||
| 34 | under the GNU General Public License in the hope that it will be useful |
||
| 35 | to others. THEY (LECROY) OBVIOUSLY CANNOT SUPPORT THIS CODE, although if |
||
| 36 | I were them I'd be starting to think seriously about supporting the Linux/ |
||
| 37 | UNIX architectures. |
||
| 38 | |||
| 39 | See "lecroy_tcp.h" for additional comments and usage |
||
| 40 | |||
| 41 | **************************************************************************/ |
||
| 42 | // modified for LabWindows CVI by Samo 23. 5. 2013 |
||
| 43 | |||
| 44 | #include <ansi_c.h> |
||
| 45 | #include <stdlib.h> |
||
| 46 | #include <winsock2.h> |
||
| 47 | #include "lecroy_tcp.h" |
||
| 48 | |||
| 49 | //#define DEBUG |
||
| 50 | |||
| 51 | static WSADATA WSA_data; |
||
| 52 | static BOOL LECROY_TCP_connected_flag = FALSE; |
||
| 53 | |||
| 54 | typedef struct { /* defines LeCroy VICP protocol (TCP header) */ |
||
| 55 | unsigned char bEOI_Flag; |
||
| 56 | unsigned char reserved[3]; |
||
| 57 | int iLength; |
||
| 58 | } LECROY_TCP_HEADER; |
||
| 59 | |||
| 60 | int LECROY_TCP_write(int sockfd, char *buf) { |
||
| 61 | |||
| 62 | LECROY_TCP_HEADER header; |
||
| 63 | int result, bytes_more, bytes_xferd,tmp; |
||
| 64 | char *idxPtr; |
||
| 65 | |||
| 66 | BOOL eoi_flag = TRUE; |
||
| 67 | int len = strlen(buf); |
||
| 68 | |||
| 69 | if (LECROY_TCP_connected_flag != TRUE) return -1; |
||
| 70 | #ifdef DEBUG |
||
| 71 | printf("Sending %s\n",buf); |
||
| 72 | #endif |
||
| 73 | /* set the header info */ |
||
| 74 | header.bEOI_Flag = LECROY_DATA_FLAG; |
||
| 75 | /* following line retained because the original "write" function |
||
| 76 | contained an extra argument of eoi_flag, which I've set to |
||
| 77 | be always TRUE */ |
||
| 78 | header.bEOI_Flag |= (eoi_flag)? LECROY_EOI_FLAG:0; |
||
| 79 | header.reserved[0] = 1; /* see LeCroy documentation about these */ |
||
| 80 | header.reserved[1] = 0; |
||
| 81 | header.reserved[2] = 0; |
||
| 82 | header.iLength = htonl(len); |
||
| 83 | |||
| 84 | |||
| 85 | /* write the header first */ |
||
| 86 | //tmp=write(sockfd, (char *) &header, sizeof(LECROY_TCP_HEADER)); |
||
| 87 | tmp=send(sockfd, (char *) &header, sizeof(LECROY_TCP_HEADER),0); |
||
| 88 | if (tmp!=sizeof(LECROY_TCP_HEADER)) { |
||
| 89 | printf("Could not write the header successfully, returned: %d\n",tmp); |
||
| 90 | return -1; |
||
| 91 | } |
||
| 92 | |||
| 93 | bytes_more = len; |
||
| 94 | idxPtr = buf; |
||
| 95 | bytes_xferd = 0; |
||
| 96 | while (1) { |
||
| 97 | /* then write the rest of the block */ |
||
| 98 | idxPtr = buf + bytes_xferd; |
||
| 99 | //result=write (sockfd, (char *) idxPtr, bytes_more); |
||
| 100 | result=send (sockfd, (char *) idxPtr, bytes_more,0); |
||
| 101 | if (result<0) { |
||
| 102 | printf("Could not write the rest of the block successfully, returned: %d\n",tmp); |
||
| 103 | return -1; |
||
| 104 | } |
||
| 105 | bytes_xferd += result; |
||
| 106 | bytes_more -= result; |
||
| 107 | if (bytes_more <= 0) break; |
||
| 108 | } |
||
| 109 | return 0; |
||
| 110 | } |
||
| 111 | |||
| 112 | int LECROY_TCP_read(int sockfd, char *buf, int len, int allowable_time) { |
||
| 113 | |||
| 114 | LECROY_TCP_HEADER header; |
||
| 115 | char tmpStr[512]; |
||
| 116 | int result, accum, space_left, bytes_more, buf_count; |
||
| 117 | char *idxPtr; |
||
| 118 | |||
| 119 | fd_set rfds; |
||
| 120 | struct timeval tval; |
||
| 121 | |||
| 122 | tval.tv_sec = allowable_time; |
||
| 123 | tval.tv_usec = 0; |
||
| 124 | |||
| 125 | if (LECROY_TCP_connected_flag != TRUE) return -1; |
||
| 126 | FD_ZERO(&rfds); |
||
| 127 | FD_SET(sockfd, &rfds); |
||
| 128 | |||
| 129 | if (buf==NULL) return -1; |
||
| 130 | |||
| 131 | memset(buf, 0, len); |
||
| 132 | buf_count = 0; |
||
| 133 | space_left = len; |
||
| 134 | |||
| 135 | while (1) { |
||
| 136 | /* block here until data is received of timeout expires */ |
||
| 137 | result = select((sockfd+1), &rfds, NULL, NULL, &tval); |
||
| 138 | if (result < 0) { |
||
| 139 | LECROY_TCP_disconnect(sockfd); |
||
| 140 | printf("Read timeout\n"); |
||
| 141 | return -1; |
||
| 142 | } |
||
| 143 | /* get the header info first */ |
||
| 144 | accum = 0; |
||
| 145 | while (1) { |
||
| 146 | memset(&header, 0, sizeof(LECROY_TCP_HEADER)); |
||
| 147 | |||
| 148 | if ((result = recv(sockfd, (char *) &header + accum, sizeof(header) - accum, 0)) < 0) { |
||
| 149 | LECROY_TCP_disconnect(sockfd); |
||
| 150 | printf("Unable to receive header info from the server.\n"); |
||
| 151 | return -1; |
||
| 152 | } |
||
| 153 | accum += result; |
||
| 154 | if (accum>=sizeof(header)) break; |
||
| 155 | } |
||
| 156 | |||
| 157 | header.iLength = ntohl(header.iLength); |
||
| 158 | if (header.iLength < 1) return 0; |
||
| 159 | |||
| 160 | /* only read to len amount */ |
||
| 161 | if (header.iLength > space_left) { |
||
| 162 | header.iLength = space_left; |
||
| 163 | sprintf(tmpStr, "Read buffer size (%d bytes) is too small\n", len); |
||
| 164 | printf(tmpStr); |
||
| 165 | } |
||
| 166 | |||
| 167 | /* read the rest of the block */ |
||
| 168 | accum = 0; |
||
| 169 | while (1) { |
||
| 170 | idxPtr = buf + (buf_count + accum); |
||
| 171 | bytes_more = header.iLength - accum; |
||
| 172 | if ((space_left-accum) < LECROY_TCP_MINIMUM_PACKET_SIZE) { |
||
| 173 | LECROY_TCP_disconnect(sockfd); |
||
| 174 | printf("Read buffer needs to be adjusted, must be minimum of %d bytes\n", |
||
| 175 | LECROY_TCP_MINIMUM_PACKET_SIZE); |
||
| 176 | return -1; |
||
| 177 | } |
||
| 178 | |||
| 179 | if ((result = recv(sockfd, (char *) idxPtr, (bytes_more>2048)?2048:bytes_more,0)) < 0) { |
||
| 180 | LECROY_TCP_disconnect(sockfd); |
||
| 181 | printf("Unable to receive data from the server.\n"); |
||
| 182 | return -1; |
||
| 183 | } |
||
| 184 | |||
| 185 | |||
| 186 | accum += result; |
||
| 187 | if (accum >= header.iLength) break; |
||
| 188 | if ((accum + buf_count) >= len) break; |
||
| 189 | } |
||
| 190 | buf_count += accum; |
||
| 191 | space_left -= accum; |
||
| 192 | |||
| 193 | if (header.bEOI_Flag & LECROY_EOI_FLAG) break; |
||
| 194 | if (space_left <= 0) break; |
||
| 195 | } |
||
| 196 | #ifdef DEBUG |
||
| 197 | printf("Received %s\n",buf); |
||
| 198 | #endif |
||
| 199 | return 0; |
||
| 200 | } |
||
| 201 | |||
| 202 | int LECROY_TCP_connect(char *ip_address, int allowable_delay) { |
||
| 203 | |||
| 204 | int sockfd; |
||
| 205 | int tmp; |
||
| 206 | const int disable=1; |
||
| 207 | |||
| 208 | struct sockaddr_in addr; |
||
| 209 | |||
| 210 | /* bomb out if we've already connected. At time of coding, many LeCroy |
||
| 211 | instruments (including my own scope) can support only one client at |
||
| 212 | a time */ |
||
| 213 | if (LECROY_TCP_connected_flag==TRUE) { |
||
| 214 | printf("ERROR! lecroy_tcp: LECROY_TCP_connected_flag==TRUE!\n"); |
||
| 215 | return -2; |
||
| 216 | } |
||
| 217 | |||
| 218 | tmp=WSAStartup(2,&WSA_data); |
||
| 219 | if (tmp!=0) { |
||
| 220 | printf("ERROR! Socket library ...!\n"); |
||
| 221 | return -1; |
||
| 222 | } |
||
| 223 | //printf("Socket library ...\n"); |
||
| 224 | |||
| 225 | sockfd = socket (PF_INET, SOCK_STREAM, 0); |
||
| 226 | /* Clear out the address struct. */ |
||
| 227 | /* not sure this is entirely necessary.... */ |
||
| 228 | // samo bzero (&addr, sizeof (addr)); |
||
| 229 | |||
| 230 | /* Initialize the values of the address struct including |
||
| 231 | port number and IP address. */ |
||
| 232 | addr.sin_family = AF_INET; |
||
| 233 | addr.sin_port = htons (LECROY_SERVER_PORT); |
||
| 234 | addr.sin_addr.s_addr = inet_addr(ip_address); |
||
| 235 | |||
| 236 | /* The following two lines are necessary so that the program doesn't |
||
| 237 | hang around waiting forever if the scope is turned off. You'd |
||
| 238 | think there would be something you could set in the socket options, |
||
| 239 | wouldn't you? Well, there is, but to quote the socket(7) man pages: |
||
| 240 | |||
| 241 | ------------------------------------------------------------------------------ |
||
| 242 | SOCKET OPTIONS |
||
| 243 | SO_RCVTIMEO and SO_SNDTIMEO |
||
| 244 | Specify the sending or receiving timeouts until reporting an |
||
| 245 | error. They are fixed to a protocol specific setting in Linux |
||
| 246 | and cannot be read or written. Their functionality can be emu- |
||
| 247 | lated using alarm(2) or setitimer(2). |
||
| 248 | ------------------------------------------------------------------------------ |
||
| 249 | |||
| 250 | So, a timer is set with alarm(), and SIGALRM is caught by the |
||
| 251 | "LECROY_TCP_bored_now(int sig)" function. Upon successful |
||
| 252 | connection, however, the alarm is cancelled with "alarm(0)" */ |
||
| 253 | |||
| 254 | // samo signal(SIGALRM,LECROY_TCP_bored_now); |
||
| 255 | // samo alarm(allowable_delay); |
||
| 256 | |||
| 257 | /* Connect to the server. */ |
||
| 258 | tmp=connect(sockfd, (struct sockaddr *)&addr, sizeof (addr)); |
||
| 259 | // samo alarm(0); |
||
| 260 | if (tmp<0){ |
||
| 261 | tmp=WSACleanup(); |
||
| 262 | printf("ERROR! lecroy_tcp: could not connect to the scope!\n"); |
||
| 263 | return -1; |
||
| 264 | } |
||
| 265 | LECROY_TCP_connected_flag=TRUE; |
||
| 266 | |||
| 267 | /* Ok, now we're all connected */ |
||
| 268 | |||
| 269 | /* THE FOLLOWING LINE IS ARCHITECTURE DEPENDENT |
||
| 270 | and is not at all necessary to make a connection and may be |
||
| 271 | safely removed */ |
||
| 272 | |||
| 273 | LECROY_TCP_write(sockfd,"CORD LO\n"); |
||
| 274 | |||
| 275 | /* It sets the 16-bit word transfer byte order to LSB,MSB (ie native |
||
| 276 | Intel format). This makes things easier to interpret, so it's a |
||
| 277 | sufficiently-useful thing to add in the connect function. Can be |
||
| 278 | commented out obviously. For motorola-based systems, use: |
||
| 279 | LECROY_TCP_write(sockfd,"CORD HI\n"); |
||
| 280 | Obviously there'll be some way of working out at compile-time, but |
||
| 281 | I don't know how! --- sds, 6/5/03 */ |
||
| 282 | |||
| 283 | return sockfd; |
||
| 284 | } |
||
| 285 | /* |
||
| 286 | void LECROY_TCP_bored_now(int sig) { |
||
| 287 | |||
| 288 | printf("Well, I got bored waiting to connect, so I'm going to quit. Bye!\n"); |
||
| 289 | exit(1); |
||
| 290 | } |
||
| 291 | */ |
||
| 292 | int LECROY_TCP_disconnect(int sockfd) { |
||
| 293 | |||
| 294 | if (LECROY_TCP_connected_flag !=TRUE) return -1; |
||
| 295 | closesocket(sockfd); |
||
| 296 | WSACleanup(); |
||
| 297 | LECROY_TCP_connected_flag=FALSE; |
||
| 298 | return 0; |
||
| 299 | } |
||
| 300 |