First Commit of my working state
[simh.git] / Ibm1130 / ibm1130_sca.c
Content-type: text/html gitweb.hachti.de Git - simh.git/blame - Ibm1130/ibm1130_sca.c


500 - Internal Server Error

Malformed UTF-8 character (fatal) at (eval 5) line 1, <$fd> line 1443.
CommitLineData
196ba1fc
PH
1/* ibm1130_sca.c: IBM 1130 synchronous communications adapter emulation\r
2\r
3 Based on the SIMH simulator package written by Robert M Supnik\r
4\r
5 Brian Knittel\r
6 Revision History\r
7\r
8 2005.03.08 - Started\r
9\r
10 * (C) Copyright 2005, Brian Knittel.\r
11 * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN\r
12 * RISK basis, there is no warranty of fitness for any purpose, and the rest of the\r
13 * usual yada-yada. Please keep this notice and the copyright in any distributions\r
14 * or modifications.\r
15 *\r
16 * This is not a supported product, but I welcome bug reports and fixes.\r
17 * Mail to simh@ibm1130.org\r
18 */\r
19\r
20/******************************************************************************************************************\r
21 * NOTES:\r
22 * This module sends raw bisync data over a standard TCP port. It's meant to be\r
23 * used with the emulated 2703 device in Hercules.\r
24 *\r
25 * Attach command:\r
26 *\r
27 * to establish an outgoing connection:\r
28 *\r
29 * attach sca host connect to named host on default port (initial default port is 2703); or\r
30 * attach sca host:### connect to named host on port ###. ### is also set as new default port number.\r
31 * >> The simulator waits until the connection is established\r
32 *\r
33 * or to set up for incoming connections:\r
34 *\r
35 * attach sca -l dummy listen for a connection on default port (initially 2703); Nonnumeric "dummy" argument is ignored; or\r
36 * attach sca -l ### listen for a connection on the port ###. ### is also set as the new default port\r
37 * >> The simulator proceeds. When another simulator connects, the READY bit is set in the DSW.\r
38 *\r
39 * If the SCA's autoanswer-enable bit has been set, an incoming connection causes an interrupt (untested)\r
40 * Configuration commands:\r
41 *\r
42 * set sca bsc set bisync mode (default)\r
43 * set sca str set synchronous transmit/recieve mode (NOT IMPLEMENTED)\r
44 *\r
45 * set sca ### set simulated baud rate to ###, where ### is 600, 1200, 2000, 2400 or 4800 (4800 is default)\r
46 *\r
47 * set sca half set simulated half-duplex mode\r
48 * set sca full set simulated full-duplex mode (note: 1130's SCA can't actually send and receive at the same time!)\r
49 *\r
50 * deposit sca keepalive ### send SYN packets every ### msec when suppressing SYN's, default is 0 (no keepalives)\r
51 *\r
52 * STR/BSC mode is selected by a toggle switch on the 1130, with the SET SCA BSC or SET SET STR command here.\r
53 * Testable with in_bsc_mode() or in_str_mode() in this module. If necessary, the SET command can be configured\r
54 * to call a routine when the mode is changed; or, we can just required the user to reboot the simulated 1130\r
55 * when switching modes.\r
56 *\r
57 * STR MODE IS NOT IMPLEMENTED!\r
58 *\r
59 * The SCA adapter appears to know nothing of the protocols used by STR and BSC. It does handle the sync/idle\r
60 * character specially, and between BSC and STR mode the timers are used differently. Also in STR mode it\r
61 * can be set to a sychronization mode where it sends SYN's without program intervention.\r
62 *\r
63 * See definition of SCA_STATE for defintion of simulator states.\r
64 *\r
65 * Rather than trying to simulate the actual baud rates, we try to keep the character service interrupts\r
66 * coming at about the same number of instruction intervals -- thus existing 1130 code should work correctly\r
67 * but the effective data transfer rate will be much higher. The "timers" however are written to run on real wall clock\r
68 * time, This may or may not work. If necessary they could be set to time out based on the number of calls to sca_svc\r
69 * which occurs once per character send/receive time; For example, at 4800 baud and an 8 bit frame, we get\r
70 * 600 characters/second, so the 3 second timer would expire in 1800 sca_svc calls. Well, that's something to\r
71 * think about.\r
72 *\r
73 * To void blowing zillions of SYN characters across the network when the system is running but idle, we suppress\r
74 * them. If 100 consecutive SYN's are sent, we flush the output buffer and stop sending SYN's\r
75 * until some other character is sent, OR the line is turned around (e.g. INITR, INITW or an end-operation\r
76 * CONTROL is issued), or the number of msec set by DEPOSIT SCS KEEPALIVE has passed, if a value has\r
77 * been set. By default no keepalives are sent.\r
78 *\r
79 * Timer operations are not debugged. First, do timers automatically reset and re-interrupt if\r
80 * left alone after they timeout the first time? Does XIO_SENSE_DEV really restart all running timers?\r
81 * Does it touch the timer trigger (program timer?) How do 3 and 1.25 second timers really work\r
82 * in BSC mode? Hard to tell from the FC manual.\r
83 ******************************************************************************************************************/\r
84\r
85#include "ibm1130_defs.h"\r
86#include "sim_sock.h" /* include path must include main simh directory */\r
87#include <ctype.h>\r
88#ifndef INADDR_NONE\r
89#define INADDR_NONE ((unsigned long)-1)\r
90#endif\r
91\r
92#define DEBUG_SCA_FLUSH 0x0001 /* debugging options */\r
93#define DEBUG_SCA_TRANSMIT 0x0002\r
94#define DEBUG_SCA_CHECK_INDATA 0x0004\r
95#define DEBUG_SCA_RECEIVE_SYNC 0x0008\r
96#define DEBUG_SCA_RECEIVE_DATA 0x0010\r
97#define DEBUG_SCA_XIO_READ 0x0020\r
98#define DEBUG_SCA_XIO_WRITE 0x0040\r
99#define DEBUG_SCA_XIO_CONTROL 0x0080\r
100#define DEBUG_SCA_XIO_INITW 0x0100\r
101#define DEBUG_SCA_XIO_INITR 0x0200\r
102#define DEBUG_SCA_XIO_SENSE_DEV 0x0400\r
103#define DEBUG_SCA_TIMERS 0x0800\r
104#define DEBUG_SCA_ALL 0xFFFF\r
105\r
106/* #define DEBUG_SCA (DEBUG_SCA_TIMERS|DEBUG_SCA_FLUSH|DEBUG_SCA_TRANSMIT|DEBUG_SCA_CHECK_INDATA|DEBUG_SCA_RECEIVE_SYNC|DEBUG_SCA_RECEIVE_DATA|DEBUG_SCA_XIO_INITR|DEBUG_SCA_XIO_INITW) */\r
107#define DEBUG_SCA (DEBUG_SCA_TIMERS|DEBUG_SCA_FLUSH|DEBUG_SCA_CHECK_INDATA|DEBUG_SCA_XIO_INITR|DEBUG_SCA_XIO_INITW)\r
108\r
109#define SCA_DEFAULT_PORT 2703 /* default socket, This is the number of the IBM 360's BSC device */\r
110\r
111#define MAX_SYNS 100 /* number of consecutive syn's after which we stop buffering them */\r
112\r
113/***************************************************************************************\r
114 * SCA\r
115 ***************************************************************************************/\r
116\r
117#define SCA_DSW_READ_RESPONSE 0x8000 /* receive buffer full interrupt */\r
118#define SCA_DSW_WRITE_RESPONSE 0x4000 /* transmitter buffer empty interrupt */\r
119#define SCA_DSW_CHECK 0x2000 /* data overrun or character gap error */\r
120#define SCA_DSW_TIMEOUT 0x1000 /* timer interrupt, mode specific */\r
121#define SCA_DSW_AUTOANSWER_REQUEST 0x0800 /* dataset is ringing and autoanswer is enabled */\r
122#define SCA_DSW_BUSY 0x0400 /* adapter is in either receive or transmit mode */\r
123#define SCA_DSW_AUTOANSWER_ENABLED 0x0200 /* 1 when autoanswer mode has been enabled */\r
124#define SCA_DSW_READY 0x0100 /* Carrier detect? Connected and ready to rcv, xmit or sync */\r
125#define SCA_DSW_RECEIVE_RUN 0x0080 /* used in two-wire half-duplex STR mode only. "Slave" mode (?) */\r
126\r
127#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT)\r
128\r
129typedef enum { /* ms m = mode (0 = idle, 1 = send, 2 = receive), s = substate */\r
130 SCA_STATE_IDLE = 0x00, /* nothing happening */\r
131 SCA_STATE_TURN_SEND = 0x10, /* line turning around to the send state */\r
132 SCA_STATE_SEND_SYNC = 0x11, /* sca is sending syncs */\r
133 SCA_STATE_SEND1 = 0x12, /* have issued write response, waiting for write command */\r
134 SCA_STATE_SEND2 = 0x13, /* write command issued, "sending" byte */\r
135 SCA_STATE_TURN_RECEIVE = 0x20, /* line turnaround to the receive state */\r
136 SCA_STATE_RECEIVE_SYNC = 0x21, /* sca is receiving syncs */\r
137 SCA_STATE_RECEIVE_SYNC2 = 0x22, /* bsc mode, waiting for 2nd SYN */\r
138 SCA_STATE_RECEIVE_SYNC3 = 0x23, /* bsc mode, waiting for 1st non-SYN */\r
139 SCA_STATE_RECEIVE1 = 0x24, /* "receiving" a byte */\r
140 SCA_STATE_RECEIVE2 = 0x25, /* read response issued, "receiving" next byte */\r
141} SCA_STATE;\r
142\r
143#define in_send_state() (sca_state & 0x10)\r
144#define in_receive_state() (sca_state & 0x20)\r
145\r
146static t_stat sca_svc (UNIT *uptr); /* prototypes */\r
147static t_stat sca_reset (DEVICE *dptr);\r
148static t_stat sca_attach (UNIT *uptr, char *cptr);\r
149static t_stat sca_detach (UNIT *uptr);\r
150static void sca_start_timer (int n, int msec_now);\r
151static void sca_halt_timer (int n);\r
152static void sca_toggle_timer (int n, int msec_now);\r
153 /* timer states, chosen so any_timer_running can be calculated by oring states of all 3 timers */\r
154typedef enum {SCA_TIMER_INACTIVE = 0, SCA_TIMER_RUNNING = 1, SCA_TIMER_INHIBITED = 2, SCA_TIMER_TIMEDOUT = 4} SCA_TIMER_STATE;\r
155\r
156#define TIMER_3S 0 /* 3 second timer index into sca_timer_xxx arrays */\r
157#define TIMER_125S 1 /* 1.25 second timer */\r
158#define TIMER_035S 2 /* 0.35 second timer */\r
159\r
160static uint16 sca_dsw = 0; /* device status word */\r
161static uint32 sca_cwait = 275; /* inter-character wait */\r
162static uint32 sca_iwait = 2750; /* idle wait */\r
163static uint32 sca_state = SCA_STATE_IDLE;\r
164static uint8 sichar = 0; /* sync/idle character */\r
165static uint8 rcvd_char = 0; /* most recently received character */\r
166static uint8 sca_frame = 8;\r
167static uint16 sca_port = SCA_DEFAULT_PORT; /* listening port number */\r
168static int32 sca_keepalive = 0; /* keepalive SYN packet period in msec, default = 0 (disabled) */\r
169static SCA_TIMER_STATE sca_timer_state[3]; /* current timer state */\r
170static int sca_timer_endtime[3]; /* clocktime when timeout is to occur if state is RUNNING */\r
171static int sca_timer_timeleft[3]; /* time left in msec if state is INHIBITED */\r
172static t_bool any_timer_running = FALSE; /* TRUE if at least one timer is running */\r
173static int sca_timer_msec[3] = {3000, 1250, 350}; /* timebase in msec for the three timers: 3 sec, 1.25 sec, 0.35 sec */\r
174static t_bool sca_timer_trigger; /* if TRUE, the "timer trigger" is set, the 0.35s timer is running and the 3 sec and 1.25 sec timers are inhibited */\r
175static int sca_nsyns = 0; /* number of consecutively sent SYN's */\r
176static int idles_since_last_write = 0; /* used to detect when software has ceased sending data */\r
177static SOCKET sca_lsock = INVALID_SOCKET;\r
178static SOCKET sca_sock = INVALID_SOCKET;\r
179\r
180#define SCA_SENDBUF_SIZE 145 /* maximum number of bytes to buffer for transmission */\r
181#define SCA_RCVBUF_SIZE 256 /* max number of bytes to read from socket at a time */\r
182#define SCA_SEND_THRESHHOLD 140 /* number of bytes to buffer before initiating packet send */\r
183#define SCA_IDLE_THRESHHOLD 3 /* maximum number of unintentional idles to buffer before initiating send */\r
184\r
185static uint8 sca_sendbuf[SCA_SENDBUF_SIZE]; /* bytes pending to write to socket */\r
186static uint8 sca_rcvbuf[SCA_RCVBUF_SIZE]; /* bytes received from socket, to be given to SCA */\r
187static int sca_n2send = 0; /* number of bytes queued for transmission */\r
188static int sca_nrcvd = 0; /* number of received bytes in buffer */\r
189static int sca_rcvptr = 0; /* index of next byte to take from rcvbuf */\r
190\r
191#define UNIT_V_BISYNC (UNIT_V_UF + 0) /* BSC (bisync) mode */\r
192#define UNIT_V_BAUD (UNIT_V_UF + 1) /* 3 bits for baud rate encoding */\r
193#define UNIT_V_FULLDUPLEX (UNIT_V_UF + 4)\r
194#define UNIT_V_AUTOANSWER (UNIT_V_UF + 5)\r
195#define UNIT_V_LISTEN (UNIT_V_UF + 6) /* listen socket mode */\r
196\r
197#define UNIT_BISYNC (1u << UNIT_V_BISYNC)\r
198#define UNIT_BAUDMASK (7u << UNIT_V_BAUD)\r
199#define UNIT_BAUD600 (0u << UNIT_V_BAUD)\r
200#define UNIT_BAUD1200 (1u << UNIT_V_BAUD)\r
201#define UNIT_BAUD2000 (2u << UNIT_V_BAUD)\r
202#define UNIT_BAUD2400 (3u << UNIT_V_BAUD)\r
203#define UNIT_BAUD4800 (4u << UNIT_V_BAUD)\r
204#define UNIT_FULLDUPLEX (1u << UNIT_V_FULLDUPLEX)\r
205#define UNIT_AUTOANSWER (1u << UNIT_V_AUTOANSWER)\r
206#define UNIT_LISTEN (1u << UNIT_V_LISTEN)\r
207\r
208extern int sim_switches; /* variable that gets bits set for -x switches on command lines */\r
209\r
210t_stat sca_set_baud (UNIT *uptr, int32 value, char *cptr, void *desc);\r
211\r
212UNIT sca_unit = { /* default settings */\r
213 UDATA (sca_svc, UNIT_ATTABLE|UNIT_BISYNC|UNIT_BAUD4800|UNIT_FULLDUPLEX, 0),\r
214};\r
215\r
216REG sca_reg[] = { /* DEVICE STATE/SETTABLE PARAMETERS: */\r
217 { HRDATA (SCADSW, sca_dsw, 16) }, /* device status word */\r
218 { DRDATA (SICHAR, sichar, 8), PV_LEFT }, /* sync/idle character */\r
219 { DRDATA (RCVDCHAR, rcvd_char, 8), PV_LEFT }, /* most recently received character */\r
220 { DRDATA (FRAME, sca_frame, 8), PV_LEFT }, /* frame bits (6, 7 or 8)\r
221 { DRDATA (SCASTATE, sca_state, 32), PV_LEFT }, /* current state */\r
222 { DRDATA (CTIME, sca_cwait, 32), PV_LEFT }, /* inter-character wait */\r
223 { DRDATA (ITIME, sca_iwait, 32), PV_LEFT }, /* idle wait (polling interval for socket connects) */\r
224 { DRDATA (SCASOCKET, sca_port, 16), PV_LEFT }, /* listening port number */\r
225 { DRDATA (KEEPALIVE, sca_keepalive, 32), PV_LEFT }, /* keepalive packet period in msec */\r
226 { NULL } };\r
227\r
228MTAB sca_mod[] = { /* DEVICE OPTIONS */\r
229 { UNIT_BISYNC, 0, "STR", "STR", NULL }, /* mode option */\r
230 { UNIT_BISYNC, UNIT_BISYNC, "BSC", "BSC", NULL },\r
231 { UNIT_BAUDMASK, UNIT_BAUD600, "600", "600", sca_set_baud }, /* data rate option */\r
232 { UNIT_BAUDMASK, UNIT_BAUD1200, "1200", "1200", sca_set_baud },\r
233 { UNIT_BAUDMASK, UNIT_BAUD2000, "2000", "2000", sca_set_baud },\r
234 { UNIT_BAUDMASK, UNIT_BAUD2400, "2400", "2400", sca_set_baud },\r
235 { UNIT_BAUDMASK, UNIT_BAUD4800, "4800", "4800", sca_set_baud },\r
236 { UNIT_FULLDUPLEX, 0, "HALF", "HALF", NULL }, /* duplex option (does this matter?) */\r
237 { UNIT_FULLDUPLEX, UNIT_FULLDUPLEX, "FULL", "FULL", NULL },\r
238 { 0 } };\r
239\r
240DEVICE sca_dev = {\r
241 "SCA", &sca_unit, sca_reg, sca_mod,\r
242 1, 16, 16, 1, 16, 16,\r
243 NULL, NULL, sca_reset,\r
244 NULL, sca_attach, sca_detach\r
245};\r
246\r
247/*********************************************************************************************\r
248 * sca_set_baud - set baud rate handler (SET SCA.BAUD nnn)\r
249 *********************************************************************************************/\r
250\r
251t_stat sca_set_baud (UNIT *uptr, int32 value, char *cptr, void *desc)\r
252{\r
253 uint32 newbits;\r
254\r
255 switch (value) {\r
256 case 600: newbits = UNIT_BAUD600; break;\r
257 case 1200: newbits = UNIT_BAUD1200; break;\r
258 case 2000: newbits = UNIT_BAUD2000; break;\r
259 case 2400: newbits = UNIT_BAUD2400; break;\r
260 case 4800: newbits = UNIT_BAUD4800; break;\r
261 default: return SCPE_ARG;\r
262 }\r
263\r
264 CLRBIT(sca_unit.flags, UNIT_BAUDMASK);\r
265 SETBIT(sca_unit.flags, newbits);\r
266\r
267 sca_cwait = 1320000 / value; /* intercharacter wait time in instructions (roughly) */\r
268\r
269 return SCPE_OK;\r
270}\r
271\r
272/*********************************************************************************************\r
273 * HANDY MACROS \r
274 *********************************************************************************************/\r
275\r
276#define in_bsc_mode() (sca_unit.flags & UNIT_BISYNC) /* TRUE if user selected BSC mode */\r
277#define in_str_mode() ((sca_unit.flags & UNIT_BISYNC) == 0) /* TRUE if user selected STR mode */\r
278\r
279/*********************************************************************************************\r
280 * mstring - allocate a copy of a string\r
281 *********************************************************************************************/\r
282\r
283char *mstring (char *str)\r
284{\r
285 int len;\r
286 char *m;\r
287\r
288 len = strlen(str)+1;\r
289 if ((m = malloc(len)) == NULL) {\r
290 printf("Out of memory!");\r
291 return "?"; /* this will of course cause trouble if it's subsequently freed */\r
292 }\r
293 strcpy(m, str);\r
294 return m;\r
295}\r
296\r
297/*********************************************************************************************\r
298 * sca_socket_error - call when there is an error reading from or writing to socket\r
299 *********************************************************************************************/\r
300\r
301static void sca_socket_error (void)\r
302{\r
303 char name[100];\r
304\r
305 /* print diagnostic? */\r
306 printf("SCA socket error, closing connection\n");\r
307\r
308 /* tell 1130 that connection was lost */\r
309 CLRBIT(sca_dsw, SCA_DSW_READY);\r
310\r
311 if (sca_sock != INVALID_SOCKET) {\r
312 /* close socket, prepare to listen again if in listen mode. It's a "master" socket if it was an outgoing connection */\r
313 sim_close_sock(sca_sock, (sca_unit.flags & UNIT_LISTEN) == 0);\r
314 sca_sock = INVALID_SOCKET;\r
315\r
316 if (sca_unit.filename != NULL) /* reset filename string in unit record */\r
317 free(sca_unit.filename);\r
318\r
319 if (sca_unit.flags & UNIT_LISTEN) {\r
320 sprintf(name, "(Listening on port %d)", sca_port);\r
321 sca_unit.filename = mstring(name);\r
322 printf("%s\n", name);\r
323 }\r
324 else\r
325 sca_unit.filename = mstring("(connection failed)");\r
326 }\r
327\r
328 /* clear buffers */\r
329 sca_nrcvd = sca_rcvptr = sca_n2send = sca_nsyns = 0;\r
330}\r
331\r
332/*********************************************************************************************\r
333 * sca_transmit_byte, sca_flush - send data buffering mechanism\r
334 *********************************************************************************************/\r
335\r
336static void sca_flush (void)\r
337{\r
338 int nbytes;\r
339\r
340 if (sca_n2send > 0) {\r
341#if (DEBUG_SCA & DEBUG_SCA_FLUSH)\r
342 printf("* SCA_FLUSH %d byte%s\n", sca_n2send, (sca_n2send == 1) ? "" : "s");\r
343#endif\r
344\r
345 if (sca_sock != INVALID_SOCKET) {\r
346 nbytes = sim_write_sock(sca_sock, sca_sendbuf, sca_n2send);\r
347\r
348 if (nbytes == SOCKET_ERROR)\r
349 sca_socket_error();\r
350 else if (nbytes != sca_n2send)\r
351 printf("SOCKET BLOCKED -- NEED TO REWRITE IBM1130_SCA.C");\r
352\r
353 /* I'm going to assume that SCA communications on the 1130 will consist entirely */\r
354 /* of back and forth exchanges of short records, and so we should never stuff the pipe so full that */\r
355 /* it blocks. If it does ever block, we'll have to come up with an asychronous buffering mechanism. */\r
356 }\r
357\r
358 sca_n2send = 0; /* mark buffer cleared */\r
359 }\r
360}\r
361\r
362/*********************************************************************************************\r
363 * sca_transmit_byte - buffer a byte to be send to the socket\r
364 *********************************************************************************************/\r
365\r
366static void sca_transmit_byte (uint8 b)\r
367{\r
368 uint32 curtime;\r
369 static uint32 last_syn_time, next_syn_time;\r
370\r
371#if (DEBUG_SCA & DEBUG_SCA_TRANSMIT)\r
372 printf("* SCA_TRANSMIT: %02x\n", b);\r
373#endif\r
374\r
375 /* write a byte to the socket. Let's assume an 8 bit frame in all cases.\r
376 * We buffer them up, then send the packet when (a) it fills up to a certain point\r
377 * and/or (b) some time has passed? We handle (b) by:\r
378 * checking in sva_svc if several sca_svc calls are made w/o any XIO_WRITES, and\r
379 * flushing send buffer on line turnaround, timeouts, or any other significant state change\r
380 */\r
381\r
382 /* on socket error, call sca_socket_error(); */\r
383\r
384 if (b == sichar) {\r
385 if (sca_nsyns >= MAX_SYNS) { /* we're suppressing SYN's */\r
386 if (sca_keepalive > 0) { /* we're sending keepalives, though... check to see if it's time */\r
387 curtime = sim_os_msec();\r
388 if (curtime >= next_syn_time || curtime < last_syn_time) { /* check for < last_syn_time because sim_os_msec() can wrap when OS has been running a long time */\r
389 sca_sendbuf[sca_n2send++] = b;\r
390 sca_sendbuf[sca_n2send++] = b; /* send 2 of them */\r
391 sca_flush();\r
392 last_syn_time = curtime;\r
393 next_syn_time = last_syn_time + sca_keepalive;\r
394 }\r
395 }\r
396 return;\r
397 }\r
398\r
399 if (++sca_nsyns == MAX_SYNS) { /* we've sent a bunch of SYN's, time to stop sending them */\r
400 sca_sendbuf[sca_n2send] = b; /* send last one */\r
401 sca_flush();\r
402 last_syn_time = sim_os_msec(); /* remember time, and note time to send next one */\r
403 next_syn_time = last_syn_time + sca_keepalive;\r
404 return;\r
405 }\r
406 }\r
407 else\r
408 sca_nsyns = 0;\r
409\r
410 sca_sendbuf[sca_n2send] = b; /* store character */\r
411\r
412 if (++sca_n2send >= SCA_SEND_THRESHHOLD)\r
413 sca_flush(); /* buffer is full, send it immediately */\r
414}\r
415\r
416/*********************************************************************************************\r
417 * sca_interrupt (utility routine) - set a bit in the device status word and initiate an interrupt\r
418 *********************************************************************************************/\r
419\r
420static void sca_interrupt (int bit)\r
421{\r
422 sca_dsw |= bit; /* set device status word bit(s) */\r
423 SETBIT(ILSW[1], ILSW_1_SCA); /* set interrupt level status word bit */\r
424\r
425 calc_ints(); /* udpate simulator interrupt status (not really needed if within xio handler, since ibm1130_cpu calls it after xio handler) */\r
426}\r
427\r
428/*********************************************************************************************\r
429 * sca_reset - reset the SCA device\r
430 *********************************************************************************************/\r
431\r
432static t_stat sca_reset (DEVICE *dptr)\r
433{\r
434 /* flush any pending data */\r
435 sca_flush();\r
436 sca_nrcvd = sca_rcvptr = sca_n2send = sca_nsyns = 0;\r
437\r
438 /* reset sca activity */\r
439 sca_state = SCA_STATE_IDLE;\r
440 CLRBIT(sca_dsw, SCA_DSW_BUSY | SCA_DSW_AUTOANSWER_ENABLED | SCA_DSW_RECEIVE_RUN | SCA_DSW_READ_RESPONSE | SCA_DSW_WRITE_RESPONSE | SCA_DSW_CHECK | SCA_DSW_TIMEOUT | SCA_DSW_AUTOANSWER_REQUEST);\r
441 sca_timer_state[0] = sca_timer_state[1] = sca_timer_state[2] = SCA_TIMER_INACTIVE;\r
442 any_timer_running = FALSE;\r
443 sca_timer_trigger = FALSE;\r
444\r
445 if (sca_unit.flags & UNIT_ATT) /* if unit is attached (or listening) */\r
446 sim_activate(&sca_unit, sca_iwait); /* poll for service. Must do this here as BOOT clears activity queue before resetting all devices */\r
447\r
448 return SCPE_OK;\r
449}\r
450\r
451/*********************************************************************************************\r
452 * sca_attach - attach the SCA device\r
453 *********************************************************************************************/\r
454\r
455static t_stat sca_attach (UNIT *uptr, char *cptr)\r
456{\r
457 t_bool do_listen;\r
458 char *colon;\r
459 uint32 ipaddr;\r
460 int32 port;\r
461 struct hostent *he;\r
462 char name[256];\r
463 static SOCKET sdummy = INVALID_SOCKET;\r
464 fd_set wr_set, err_set;\r
465\r
466 do_listen = sim_switches & SWMASK('L'); /* -l means listen mode */\r
467\r
468 if (sca_unit.flags & UNIT_ATT) /* if already attached, detach */\r
469 detach_unit(&sca_unit);\r
470\r
471 if (do_listen) { /* if listen mode, string specifies socket number (only; otherwise it's a dummy argument) */\r
472 if (isdigit(*cptr)) { /* if digits specified, extract port number */\r
473 port = atoi(cptr);\r
474 if (port <= 0 || port > 65535)\r
475 return SCPE_ARG;\r
476 else\r
477 sca_port = port;\r
478 }\r
479 /* else if nondigits specified, ignore... but the command has to have something there otherwise the core scp */\r
480 /* attach_cmd() routine complains "too few arguments". */\r
481\r
482 if ((sca_lsock = sim_master_sock(sca_port)) == INVALID_SOCKET)\r
483 return SCPE_OPENERR;\r
484 \r
485 SETBIT(sca_unit.flags, UNIT_LISTEN); /* note that we are listening, not yet connected */\r
486\r
487 sprintf(name, "(Listening on port %d)", sca_port);\r
488 sca_unit.filename = mstring(name);\r
489 printf("%s\n", name);\r
490\r
491 }\r
492 else {\r
493 while (*cptr && *cptr <= ' ')\r
494 cptr++;\r
495\r
496 if (! *cptr)\r
497 return SCPE_2FARG;\r
498\r
499 if ((colon = strchr(cptr, ':')) != NULL) {\r
500 *colon++ = '\0'; /* clip hostname at colon */\r
501\r
502 port = atoi(colon); /* extract port number that follows it */\r
503 if (port <= 0 || port > 65535)\r
504 return SCPE_ARG;\r
505 else\r
506 sca_port = port;\r
507 }\r
508\r
509 if (sdummy == INVALID_SOCKET)\r
510 if ((sdummy = sim_create_sock()) == INVALID_SOCKET) /* create and keep a socket, to force initialization */\r
511 return SCPE_IERR; /* of socket library (e.g on Win32 call WSAStartup), else gethostbyname fails */\r
512\r
513 if (get_ipaddr(cptr, &ipaddr, NULL) != SCPE_OK) { /* try to parse hostname as dotted decimal nnn.nnn.nnn.nnn */\r
514 if ((he = gethostbyname(cptr)) == NULL) /* if not decimal, look up name through DNS */\r
515 return SCPE_OPENERR;\r
516 \r
517 if ((ipaddr = * (unsigned long *) he->h_addr_list[0]) == INADDR_NONE)\r
518 return SCPE_OPENERR;\r
519\r
520 ipaddr = ntohl(ipaddr); /* convert to host byte order; gethostbyname() gives us network order */\r
521 }\r
522\r
523 if ((sca_sock = sim_connect_sock(ipaddr, sca_port)) == INVALID_SOCKET)\r
524 return SCPE_OPENERR;\r
525\r
526 /* sim_connect_sock() sets socket to nonblocking before initiating the connect, so\r
527 * the connect is pending when it returns. For outgoing connections, the attach command should wait\r
528 * until the connection succeeds or fails. We use "accept" to wait and find out which way it goes...\r
529 */\r
530\r
531 FD_ZERO(&wr_set); /* we are only interested in info for sca_sock */\r
532 FD_ZERO(&err_set);\r
533 FD_SET(sca_sock, &wr_set);\r
534 FD_SET(sca_sock, &err_set);\r
535\r
536 select(3, NULL, &wr_set, &err_set, NULL); /* wait for connection to complete or fail */\r
537\r
538 if (FD_ISSET(sca_sock, &wr_set)) { /* sca_sock appears in "writable" set -- connect completed */\r
539 sprintf(name, "%s:%d", cptr, sca_port);\r
540 sca_unit.filename = mstring(name);\r
541 SETBIT(sca_dsw, SCA_DSW_READY);\r
542 }\r
543 else if (FD_ISSET(sca_sock, &err_set)) { /* sca_sock appears in "error" set -- connect failed */\r
544 sim_close_sock(sca_sock, TRUE);\r
545 sca_sock = INVALID_SOCKET;\r
546 return SCPE_OPENERR;\r
547 }\r
548 else { /* if we get here my assumption about how select works is wrong */\r
549 printf("SCA_SOCK NOT FOUND IN WR_SET -OR- ERR_SET, CODING IN IBM1130_SCA IS WRONG\n");\r
550 sim_close_sock(sca_sock, TRUE);\r
551 sca_sock = INVALID_SOCKET;\r
552 return SCPE_OPENERR;\r
553 }\r
554 }\r
555 \r
556 /* set up socket connect or listen. on success, set UNIT_ATT.\r
557 * If listen mode, set UNIT_LISTEN. sca_svc will poll for connection\r
558 * If connect mode, set dsw SCA_DSW_READY to indicate connection is up\r
559 */\r
560 \r
561 SETBIT(sca_unit.flags, UNIT_ATT); /* record successful socket binding */\r
562\r
563 sca_state = SCA_STATE_IDLE;\r
564 sim_activate(&sca_unit, sca_iwait); /* start polling for service */\r
565\r
566 sca_n2send = 0; /* clear buffers */\r
567 sca_nrcvd = 0;\r
568 sca_rcvptr = 0;\r
569 sca_nsyns = 0;\r
570\r
571 return SCPE_OK;\r
572}\r
573\r
574/*********************************************************************************************\r
575 * sca_detach - detach the SCA device\r
576 *********************************************************************************************/\r
577\r
578static t_stat sca_detach (UNIT *uptr)\r
579{\r
580 if ((sca_unit.flags & UNIT_ATT) == 0)\r
581 return SCPE_OK;\r
582\r
583 sca_flush();\r
584\r
585 sca_state = SCA_STATE_IDLE; /* stop processing during service calls */\r
586 sim_cancel(&sca_unit); /* stop polling for service */\r
587\r
588 CLRBIT(sca_dsw, SCA_DSW_READY); /* indicate offline */\r
589\r
590 if (sca_sock != INVALID_SOCKET) { /* close connected socket */\r
591 sim_close_sock(sca_sock, (sca_unit.flags & UNIT_LISTEN) == 0);\r
592 sca_sock = INVALID_SOCKET;\r
593 }\r
594 if (sca_lsock != INVALID_SOCKET) { /* close listening socket */\r
595 sim_close_sock(sca_lsock, TRUE);\r
596 sca_lsock = INVALID_SOCKET;\r
597 }\r
598 \r
599 free(sca_unit.filename);\r
600 sca_unit.filename = NULL;\r
601\r
602 CLRBIT(sca_unit.flags, UNIT_ATT|UNIT_LISTEN);\r
603\r
604 return SCPE_OK;\r
605}\r
606\r
607/*********************************************************************************************\r
608 * sca_check_connect - see if an incoming socket connection has com\r
609 *********************************************************************************************/\r
610\r
611static void sca_check_connect (void)\r
612{\r
613 uint32 ipaddr;\r
614 char name[100];\r
615\r
616 if ((sca_sock = sim_accept_conn(sca_lsock, &ipaddr)) == INVALID_SOCKET)\r
617 return;\r
618\r
619 ipaddr = htonl(ipaddr); /* convert to network order so we can print it */\r
620\r
621 sprintf(name, "%d.%d.%d.%d", ipaddr & 0xFF, (ipaddr >> 8) & 0xFF, (ipaddr >> 16) & 0xFF, (ipaddr >> 24) & 0xFF);\r
622\r
623 printf("(SCA connection from %s)\n", name);\r
624\r
625 if (sca_unit.filename != NULL)\r
626 free(sca_unit.filename);\r
627\r
628 sca_unit.filename = mstring(name);\r
629\r
630 SETBIT(sca_dsw, SCA_DSW_READY); /* indicate active connection */\r
631\r
632 if (sca_dsw & SCA_DSW_AUTOANSWER_ENABLED) /* if autoanswer was enabled, I guess we should give them an interrupt. Untested. */\r
633 sca_interrupt(SCA_DSW_AUTOANSWER_REQUEST);\r
634}\r
635\r
636/*********************************************************************************************\r
637 * sca_check_indata - try to fill receive buffer from socket\r
638 *********************************************************************************************/\r
639\r
640static void sca_check_indata (void)\r
641{\r
642 int nbytes;\r
643\r
644 sca_rcvptr = 0; /* reset pointers and count */\r
645 sca_nrcvd = 0;\r
646\r
647#ifdef FAKE_SCA\r
648\r
649 nbytes = 5; /* FAKE: receive SYN SYN SYN SYN DLE ACK0 */\r
650 sca_rcvbuf[0] = 0x32;\r
651 sca_rcvbuf[1] = 0x32;\r
652 sca_rcvbuf[2] = 0x32;\r
653 sca_rcvbuf[3] = 0x10;\r
654 sca_rcvbuf[4] = 0x70;\r
655\r
656#else\r
657 /* read socket; 0 is returned if no data is available */\r
658 nbytes = sim_read_sock(sca_sock, sca_rcvbuf, SCA_RCVBUF_SIZE);\r
659\r
660#endif\r
661\r
662 if (nbytes < 0)\r
663 sca_socket_error();\r
664 else /* zero or more */\r
665 sca_nrcvd = nbytes;\r
666\r
667#if (DEBUG_SCA & DEBUG_SCA_CHECK_INDATA)\r
668 if (sca_nrcvd > 0)\r
669 printf("* SCA_CHECK_INDATA %d byte%s\n", sca_nrcvd, (sca_nrcvd == 1) ? "" : "s");\r
670#endif\r
671}\r
672\r
673/*********************************************************************************************\r
674 * sca_svc - handled scheduled event. This will presumably be scheduled frequently, and can check\r
675 * for incoming data, reasonableness of initiating a write interrupt, timeouts etc.\r
676 *********************************************************************************************/\r
677\r
678static t_stat sca_svc (UNIT *uptr)\r
679{\r
680 t_bool timeout;\r
681 int msec_now;\r
682 int i;\r
683\r
684 /* if not connected, and if in wait-for-connection mode, check for connection attempt */\r
685 if ((sca_unit.flags & UNIT_LISTEN) && ! (sca_dsw & SCA_DSW_READY))\r
686 sca_check_connect();\r
687\r
688 if (any_timer_running) {\r
689 msec_now = sim_os_msec();\r
690\r
691 timeout = FALSE;\r
692 for (i = 0; i < 3; i++) {\r
693 if (sca_timer_state[i] == SCA_TIMER_RUNNING && msec_now >= sca_timer_endtime[i]) {\r
694 timeout = TRUE;\r
695 sca_timer_state[i] = SCA_TIMER_TIMEDOUT;\r
696#if (DEBUG_SCA & DEBUG_SCA_TIMERS)\r
697 printf("+ SCA_TIMER %d timed out\n", i);\r
698#endif\r
699\r
700 if (i == TIMER_035S && sca_timer_trigger) {\r
701 sca_timer_trigger = FALSE; /* uninhibit the other two timers */\r
702 sca_toggle_timer(TIMER_3S, msec_now);\r
703 sca_toggle_timer(TIMER_125S, msec_now);\r
704 }\r
705 }\r
706 }\r
707\r
708 if (timeout)\r
709 sca_interrupt(SCA_DSW_TIMEOUT);\r
710\r
711 any_timer_running = (sca_timer_state[0]| sca_timer_state[1] | sca_timer_state[2]) & SCA_TIMER_RUNNING;\r
712 }\r
713\r
714 if (sca_dsw & SCA_DSW_READY) { /* if connected */\r
715\r
716