This source file includes following definitions.
- rdr_init
- rdr_reset
- asciiToH
- asciiToHGCOS
- getCardLine
- getCardData
- getRawCardData
- getBinCardData
- rdrReadRecord
- submit
- scanForCards
- rdrProcessEvent
- rdrCardReady
- rdr_iom_cmd
- rdr_show_nunits
- rdr_set_nunits
- rdr_show_device_name
- rdr_set_device_name
- rdr_set_path
- rdr_show_path
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 #include <stdio.h>
33 #include <ctype.h>
34 #include <signal.h>
35 #include <stdlib.h>
36 #include <sys/types.h>
37 #include <dirent.h>
38 #include <unistd.h>
39 #include <errno.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include <stdint.h>
43
44 #include "dps8.h"
45 #include "dps8_iom.h"
46 #include "dps8_crdrdr.h"
47 #include "dps8_sys.h"
48 #include "dps8_cable.h"
49 #include "dps8_cpu.h"
50 #include "dps8_faults.h"
51 #include "dps8_scu.h"
52 #include "dps8_utils.h"
53
54 #if defined(NO_LOCALE)
55 # define xstrerror_l strerror
56 #endif
57
58 #define DBG_CTR 1
59 #define N_RDR_UNITS 1
60
61 #define snprintf_truncat(dst, size, ...) \
62 do \
63 { \
64 volatile size_t n = size; \
65 (void)snprintf (dst, n, __VA_ARGS__); \
66 } \
67 while (0)
68
69 static t_stat rdr_reset (DEVICE * dptr);
70 static t_stat rdr_show_nunits (FILE *st, UNIT *uptr, int val, const void *desc);
71 static t_stat rdr_set_nunits (UNIT * uptr, int32 value, const char * cptr, void * desc);
72 static t_stat rdr_show_device_name (FILE *st, UNIT *uptr, int val, const void *desc);
73 static t_stat rdr_set_device_name (UNIT * uptr, int32 value, const char * cptr, void * desc);
74 static t_stat rdr_show_path (UNUSED FILE * st, UNIT * uptr, UNUSED int val,
75 UNUSED const void * desc);
76 static t_stat rdr_set_path (UNUSED UNIT * uptr, UNUSED int32 value, const UNUSED char * cptr,
77 UNUSED void * desc);
78
79 #define UNIT_FLAGS ( UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | \
80 UNIT_IDLE )
81 UNIT rdr_unit [N_RDR_UNITS_MAX] =
82 {
83 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
84 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
85 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
86 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
87 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
88 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
89 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
90 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
91 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
92 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
93 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
94 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
95 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
96 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
97 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
98 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL}
99 };
100
101 #define RDR_UNIT_NUM(uptr) ((uptr) - rdr_unit)
102
103 static DEBTAB rdr_dt [] =
104 {
105 { "NOTIFY", DBG_NOTIFY, NULL },
106 { "INFO", DBG_INFO, NULL },
107 { "ERR", DBG_ERR, NULL },
108 { "WARN", DBG_WARN, NULL },
109 { "DEBUG", DBG_DEBUG, NULL },
110 { "ALL", DBG_ALL, NULL },
111 { NULL, 0, NULL }
112 };
113
114 #define UNIT_WATCH UNIT_V_UF
115
116 static MTAB rdr_mod [] =
117 {
118 #if !defined(SPEED)
119 { UNIT_WATCH, 1, "WATCH", "WATCH", 0, 0, NULL, NULL },
120 { UNIT_WATCH, 0, "NOWATCH", "NOWATCH", 0, 0, NULL, NULL },
121 #endif
122 {
123 MTAB_XTD | MTAB_VDV | \
124 MTAB_NMO | MTAB_VALR,
125 0,
126 "NUNITS",
127 "NUNITS",
128 rdr_set_nunits,
129 rdr_show_nunits,
130 "Number of RDR units in the system",
131 NULL
132 },
133 {
134 MTAB_XTD | MTAB_VUN | \
135 MTAB_VALR | MTAB_NC,
136 0,
137 "NAME",
138 "NAME",
139 rdr_set_device_name,
140 rdr_show_device_name,
141 "Select the boot drive",
142 NULL
143 },
144 {
145 MTAB_XTD | MTAB_VDV | MTAB_NMO | \
146 MTAB_VALR | MTAB_NC,
147 0,
148 "PATH",
149 "PATH",
150 rdr_set_path,
151 rdr_show_path,
152 "Path to card reader directories",
153 NULL
154 },
155
156 { 0, 0, NULL, NULL, 0, 0, NULL, NULL }
157 };
158
159 DEVICE rdr_dev = {
160 "RDR",
161 rdr_unit,
162 NULL,
163 rdr_mod,
164 N_RDR_UNITS,
165 10,
166 24,
167 1,
168 8,
169 36,
170 NULL,
171 NULL,
172 rdr_reset,
173 NULL,
174 NULL,
175 NULL,
176 NULL,
177 DEV_DEBUG,
178 0,
179 rdr_dt,
180 NULL,
181 NULL,
182 NULL,
183 NULL,
184 NULL,
185 NULL,
186 NULL
187 };
188
189 enum deckFormat { sevenDeck, cardDeck, streamDeck, xDeck, gDeck, bDeck };
190
191
192
193
194
195 static struct rdr_state
196 {
197 enum rdr_mode
198 {
199 rdr_no_mode, rdr_rd_bin
200 } io_mode;
201 int deckfd;
202
203
204 enum { deckStart = 0, eof1Sent, uid1Sent, inputSent, eof2Sent} deckState;
205 enum deckFormat deckFormat;
206 bool running;
207 char device_name [MAX_DEV_NAME_LEN];
208 char fname [PATH_MAX+1];
209 } rdr_state [N_RDR_UNITS_MAX];
210
211 static char* rdr_name = "rdr";
212 static char rdr_path_prefix[PATH_MAX+1];
213
214
215
216
217
218
219
220 void rdr_init (void)
221 {
222 (void)memset (rdr_path_prefix, 0, sizeof (rdr_path_prefix));
223 (void)memset (rdr_state, 0, sizeof (rdr_state));
224 for (uint i = 0; i < N_RDR_UNITS_MAX; i ++)
225 rdr_state [i] . deckfd = -1;
226 }
227
228 static t_stat rdr_reset (UNUSED DEVICE * dptr)
229 {
230
231
232
233
234
235
236
237 return SCPE_OK;
238 }
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362 static uint16 table [128] =
363 {
364 05403, 04401, 04201, 04101, 00005, 01023, 01013, 01007,
365 02011, 04021, 02021, 04103, 04043, 04023, 04013, 04007,
366 06403, 02401, 02201, 02101, 00043, 00023, 00201, 01011,
367 02003, 02403, 00007, 01005, 02043, 02023, 02013, 02007,
368 00000, 02202, 00006, 00102, 02102, 01042, 04000, 00022,
369 04022, 02022, 02042, 04012, 01102, 02000, 04102, 01400,
370 01000, 00400, 00200, 00100, 00040, 00020, 00010, 00004,
371 00002, 00001, 00202, 02012, 04042, 00012, 01012, 01006,
372 00042, 04400, 04200, 04100, 04040, 04020, 04010, 04004,
373 04002, 04001, 02400, 02200, 02100, 02040, 02020, 02010,
374 02004, 02002, 02001, 01200, 01100, 01040, 01020, 01010,
375 01004, 01002, 01001, 05022, 04202, 06022, 02006, 01022,
376 00402, 05400, 05200, 05100, 05040, 05020, 05010, 05004,
377 05002, 05001, 06400, 06200, 06100, 06040, 06020, 06010,
378 06004, 06002, 06001, 03200, 03100, 03040, 03020, 03010,
379 03004, 03002, 03001, 05000, 04006, 03000, 03400, 00000
380 };
381
382 static uint16 gcos_table [128] =
383 {
384 05403, 04401, 04201, 04101, 00005, 01023, 01013, 01007,
385 02011, 04021, 02021, 04103, 04043, 04023, 04013, 04007,
386 06403, 02401, 02201, 02101, 00043, 00023, 00201, 01011,
387 02003, 02403, 00007, 01005, 02043, 02023, 02013, 02007,
388 00000, 01006, 01012, 00102, 02102, 01042, 04000, 02006,
389 04022, 02022, 02042, 05000, 01102, 02000, 04102, 01400,
390 01000, 00400, 00200, 00100, 00040, 00020, 00010, 00004,
391 00002, 00001, 00022, 02012, 04012, 01022, 00012, 00006,
392 00042, 04400, 04200, 04100, 04040, 04020, 04010, 04004,
393 04002, 04001, 02400, 02200, 02100, 02040, 02020, 02010,
394 02004, 02002, 02001, 01200, 01100, 01040, 01020, 01010,
395 01004, 01002, 01001, 00202, 04006, 04042, 03000, 01202,
396 00402, 05400, 05200, 05100, 05040, 05020, 05010, 05004,
397 05002, 05001, 06400, 06200, 06100, 06040, 06020, 06010,
398 06004, 06002, 06001, 03200, 03100, 03040, 03020, 03010,
399 03004, 03002, 03001, 05000, 04006, 03000, 03400, 00000
400 };
401
402 static void asciiToH (char * str, uint * hstr, size_t l)
403 {
404 char * p = str;
405 for (size_t i = 0; i < l; i ++)
406
407 {
408 * hstr ++ = table [(* p) & 0177];
409 p ++;
410 }
411 }
412
413 static void asciiToHGCOS (char * str, uint * hstr, size_t l)
414 {
415 char * p = str;
416 for (size_t i = 0; i < l; i ++)
417
418 {
419 * hstr ++ = gcos_table [(* p) & 0177];
420 p ++;
421 }
422 }
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452 static int getCardLine (int fd, unsigned char * buffer)
453 {
454 uint n = 0;
455 buffer [n] = 0;
456 while (1)
457 {
458 uint8 ch;
459 ssize_t rc = read (fd, & ch, 1);
460 if (rc <= 0)
461 return n == 0;
462 if (ch == '\n')
463 return 0;
464 buffer [n ++] = ch;
465 buffer [n] = 0;
466 if (n > 79)
467 return 0;
468 }
469 #if defined(SUNLINT) || !defined(__SUNPRO_C) && !defined(__SUNPRO_CC)
470
471 return 0;
472 #endif
473 }
474
475 static int getCardData (int fd, char * buffer)
476 {
477 (void)memset (buffer, 0, 80);
478 ssize_t rc = read (fd, buffer, 80);
479 if (rc < 0)
480 return 0;
481 return (int) rc;
482 }
483
484 #define rawCardImageBytes (80 * 12 / 8)
485 static int getRawCardData (int fd, uint8_t * buffer)
486 {
487 (void)memset (buffer, 0, rawCardImageBytes + 2);
488 ssize_t rc = read (fd, buffer, rawCardImageBytes);
489 if (rc < 0)
490 return 0;
491 return (int) rc;
492 }
493
494 #define CARD_COL_COUNT 80
495 #define NIBBLES_PER_COL 3
496 #define NIBBLES_PER_CARD (CARD_COL_COUNT * NIBBLES_PER_COL)
497 #define BYTES_PER_CARD (NIBBLES_PER_CARD / 2)
498
499 typedef struct
500 {
501 word12 column[CARD_COL_COUNT];
502 } card_image_t;
503
504 card_image_t card;
505
506 static int getBinCardData (int fd, card_image_t* card)
507 {
508 uint8 byte_buffer[BYTES_PER_CARD];
509
510 ssize_t bytes_read = read (fd, byte_buffer, BYTES_PER_CARD);
511 if (bytes_read <= 0)
512 return 0;
513
514 for (int col = 0; col < CARD_COL_COUNT; col++)
515 {
516 card->column[col] = 0;
517 }
518
519 for (int current_nibble = 0; current_nibble < NIBBLES_PER_CARD; current_nibble++)
520 {
521 int byte_offset = current_nibble / 2;
522 int nibble_offset = (2 - (current_nibble % 3)) * 4;
523 int col = current_nibble / 3;
524
525 word12 nibble = (current_nibble & 0x1) ? byte_buffer[byte_offset] : (byte_buffer[byte_offset] >> 4);
526 nibble &= 0x00000F;
527 card->column[col] |= (nibble << nibble_offset);
528 }
529
530 return (int) bytes_read;
531 }
532
533 #if defined(TESTING)
534 static bool empty = false;
535 #endif
536
537 static int rdrReadRecord (uint iomUnitIdx, uint chan) {
538 #if defined(TESTING)
539 cpu_state_t * cpup = _cpup;
540 (void)cpup;
541 #endif
542 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
543
544 uint ctlr_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
545 uint unitIdx = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563 #if defined(TESTING)
564 sim_printf ("hopper not empty\r\n");
565 empty = false;
566 #endif
567 unsigned char cardImage [80] = "";
568 uint8_t rawCardImage [rawCardImageBytes + 2 ];
569 size_t l = 0;
570
571 enum deckFormat thisCard = cardDeck;
572
573 static int jobNo = 0;
574
575 switch (rdr_state [unitIdx].deckState) {
576 case deckStart: {
577 #if defined(TESTING)
578 sim_printf ("deckStart: sending ++EOF\r\n");
579 #endif
580 strcpy ((char *) cardImage, "++EOF");
581 l = strlen ((char *) cardImage);
582 thisCard = cardDeck;
583 rdr_state [unitIdx].deckState = eof1Sent;
584 jobNo ++;
585 }
586 break;
587
588 case eof1Sent: {
589 #if defined(TESTING)
590 sim_printf ("eof1Sent: sending ++UID\r\n");
591 #endif
592 (void)sprintf ((char *) cardImage, "++UID %d", jobNo);
593 l = strlen ((char *) cardImage);
594 thisCard = cardDeck;
595 rdr_state [unitIdx].deckState = uid1Sent;
596 }
597 break;
598
599 case uid1Sent: {
600 #if defined(TESTING)
601 sim_printf ("uid1Sent: sending data\r\n");
602 #endif
603 int rc = getCardLine (rdr_state [unitIdx].deckfd, cardImage);
604 if (rc) {
605 #if defined(TESTING)
606 sim_printf ("uid1Sent: getCardLine returned %d\r\n", rc);
607 #endif
608 close (rdr_state [unitIdx].deckfd);
609
610 rc = unlink (rdr_state [unitIdx].fname);
611 if (rc)
612 (void)sir_error ("crdrdr: Failure unlinking card reader deck: %s (Error %d)", xstrerror_l (errno), errno);
613 rdr_state [unitIdx].deckfd = -1;
614 rdr_state [unitIdx].deckState = deckStart;
615 p->stati = 04201;
616
617
618 p->initiate = true;
619 return IOM_CMD_DISCONNECT;
620 }
621 #if defined(TESTING)
622 sim_printf ("uid1Sent: getCardLine returned <%s>\r\n", cardImage);
623 #endif
624 l = strlen ((char *) cardImage);
625 thisCard = cardDeck;
626 if (strncasecmp ((char *) cardImage, "++input", 7) == 0) {
627 #if defined(TESTING)
628 sim_printf ("uid1Sent: switching to inputSent <%s>\r\n", cardImage);
629 #endif
630 rdr_state [unitIdx].deckState = inputSent;
631 }
632 }
633 break;
634
635
636
637 case inputSent: {
638 #if defined(TESTING)
639 sim_printf ("inputSent: format %d\r\n", rdr_state [unitIdx].deckFormat);
640 #endif
641 switch (rdr_state [unitIdx].deckFormat) {
642 case xDeck:
643 case gDeck: {
644 #if defined(TESTING)
645 sim_printf ("inputSent: xDeck or gDeck\r\n");
646 #endif
647 int rc = getCardLine (rdr_state [unitIdx].deckfd, cardImage);
648 if (rc) {
649 rdr_state [unitIdx].deckState = deckStart;
650 close (rdr_state [unitIdx].deckfd);
651
652 int rc = unlink (rdr_state [unitIdx].fname);
653 if (rc)
654 (void)sir_error ("crdrdr: Failure unlinking card reader deck: %s (Error %d)", xstrerror_l (errno), errno);
655 rdr_state [unitIdx].deckfd = -1;
656 p->stati = 04201;
657
658
659 p->initiate = true;
660 return IOM_CMD_DISCONNECT;
661 }
662 l = strlen ((char *) cardImage);
663 }
664 thisCard = cardDeck;
665 break;
666
667 case cardDeck: {
668 #if defined(TESTING)
669 sim_printf ("inputSent: cardDeck\r\n");
670 #endif
671 int rc = getCardLine (rdr_state [unitIdx].deckfd, cardImage);
672 if (rc) {
673 strcpy ((char *) cardImage, "++EOF");
674 rdr_state [unitIdx].deckState = eof2Sent;
675 }
676 l = strlen ((char *) cardImage);
677 }
678 thisCard = cardDeck;
679 break;
680
681 case streamDeck: {
682 #if defined(TESTING)
683 sim_printf ("inputSent: streamDeck\r\n");
684 #endif
685 l = (size_t) getCardData (rdr_state [unitIdx].deckfd, (char *) cardImage);
686 if (l) {
687 thisCard = streamDeck;
688 } else {
689 strcpy ((char *) cardImage, "++EOF");
690 l = strlen ((char *) cardImage);
691 rdr_state [unitIdx].deckState = eof2Sent;
692 thisCard = cardDeck;
693 }
694 #if defined(TESTING)
695 sim_printf ("inputSent: getCardLine returned <%s>\r\n", cardImage);
696 #endif
697 }
698 break;
699
700 case bDeck:
701 #if defined(TESTING)
702 sim_printf ("inputSent: bDeck\r\n");
703 #endif
704 l = (size_t) getBinCardData (rdr_state [unitIdx].deckfd, &card);
705 if (l) {
706 thisCard = bDeck;
707 } else {
708 rdr_state [unitIdx].deckState = deckStart;
709 close (rdr_state [unitIdx].deckfd);
710
711 int rc = unlink (rdr_state [unitIdx].fname);
712 if (rc)
713 (void)sir_error ("crdrdr: Failure unlinking card reader deck: %s (Error %d)", xstrerror_l (errno), errno);
714 rdr_state [unitIdx].deckfd = -1;
715 p->stati = 04201;
716
717
718 p->initiate = true;
719 return IOM_CMD_DISCONNECT;
720 }
721 break;
722
723 case sevenDeck: {
724 #if defined(TESTING)
725 sim_printf ("inputSent: 7Deck\r\n");
726 #endif
727 l = (size_t) getRawCardData (rdr_state [unitIdx].deckfd, rawCardImage);
728 if (l) {
729 thisCard = sevenDeck;
730 } else {
731 strcpy ((char *) cardImage, "++EOF");
732 l = strlen ((char *) cardImage);
733 rdr_state [unitIdx].deckState = eof2Sent;
734 thisCard = cardDeck;
735 }
736 }
737 break;
738
739 }
740 }
741 break;
742
743
744
745 case eof2Sent: {
746 # if defined(TESTING)
747 sim_printf ("eof2Sent\r\n");
748 # endif
749 (void)sprintf ((char *) cardImage, "++UID %d", jobNo);
750 l = strlen ((char *) cardImage);
751 thisCard = cardDeck;
752 rdr_state [unitIdx].deckState = deckStart;
753 close (rdr_state [unitIdx].deckfd);
754
755 int rc = unlink (rdr_state [unitIdx].fname);
756 if (rc)
757 (void)sir_error ("crdrdr: Failure unlinking card reader deck: %s (Error %d)", xstrerror_l (errno), errno);
758 rdr_state [unitIdx].deckfd = -1;
759 }
760 break;
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790 }
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811 word36 buffer [27];
812 switch (thisCard) {
813 case bDeck: {
814
815 uint l = 80;
816
817 uint nbits = (uint) l * 12;
818
819 uint tally = (nbits + 35) / 36;
820
821 if (tally > 27) {
822 sim_warn ("Impossible rdr tally: %d > 27; truncating.\r\n", tally);
823 tally = 27;
824 }
825
826
827
828 (void)memset (buffer, 0, sizeof (buffer));
829 for (uint col = 0; col < l; col ++) {
830 uint wordno = col / 3;
831 uint fieldno = col % 3;
832 putbits36_12 (& buffer [wordno], fieldno * 12, (word12) card.column [col]);
833 }
834 }
835 break;
836 case sevenDeck: {
837
838
839 for (uint i = 0; i < 27; i ++)
840 buffer [i] = extr36 ((uint8 *) rawCardImage, i);
841
842
843 }
844 break;
845
846 case streamDeck:
847
848
849
850
851
852
853
854
855
856
857 case xDeck:
858 case gDeck:
859 case cardDeck: {
860 if (l > 80) {
861 sim_warn ("Whups. rdr l %lu > 80; truncating.\r\n", (unsigned long)l);
862 l = 80;
863
864 }
865
866 uint hbuf [l + 1];
867
868 if (rdr_state [unitIdx].deckFormat == gDeck) {
869 asciiToHGCOS ((char *) cardImage, hbuf, l);
870 }
871 else {
872 asciiToH ((char *) cardImage, hbuf, l);
873 }
874
875
876 uint nbits = (uint) l * 12;
877
878 uint tally = (nbits + 35) / 36;
879
880 if (tally > 27) {
881 sim_warn ("Impossible rdr tally: %d > 27; truncating.\r\n", tally);
882 tally = 27;
883 }
884
885
886
887 (void)memset (buffer, 0, sizeof (buffer));
888 for (uint col = 0; col < l; col ++) {
889 uint wordno = col / 3;
890 uint fieldno = col % 3;
891 putbits36_12 (& buffer [wordno], fieldno * 12, (word12) hbuf [col]);
892 }
893 }
894 break;
895 }
896
897
898
899
900
901
902
903
904
905
906
907 p->stati = 04000;
908
909
910 uint tally = 27;
911
912 iom_indirect_data_service (iomUnitIdx, chan, buffer, & tally, true);
913 p->initiate = false;
914 p->stati = 04000;
915 p->tallyResidue = (word12) tally & MASK12;
916 p->charPos = 0;
917
918 return IOM_CMD_PROCEED;
919 }
920
921 static void submit (enum deckFormat fmt, char * fname, uint16 readerIndex)
922 {
923 if (readerIndex >= N_RDR_UNITS_MAX) {
924 sim_warn("crdrdr: submit called with invalid reader index %ld\r\n", (long) readerIndex);
925 return;
926 }
927
928 int deckfd = open (fname, O_RDONLY);
929 if (deckfd < 0)
930 (void)sir_error ("crdrdr: Failure opening card reader deck: %s (Error %d)", xstrerror_l (errno), errno);
931
932
933 #if defined(TESTING)
934 sim_printf ("submit %s\r\n", fname);
935 #endif
936 #if defined(__GNUC__)
937 # if !defined(__clang_version__)
938 # if __GNUC__ > 7
939 # if !defined(__INTEL_COMPILER)
940 # pragma GCC diagnostic push
941 # pragma GCC diagnostic ignored "-Wstringop-truncation"
942 # endif
943 # endif
944 # endif
945 #endif
946 strncpy (rdr_state [readerIndex].fname, fname, sizeof(rdr_state [readerIndex].fname) - 1);
947 rdr_state [readerIndex].fname [sizeof(rdr_state [readerIndex].fname) - 1] = '\0';
948 #if defined(__GNUC__)
949 # if !defined(__clang_version__)
950 # if __GNUC__ > 7
951 # if !defined(__INTEL_COMPILER)
952 # pragma GCC diagnostic pop
953 # endif
954 # endif
955 # endif
956 #endif
957 rdr_state [readerIndex].deckfd = deckfd;
958 rdr_state [readerIndex].deckState = deckStart;
959 rdr_state [readerIndex].deckFormat = fmt;
960 if (fmt == xDeck || fmt == gDeck || fmt == bDeck) {
961 rdr_state [readerIndex].deckState = inputSent;
962 }
963 if (deckfd >= 0)
964 rdrCardReady (readerIndex);
965 }
966
967 static void scanForCards(uint16 readerIndex)
968 {
969 char rdr_dir [2 * PATH_MAX + 8];
970
971 if (readerIndex >= N_RDR_UNITS_MAX)
972 {
973 (void)sir_error ("crdrdr: scanForCards called with invalid reader index %d", readerIndex);
974 return;
975 }
976
977 #if !defined(__MINGW64__) || !defined(__MINGW32__)
978 const char* r_tmpdir = getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp";
979 #else
980 const char* r_tmpdir = getenv("TEMP") ? getenv("TEMP") : \
981 getenv("TMP") ? getenv("TMP") : ".";
982 #endif
983 snprintf_truncat(rdr_dir, PATH_MAX + 1, "%s/%s%c",
984 r_tmpdir, rdr_name, 'a' + readerIndex);
985
986 if (rdr_path_prefix [0])
987 {
988 snprintf_truncat(rdr_dir, PATH_MAX + 1, "%s%s%c",
989 rdr_path_prefix, rdr_name, 'a' + readerIndex);
990 }
991
992 DIR * dp;
993 dp = opendir (rdr_dir);
994 if (! dp)
995 {
996 if (errno == ENOENT)
997 {
998 (void)sir_notice ("crdrdr: Punch reader %s%c input directory '%s' not found; creating it.",
999 rdr_name, 'a' + readerIndex, rdr_dir);
1000 if (x_mkdir_p (rdr_dir) == -1)
1001 {
1002 (void)sir_error ("crdrdr: Failure creating punch reader %s%c input directory '%s': %s (Error %d)",
1003 rdr_name, 'a' + readerIndex, rdr_dir, xstrerror_l (errno), errno);
1004 return;
1005 }
1006 }
1007
1008 dp = opendir (rdr_dir);
1009 if (! dp)
1010 {
1011 (void)sir_error ("crdrdr: Failure opening punch reader %s%c input directory '%s': %s (Error %d)",
1012 rdr_name, 'a' + readerIndex, rdr_dir, xstrerror_l (errno), errno);
1013 return;
1014 }
1015 }
1016
1017 struct dirent * entry;
1018 struct stat info;
1019 char fqname [2 * PATH_MAX + 8];
1020 while ((entry = readdir (dp)))
1021 {
1022 strcpy (fqname, rdr_dir);
1023 strcat (fqname, "/");
1024 strcat (fqname, entry -> d_name);
1025
1026 if (stat(fqname, &info) != 0)
1027 {
1028 (void)sir_error ("crdrdr: scanForCards stat() failure for %s: %s (Error %d)",
1029 fqname, xstrerror_l(errno), errno);
1030 continue;
1031 }
1032
1033 if (S_ISDIR(info.st_mode))
1034 {
1035
1036 continue;
1037 }
1038
1039 if (rdr_state [readerIndex] . deckfd < 0)
1040 {
1041 if (strncmp (entry -> d_name, "xdeck.", 6) == 0)
1042 {
1043 submit (xDeck, fqname, readerIndex);
1044 break;
1045 }
1046 if (strncmp (entry -> d_name, "gdeck.", 6) == 0)
1047 {
1048 submit (gDeck, fqname, readerIndex);
1049 break;
1050 }
1051 if (strncmp (entry -> d_name, "cdeck.", 6) == 0)
1052 {
1053 submit (cardDeck, fqname, readerIndex);
1054 break;
1055 }
1056 if (strncmp (entry -> d_name, "7deck.", 6) == 0)
1057 {
1058 submit (sevenDeck, fqname, readerIndex);
1059 break;
1060 }
1061 if (strncmp (entry -> d_name, "sdeck.", 6) == 0)
1062 {
1063 submit (streamDeck, fqname, readerIndex);
1064 break;
1065 }
1066 if (strncmp (entry -> d_name, "bdeck.", 6) == 0)
1067 {
1068 submit (bDeck, fqname, readerIndex);
1069 break;
1070 }
1071 }
1072 if (strcmp (entry -> d_name, "discard") == 0)
1073 {
1074
1075 int rc = unlink (fqname);
1076 if (rc)
1077 (void)sir_error ("crdrdr: Failure unlinking card reader deck: %s (Error %d)", xstrerror_l (errno), errno);
1078 if (rdr_state [readerIndex] . deckfd >= 0)
1079 {
1080 close (rdr_state [readerIndex] . deckfd);
1081 rc = unlink (rdr_state [readerIndex] . fname);
1082 if (rc)
1083 (void)sir_error ("crdrdr: Failure unlinking card reader deck: %s (Error %d)", xstrerror_l (errno), errno);
1084 rdr_state [readerIndex] . deckfd = -1;
1085 rdr_state [readerIndex] . deckState = deckStart;
1086 break;
1087 }
1088 }
1089 }
1090 closedir (dp);
1091 }
1092
1093 void rdrProcessEvent (void)
1094 {
1095 if (rdr_path_prefix [0])
1096 {
1097
1098
1099 for (uint16 reader_idx = 0; reader_idx < rdr_dev . numunits; reader_idx++)
1100 {
1101 if (rdr_state [reader_idx] . running)
1102 scanForCards(reader_idx);
1103 }
1104 }
1105 else
1106 {
1107
1108
1109 if (! rdr_state [0] . running)
1110 return;
1111
1112 scanForCards(0);
1113 }
1114 }
1115
1116 void rdrCardReady (int unitNum)
1117 {
1118 uint ctlr_unit_idx = cables->rdr_to_urp [unitNum].ctlr_unit_idx;
1119 uint ctlr_port_num = 0;
1120 uint iom_unit_idx = cables->urp_to_iom[ctlr_unit_idx][ctlr_port_num].iom_unit_idx;
1121 uint chan_num = cables->urp_to_iom[ctlr_unit_idx][ctlr_port_num].chan_num;
1122 uint dev_code = cables->rdr_to_urp[unitNum].dev_code;
1123 send_special_interrupt (iom_unit_idx, chan_num, dev_code, 0377, 0377 );
1124 }
1125
1126 iom_cmd_rc_t rdr_iom_cmd (uint iomUnitIdx, uint chan) {
1127 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
1128 #if defined(xTESTING)
1129 uint dev_code = p->IDCW_DEV_CODE;
1130 cpu_state_t * cpup = _cpup;
1131
1132
1133
1134 #endif
1135
1136 uint ctlr_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
1137 uint unitIdx = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
1138 struct rdr_state * statep = & rdr_state[unitIdx];
1139 statep->running = true;
1140
1141 iom_cmd_rc_t rc = IOM_CMD_PROCEED;
1142
1143 if (IS_IDCW (p)) {
1144
1145 statep->io_mode = rdr_no_mode;
1146
1147 switch (p->IDCW_DEV_CMD) {
1148 case 000:
1149
1150 p->stati = 04000;
1151
1152
1153
1154 #if defined(TESTING)
1155 sim_printf ("Request status %04o\r\n", p->stati);
1156 #endif
1157 break;
1158
1159 case 001:
1160
1161 if (rdr_state [unitIdx].deckfd < 0) {
1162 p->stati = 04201;
1163 p->tallyResidue = 0;
1164 #if defined(TESTING)
1165 if (! empty)
1166 sim_printf ("hopper empty\r\n");
1167 empty = true;
1168 #endif
1169 return IOM_CMD_DISCONNECT;
1170 }
1171 statep->io_mode = rdr_rd_bin;
1172 p->stati = 04000;
1173
1174
1175
1176 #if defined(TESTING)
1177 sim_printf ("read binary %04o\r\n", p->stati);
1178 #endif
1179 break;
1180
1181 case 040:
1182
1183 p->stati = 04000;
1184 p->isRead = false;
1185
1186
1187
1188 #if defined(TESTING)
1189 sim_printf ("reset status %04o\r\n", p->stati);
1190 #endif
1191 break;
1192
1193 default:
1194 #if defined(TESTING)
1195 sim_printf ("unknown %o\r\n", p->IDCW_DEV_CMD);
1196 #endif
1197
1198
1199
1200 if (p->IDCW_DEV_CMD != 051 && ! (tandd_io_mode () && p->IDCW_DEV_CMD == 030))
1201 sim_warn ("%s: RDR unrecognized device command %02o\r\n", __func__, p->IDCW_DEV_CMD);
1202 p->stati = 04501;
1203 p->chanStatus = chanStatIncorrectDCW;
1204 return IOM_CMD_ERROR;
1205 }
1206
1207
1208 return IOM_CMD_PROCEED;
1209 }
1210
1211
1212 switch (statep->io_mode) {
1213 case rdr_no_mode:
1214 #if defined(TESTING)
1215 sim_printf ("%s: Unexpected IOTx\r\n", __func__);
1216 #endif
1217
1218
1219 break;
1220
1221 case rdr_rd_bin: {
1222 int rc = rdrReadRecord (iomUnitIdx, chan);
1223 #if defined(TESTING)
1224 sim_printf ("rdrReadRecord returned %d\r\n", rc);
1225 #endif
1226 if (rc)
1227 return IOM_CMD_DISCONNECT;
1228 }
1229 break;
1230
1231 default:
1232 sim_warn ("%s: Unrecognized io_mode %d\r\n", __func__, statep->io_mode);
1233 return IOM_CMD_ERROR;
1234 }
1235 return rc;
1236 }
1237
1238 static t_stat rdr_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr, UNUSED int val,
1239 UNUSED const void * desc)
1240 {
1241 sim_printf("Number of RDR units in system is %d\r\n", rdr_dev . numunits);
1242 return SCPE_OK;
1243 }
1244
1245 static t_stat rdr_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value, const char * cptr,
1246 UNUSED void * desc)
1247 {
1248 if (! cptr)
1249 return SCPE_ARG;
1250 int n = atoi (cptr);
1251 if (n < 1 || n > N_RDR_UNITS_MAX)
1252 return SCPE_ARG;
1253 rdr_dev . numunits = (uint32) n;
1254 return SCPE_OK;
1255 }
1256
1257 static t_stat rdr_show_device_name (UNUSED FILE * st, UNIT * uptr,
1258 UNUSED int val, UNUSED const void * desc)
1259 {
1260 long n = RDR_UNIT_NUM (uptr);
1261 if (n < 0 || n >= N_RDR_UNITS_MAX)
1262 return SCPE_ARG;
1263 sim_printf("name : %s", rdr_state [n] . device_name);
1264 return SCPE_OK;
1265 }
1266
1267 static t_stat rdr_set_device_name (UNUSED UNIT * uptr, UNUSED int32 value,
1268 UNUSED const char * cptr, UNUSED void * desc)
1269 {
1270 long n = RDR_UNIT_NUM (uptr);
1271 if (n < 0 || n >= N_RDR_UNITS_MAX)
1272 return SCPE_ARG;
1273 if (cptr)
1274 {
1275 strncpy (rdr_state [n] . device_name, cptr, MAX_DEV_NAME_LEN - 1);
1276 rdr_state [n] . device_name [MAX_DEV_NAME_LEN - 1] = 0;
1277 }
1278 else
1279 rdr_state [n] . device_name [0] = 0;
1280 return SCPE_OK;
1281 }
1282
1283 static t_stat rdr_set_path (UNUSED UNIT * uptr, UNUSED int32 value,
1284 const UNUSED char * cptr, UNUSED void * desc)
1285 {
1286 if (! cptr)
1287 return SCPE_ARG;
1288
1289 size_t len = strlen(cptr);
1290
1291
1292
1293 if (len >= (sizeof(rdr_path_prefix) - (strlen(rdr_name) + 3)))
1294 return SCPE_ARG;
1295
1296 strncpy(rdr_path_prefix, cptr, sizeof(rdr_path_prefix) -1);
1297 rdr_path_prefix[sizeof(rdr_path_prefix) - 1] = '\0';
1298 if (len > 0)
1299 {
1300 if (rdr_path_prefix[len - 1] != '/')
1301 {
1302 if (len == sizeof(rdr_path_prefix) - 1)
1303 return SCPE_ARG;
1304 rdr_path_prefix[len++] = '/';
1305 rdr_path_prefix[len] = 0;
1306 }
1307 }
1308 return SCPE_OK;
1309 }
1310
1311 static t_stat rdr_show_path (UNUSED FILE * st, UNUSED UNIT * uptr,
1312 UNUSED int val, UNUSED const void * desc)
1313 {
1314 if (rdr_path_prefix [0])
1315 {
1316 sim_printf("\rPath to card reader directories is \"%s\".\r\n", rdr_path_prefix);
1317 }
1318 else
1319 {
1320 sim_printf("\rPath to card reader directories is unset.\r\n");
1321 }
1322 return SCPE_OK;
1323 }