This source file includes following definitions.
- rdr_init
- rdr_reset
- asciiToH
- getCardLine
- getCardData
- getRawCardData
- 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
33
34
35 #include <stdio.h>
36 #include <ctype.h>
37 #include <signal.h>
38 #include <stdlib.h>
39 #include <sys/types.h>
40 #include <dirent.h>
41 #include <unistd.h>
42 #include <errno.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <stdint.h>
46
47 #include "dps8.h"
48 #include "dps8_iom.h"
49 #include "dps8_crdrdr.h"
50 #include "dps8_sys.h"
51 #include "dps8_faults.h"
52 #include "dps8_scu.h"
53 #include "dps8_cable.h"
54 #include "dps8_cpu.h"
55 #include "dps8_utils.h"
56
57 #define DBG_CTR 1
58 #define N_RDR_UNITS 1
59
60 #define snprintf_truncat(dst, size, ...) \
61 do \
62 { \
63 volatile size_t n = size; \
64 (void)snprintf (dst, n, __VA_ARGS__); \
65 } \
66 while (0)
67
68 static t_stat rdr_reset (DEVICE * dptr);
69 static t_stat rdr_show_nunits (FILE *st, UNIT *uptr, int val, const void *desc);
70 static t_stat rdr_set_nunits (UNIT * uptr, int32 value, const char * cptr, void * desc);
71 static t_stat rdr_show_device_name (FILE *st, UNIT *uptr, int val, const void *desc);
72 static t_stat rdr_set_device_name (UNIT * uptr, int32 value, const char * cptr, void * desc);
73 static t_stat rdr_show_path (UNUSED FILE * st, UNIT * uptr, UNUSED int val,
74 UNUSED const void * desc);
75 static t_stat rdr_set_path (UNUSED UNIT * uptr, UNUSED int32 value, const UNUSED char * cptr,
76 UNUSED void * desc);
77
78 #define UNIT_FLAGS ( UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | \
79 UNIT_IDLE )
80 UNIT rdr_unit [N_RDR_UNITS_MAX] =
81 {
82 {UDATA (NULL, UNIT_FLAGS, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL},
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 };
99
100 #define RDR_UNIT_NUM(uptr) ((uptr) - rdr_unit)
101
102 static DEBTAB rdr_dt [] =
103 {
104 { "NOTIFY", DBG_NOTIFY, NULL },
105 { "INFO", DBG_INFO, NULL },
106 { "ERR", DBG_ERR, NULL },
107 { "WARN", DBG_WARN, NULL },
108 { "DEBUG", DBG_DEBUG, NULL },
109 { "ALL", DBG_ALL, NULL },
110 { NULL, 0, NULL }
111 };
112
113 #define UNIT_WATCH UNIT_V_UF
114
115 static MTAB rdr_mod [] =
116 {
117 #ifndef SPEED
118 { UNIT_WATCH, 1, "WATCH", "WATCH", 0, 0, NULL, NULL },
119 { UNIT_WATCH, 0, "NOWATCH", "NOWATCH", 0, 0, NULL, NULL },
120 #endif
121 {
122 MTAB_XTD | MTAB_VDV | \
123 MTAB_NMO | MTAB_VALR,
124 0,
125 "NUNITS",
126 "NUNITS",
127 rdr_set_nunits,
128 rdr_show_nunits,
129 "Number of RDR units in the system",
130 NULL
131 },
132 {
133 MTAB_XTD | MTAB_VUN | \
134 MTAB_VALR | MTAB_NC,
135 0,
136 "NAME",
137 "NAME",
138 rdr_set_device_name,
139 rdr_show_device_name,
140 "Select the boot drive",
141 NULL
142 },
143 {
144 MTAB_XTD | MTAB_VDV | MTAB_NMO | \
145 MTAB_VALR | MTAB_NC,
146 0,
147 "PATH",
148 "PATH",
149 rdr_set_path,
150 rdr_show_path,
151 "Path to card reader directories",
152 NULL
153 },
154
155 { 0, 0, NULL, NULL, 0, 0, NULL, NULL }
156 };
157
158 DEVICE rdr_dev = {
159 "RDR",
160 rdr_unit,
161 NULL,
162 rdr_mod,
163 N_RDR_UNITS,
164 10,
165 24,
166 1,
167 8,
168 36,
169 NULL,
170 NULL,
171 rdr_reset,
172 NULL,
173 NULL,
174 NULL,
175 NULL,
176 DEV_DEBUG,
177 0,
178 rdr_dt,
179 NULL,
180 NULL,
181 NULL,
182 NULL,
183 NULL,
184 NULL,
185 NULL
186 };
187
188 enum deckFormat { sevenDeck, cardDeck, streamDeck };
189
190
191
192
193
194 static struct rdr_state
195 {
196 enum rdr_mode
197 {
198 rdr_no_mode, rdr_rd_bin
199 } io_mode;
200 int deckfd;
201
202
203 enum { deckStart = 0, eof1Sent, uid1Sent, inputSent, eof2Sent} deckState;
204 enum deckFormat deckFormat;
205 bool running;
206 char device_name [MAX_DEV_NAME_LEN];
207 char fname [PATH_MAX+1];
208 } rdr_state [N_RDR_UNITS_MAX];
209
210 static char* rdr_name = "rdr";
211 static char rdr_path_prefix[PATH_MAX+1];
212
213
214
215
216
217
218
219 void rdr_init (void)
220 {
221 memset (rdr_path_prefix, 0, sizeof (rdr_path_prefix));
222 memset (rdr_state, 0, sizeof (rdr_state));
223 for (uint i = 0; i < N_RDR_UNITS_MAX; i ++)
224 rdr_state [i] . deckfd = -1;
225 }
226
227 static t_stat rdr_reset (UNUSED DEVICE * dptr)
228 {
229
230
231
232
233
234
235
236 return SCPE_OK;
237 }
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 static uint16 table [128] =
362 {
363 05403, 04401, 04201, 04101, 00005, 01023, 01013, 01007,
364 02011, 04021, 02021, 04103, 04043, 04023, 04013, 04007,
365 06403, 02401, 02201, 02101, 00043, 00023, 00201, 01011,
366 02003, 02403, 00007, 01005, 02043, 02023, 02013, 02007,
367 00000, 02202, 00006, 00102, 02102, 01042, 04000, 00022,
368 04022, 02022, 02042, 04012, 01102, 02000, 04102, 01400,
369 01000, 00400, 00200, 00100, 00040, 00020, 00010, 00004,
370 00002, 00001, 00202, 02012, 04042, 00012, 01012, 01006,
371 00042, 04400, 04200, 04100, 04040, 04020, 04010, 04004,
372 04002, 04001, 02400, 02200, 02100, 02040, 02020, 02010,
373 02004, 02002, 02001, 01200, 01100, 01040, 01020, 01010,
374 01004, 01002, 01001, 05022, 04202, 06022, 02006, 01022,
375 00402, 05400, 05200, 05100, 05040, 05020, 05010, 05004,
376 05002, 05001, 06400, 06200, 06100, 06040, 06020, 06010,
377 06004, 06002, 06001, 03200, 03100, 03040, 03020, 03010,
378 03004, 03002, 03001, 05000, 04006, 03000, 03400, 00000
379 };
380
381 static void asciiToH (char * str, uint * hstr, size_t l)
382 {
383 char * p = str;
384 for (size_t i = 0; i < l; i ++)
385
386 {
387 * hstr ++ = table [(* p) & 0177];
388 p ++;
389 }
390 }
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420 static int getCardLine (int fd, unsigned char * buffer)
421 {
422 uint n = 0;
423 buffer [n] = 0;
424 while (1)
425 {
426 uint8 ch;
427 ssize_t rc = read (fd, & ch, 1);
428 if (rc <= 0)
429 return n == 0;
430 if (ch == '\n')
431 return 0;
432 buffer [n ++] = ch;
433 buffer [n] = 0;
434 if (n > 79)
435 return 0;
436 }
437
438 return 0;
439 }
440
441 static int getCardData (int fd, char * buffer)
442 {
443 memset (buffer, 0, 80);
444 ssize_t rc = read (fd, buffer, 80);
445 if (rc < 0)
446 return 0;
447 return (int) rc;
448 }
449
450 #define rawCardImageBytes (80 * 12 / 8)
451 static int getRawCardData (int fd, uint8_t * buffer)
452 {
453 memset (buffer, 0, rawCardImageBytes + 2);
454 ssize_t rc = read (fd, buffer, rawCardImageBytes);
455 if (rc < 0)
456 return 0;
457 return (int) rc;
458 }
459
460 #ifdef TESTING
461 static bool empty = false;
462 #endif
463
464 static int rdrReadRecord (uint iomUnitIdx, uint chan) {
465 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
466 sim_debug (DBG_NOTIFY, & rdr_dev, "Read binary\n");
467 uint ctlr_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
468 uint unitIdx = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486 #ifdef TESTING
487 sim_printf ("hopper not empty\r\n");
488 empty = false;
489 #endif
490 unsigned char cardImage [80] = "";
491 uint8_t rawCardImage [rawCardImageBytes + 2 ];
492 size_t l = 0;
493
494 enum deckFormat thisCard = cardDeck;
495
496 static int jobNo = 0;
497
498 switch (rdr_state [unitIdx].deckState) {
499
500 case deckStart: {
501 #ifdef TESTING
502 sim_printf ("deckStart: sending ++EOF\r\n");
503 #endif
504 strcpy ((char *) cardImage, "++EOF");
505 l = strlen ((char *) cardImage);
506 thisCard = cardDeck;
507 rdr_state [unitIdx].deckState = eof1Sent;
508 jobNo ++;
509 }
510 break;
511
512 case eof1Sent: {
513 #ifdef TESTING
514 sim_printf ("eof1Sent: sending ++UID\r\n");
515 #endif
516 sprintf ((char *) cardImage, "++UID %d", jobNo);
517 l = strlen ((char *) cardImage);
518 thisCard = cardDeck;
519 rdr_state [unitIdx].deckState = uid1Sent;
520 }
521 break;
522
523 case uid1Sent: {
524 #ifdef TESTING
525 sim_printf ("uid1Sent: sending data\r\n");
526 #endif
527 int rc = getCardLine (rdr_state [unitIdx].deckfd, cardImage);
528 if (rc) {
529 #ifdef TESTING
530 sim_printf ("uid1Sent: getCardLine returned %d\r\n", rc);
531 #endif
532 close (rdr_state [unitIdx].deckfd);
533
534 rc = unlink (rdr_state [unitIdx].fname);
535 if (rc)
536 perror ("card reader deck unlink\n");
537 rdr_state [unitIdx].deckfd = -1;
538 rdr_state [unitIdx].deckState = deckStart;
539 p->stati = 04201;
540 return IOM_CMD_DISCONNECT;
541 }
542 #ifdef TESTING
543 sim_printf ("uid1Sent: getCardLine returned <%s>\r\n", cardImage);
544 #endif
545 l = strlen ((char *) cardImage);
546 thisCard = cardDeck;
547 if (strncasecmp ((char *) cardImage, "++input", 7) == 0) {
548 #ifdef TESTING
549 sim_printf ("uid1Sent: switching to inputSent <%s>\r\n", cardImage);
550 #endif
551 rdr_state [unitIdx].deckState = inputSent;
552 }
553 }
554 break;
555
556
557
558 case inputSent: {
559 #ifdef TESTING
560 sim_printf ("inputSent: format %d\r\n", rdr_state [unitIdx].deckFormat);
561 #endif
562 switch (rdr_state [unitIdx].deckFormat) {
563 case cardDeck: {
564 #ifdef TESTING
565 sim_printf ("inputSent: cardDeck\r\n");
566 #endif
567 int rc = getCardLine (rdr_state [unitIdx].deckfd, cardImage);
568 if (rc) {
569 strcpy ((char *) cardImage, "++EOF");
570 rdr_state [unitIdx].deckState = eof2Sent;
571 }
572 l = strlen ((char *) cardImage);
573 }
574 thisCard = cardDeck;
575 break;
576
577 case streamDeck: {
578 #ifdef TESTING
579 sim_printf ("inputSent: streamDeck\r\n");
580 #endif
581 l = (size_t) getCardData (rdr_state [unitIdx].deckfd, (char *) cardImage);
582 if (l) {
583 thisCard = streamDeck;
584 } else {
585 strcpy ((char *) cardImage, "++EOF");
586 l = strlen ((char *) cardImage);
587 rdr_state [unitIdx].deckState = eof2Sent;
588 thisCard = cardDeck;
589 }
590 #ifdef TESTING
591 sim_printf ("inputSent: getCardLine returned <%s>\r\n", cardImage);
592 #endif
593 }
594 break;
595
596 case sevenDeck: {
597 #ifdef TESTING
598 sim_printf ("inputSent: 7Deck\r\n");
599 #endif
600 l = (size_t) getRawCardData (rdr_state [unitIdx].deckfd, rawCardImage);
601 if (l) {
602 thisCard = sevenDeck;
603 } else {
604 strcpy ((char *) cardImage, "++EOF");
605 l = strlen ((char *) cardImage);
606 rdr_state [unitIdx].deckState = eof2Sent;
607 thisCard = cardDeck;
608 }
609 }
610 break;
611
612 }
613 }
614 break;
615
616
617
618 case eof2Sent: {
619 # ifdef TESTING
620 sim_printf ("eof2Sent\r\n");
621 # endif
622 sprintf ((char *) cardImage, "++UID %d", jobNo);
623 l = strlen ((char *) cardImage);
624 thisCard = cardDeck;
625 rdr_state [unitIdx].deckState = deckStart;
626 close (rdr_state [unitIdx].deckfd);
627
628 int rc = unlink (rdr_state [unitIdx].fname);
629 if (rc)
630 perror ("card reader deck unlink\n");
631 rdr_state [unitIdx].deckfd = -1;
632 }
633 break;
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663 }
664
665
666
667
668
669
670 #ifdef TESTING
671 sim_printf ("\r\n");
672 sim_printf ("\r\n");
673 for (uint i = 0; i < 80; i ++) {
674 if (isprint (cardImage [i]))
675 sim_printf ("%c", cardImage [i]);
676 else
677 sim_printf ("\\%03o", cardImage [i]);
678 }
679 sim_printf ("\r\n");
680 sim_printf ("\r\n");
681 #endif
682 word36 buffer [27];
683 switch (thisCard) {
684
685 case sevenDeck: {
686
687
688 for (uint i = 0; i < 27; i ++)
689 buffer [i] = extr36 ((uint8 *) rawCardImage, i);
690
691
692 }
693 break;
694
695 case streamDeck:
696
697
698
699
700
701
702
703
704
705
706 case cardDeck: {
707 if (l > 80) {
708 sim_warn ("Whups. rdr l %lu > 80; truncating.\n", (unsigned long)l);
709 l = 80;
710
711 }
712
713 uint hbuf [l];
714 asciiToH ((char *) cardImage, hbuf, l);
715
716
717 uint nbits = (uint) l * 12;
718
719 uint tally = (nbits + 35) / 36;
720
721 if (tally > 27) {
722 sim_warn ("Impossible rdr tally: %d > 27; truncating.\n", tally);
723 tally = 27;
724 }
725
726
727
728 memset (buffer, 0, sizeof (buffer));
729 for (uint col = 0; col < l; col ++) {
730 uint wordno = col / 3;
731 uint fieldno = col % 3;
732 putbits36_12 (& buffer [wordno], fieldno * 12, (word12) hbuf [col]);
733 }
734 }
735 break;
736 }
737
738
739
740
741
742
743
744
745
746
747
748 p->stati = 04000;
749
750
751 uint tally = 27;
752
753 iom_indirect_data_service (iomUnitIdx, chan, buffer, & tally, true);
754 p->initiate = false;
755 p->stati = 04000;
756 p->tallyResidue = (word12) tally & MASK12;
757 p->charPos = 0;
758
759 return IOM_CMD_PROCEED;
760 }
761
762 static void submit (enum deckFormat fmt, char * fname, uint16 readerIndex)
763 {
764 if (readerIndex >= N_RDR_UNITS_MAX) {
765 sim_warn("crdrdr: submit called with invalid reader index %ld\n", (long) readerIndex);
766 return;
767 }
768
769 int deckfd = open (fname, O_RDONLY);
770 if (deckfd < 0)
771 perror ("card reader deck open\n");
772
773
774 #ifdef TESTING
775 sim_printf ("submit %s\r\n", fname);
776 #endif
777 strcpy (rdr_state [readerIndex].fname, fname);
778 rdr_state [readerIndex].deckfd = deckfd;
779 rdr_state [readerIndex].deckState = deckStart;
780 rdr_state [readerIndex].deckFormat = fmt;
781 if (deckfd >= 0)
782 rdrCardReady (readerIndex);
783 }
784
785 static void scanForCards(uint16 readerIndex)
786 {
787 char rdr_dir [2 * PATH_MAX + 8];
788
789 if (readerIndex >= N_RDR_UNITS_MAX) {
790 sim_warn("crdrdr: scanForCards called with invalid reader index %d\n", readerIndex);
791 return;
792 }
793
794 #if !defined(__MINGW64__) || !defined(__MINGW32__)
795 const char* r_tmpdir = getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp";
796 #else
797 const char* r_tmpdir = getenv("TEMP") ? getenv("TEMP") : \
798 getenv("TMP") ? getenv("TMP") : ".";
799 #endif
800 snprintf_truncat(rdr_dir, PATH_MAX + 1, "%s/%s%c",
801 r_tmpdir, rdr_name, 'a' + readerIndex);
802
803 if (rdr_path_prefix [0])
804 {
805 snprintf_truncat(rdr_dir, PATH_MAX + 1, "%s%s%c",
806 rdr_path_prefix, rdr_name, 'a' + readerIndex);
807 }
808
809 DIR * dp;
810 dp = opendir (rdr_dir);
811 if (! dp)
812 {
813 sim_warn ("crdrdr opendir '%s' fail.\n", rdr_dir);
814 perror ("opendir");
815 return;
816 }
817 struct dirent * entry;
818 struct stat info;
819 char fqname [2 * PATH_MAX + 8];
820 while ((entry = readdir (dp)))
821 {
822 strcpy (fqname, rdr_dir);
823 strcat (fqname, "/");
824 strcat (fqname, entry -> d_name);
825
826 if (stat(fqname, &info) != 0)
827 {
828 sim_warn("crdrdr: scanForCards stat() error for %s: %s\n", fqname, strerror(errno));
829 continue;
830 }
831
832 if (S_ISDIR(info.st_mode))
833 {
834
835 continue;
836 }
837
838 if (rdr_state [readerIndex] . deckfd < 0)
839 {
840 if (strncmp (entry -> d_name, "cdeck.", 6) == 0)
841 {
842 submit (cardDeck, fqname, readerIndex);
843 break;
844 }
845 if (strncmp (entry -> d_name, "7deck.", 6) == 0)
846 {
847 submit (sevenDeck, fqname, readerIndex);
848 break;
849 }
850 if (strncmp (entry -> d_name, "sdeck.", 6) == 0)
851 {
852 submit (streamDeck, fqname, readerIndex);
853 break;
854 }
855 }
856 if (strcmp (entry -> d_name, "discard") == 0)
857 {
858
859 int rc = unlink (fqname);
860 if (rc)
861 perror ("crdrdr discard unlink\n");
862 if (rdr_state [readerIndex] . deckfd >= 0)
863 {
864 close (rdr_state [readerIndex] . deckfd);
865 rc = unlink (rdr_state [readerIndex] . fname);
866 if (rc)
867 perror ("crdrdr deck unlink\n");
868 rdr_state [readerIndex] . deckfd = -1;
869 rdr_state [readerIndex] . deckState = deckStart;
870 break;
871 }
872 }
873 }
874 closedir (dp);
875 }
876
877 void rdrProcessEvent (void)
878 {
879 if (rdr_path_prefix [0])
880 {
881
882
883 for (uint16 reader_idx = 0; reader_idx < rdr_dev . numunits; reader_idx++)
884 {
885 if (rdr_state [reader_idx] . running)
886 scanForCards(reader_idx);
887 }
888 }
889 else
890 {
891
892
893 if (! rdr_state [0] . running)
894 return;
895
896 scanForCards(0);
897 }
898 }
899
900 void rdrCardReady (int unitNum)
901 {
902 uint ctlr_unit_idx = cables->rdr_to_urp [unitNum].ctlr_unit_idx;
903 uint ctlr_port_num = 0;
904 uint iom_unit_idx = cables->urp_to_iom[ctlr_unit_idx][ctlr_port_num].iom_unit_idx;
905 uint chan_num = cables->urp_to_iom[ctlr_unit_idx][ctlr_port_num].chan_num;
906 uint dev_code = cables->rdr_to_urp[unitNum].dev_code;
907 send_special_interrupt (iom_unit_idx, chan_num, dev_code, 0377, 0377 );
908 }
909
910 iom_cmd_rc_t rdr_iom_cmd (uint iomUnitIdx, uint chan) {
911 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
912 uint dev_code = p->IDCW_DEV_CODE;
913
914 sim_debug (DBG_TRACE, & rdr_dev, "%s: RDR %c%02o_%02o\n",
915 __func__, iomChar (iomUnitIdx), chan, dev_code);
916
917 uint ctlr_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
918 uint unitIdx = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
919 struct rdr_state * statep = & rdr_state[unitIdx];
920 statep->running = true;
921
922 iom_cmd_rc_t rc = IOM_CMD_PROCEED;
923
924 if (IS_IDCW (p)) {
925
926 statep->io_mode = rdr_no_mode;
927
928 switch (p->IDCW_DEV_CMD) {
929
930 case 000:
931 sim_debug (DBG_DEBUG, & rdr_dev, "%s: Request Status\n", __func__);
932 p->stati = 04000;
933
934
935
936 #ifdef TESTING
937 sim_printf ("Request status %04o\r\n", p->stati);
938 #endif
939 break;
940
941 case 001:
942 sim_debug (DBG_DEBUG, & rdr_dev, "%s: Read Binary\n", __func__);
943 if (rdr_state [unitIdx].deckfd < 0) {
944 p->stati = 04201;
945 p->tallyResidue = 0;
946 #ifdef TESTING
947 if (! empty)
948 sim_printf ("hopper empty\r\n");
949 empty = true;
950 #endif
951 return IOM_CMD_DISCONNECT;
952 }
953 statep->io_mode = rdr_rd_bin;
954 p->stati = 04000;
955
956
957
958 #ifdef TESTING
959 sim_printf ("read binary %04o\r\n", p->stati);
960 #endif
961 break;
962
963 case 040:
964 sim_debug (DBG_DEBUG, & rdr_dev, "%s: Request Status\n", __func__);
965 p->stati = 04000;
966 p->isRead = false;
967
968
969
970 #ifdef TESTING
971 sim_printf ("reset status %04o\r\n", p->stati);
972 #endif
973 break;
974
975 default:
976 #ifdef TESTING
977 sim_printf ("unknown %o\r\n", p->IDCW_DEV_CMD);
978 #endif
979 if (p->IDCW_DEV_CMD != 051)
980 sim_warn ("%s: RDR unrecognized device command %02o\n", __func__, p->IDCW_DEV_CMD);
981 p->stati = 04501;
982 p->chanStatus = chanStatIncorrectDCW;
983 return IOM_CMD_ERROR;
984 }
985
986 sim_debug (DBG_DEBUG, & rdr_dev, "%s: stati %04o\n", __func__, p->stati);
987 return IOM_CMD_PROCEED;
988 }
989
990
991 switch (statep->io_mode) {
992
993 case rdr_no_mode:
994 #ifdef TESTING
995 sim_printf ("%s: Unexpected IOTx\r\n", __func__);
996 #endif
997
998
999 break;
1000
1001 case rdr_rd_bin: {
1002 int rc = rdrReadRecord (iomUnitIdx, chan);
1003 #ifdef TESTING
1004 sim_printf ("rdrReadRecord returned %d\r\n", rc);
1005 #endif
1006 if (rc)
1007 return IOM_CMD_DISCONNECT;
1008 }
1009 break;
1010
1011 default:
1012 sim_warn ("%s: Unrecognized io_mode %d\n", __func__, statep->io_mode);
1013 return IOM_CMD_ERROR;
1014 }
1015 return rc;
1016 }
1017
1018 static t_stat rdr_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr, UNUSED int val,
1019 UNUSED const void * desc)
1020 {
1021 sim_printf("Number of RDR units in system is %d\n", rdr_dev . numunits);
1022 return SCPE_OK;
1023 }
1024
1025 static t_stat rdr_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value, const char * cptr,
1026 UNUSED void * desc)
1027 {
1028 if (! cptr)
1029 return SCPE_ARG;
1030 int n = atoi (cptr);
1031 if (n < 1 || n > N_RDR_UNITS_MAX)
1032 return SCPE_ARG;
1033 rdr_dev . numunits = (uint32) n;
1034 return SCPE_OK;
1035 }
1036
1037 static t_stat rdr_show_device_name (UNUSED FILE * st, UNIT * uptr,
1038 UNUSED int val, UNUSED const void * desc)
1039 {
1040 long n = RDR_UNIT_NUM (uptr);
1041 if (n < 0 || n >= N_RDR_UNITS_MAX)
1042 return SCPE_ARG;
1043 sim_printf("name : %s", rdr_state [n] . device_name);
1044 return SCPE_OK;
1045 }
1046
1047 static t_stat rdr_set_device_name (UNUSED UNIT * uptr, UNUSED int32 value,
1048 UNUSED const char * cptr, UNUSED void * desc)
1049 {
1050 long n = RDR_UNIT_NUM (uptr);
1051 if (n < 0 || n >= N_RDR_UNITS_MAX)
1052 return SCPE_ARG;
1053 if (cptr)
1054 {
1055 strncpy (rdr_state [n] . device_name, cptr, MAX_DEV_NAME_LEN - 1);
1056 rdr_state [n] . device_name [MAX_DEV_NAME_LEN - 1] = 0;
1057 }
1058 else
1059 rdr_state [n] . device_name [0] = 0;
1060 return SCPE_OK;
1061 }
1062
1063 static t_stat rdr_set_path (UNUSED UNIT * uptr, UNUSED int32 value,
1064 const UNUSED char * cptr, UNUSED void * desc)
1065 {
1066 if (! cptr)
1067 return SCPE_ARG;
1068
1069 size_t len = strlen(cptr);
1070
1071
1072
1073 if (len >= (sizeof(rdr_path_prefix) - (strlen(rdr_name) + 3)))
1074 return SCPE_ARG;
1075
1076 strncpy(rdr_path_prefix, cptr, sizeof(rdr_path_prefix));
1077 if (len > 0)
1078 {
1079 if (rdr_path_prefix[len - 1] != '/')
1080 {
1081 if (len == sizeof(rdr_path_prefix) - 1)
1082 return SCPE_ARG;
1083 rdr_path_prefix[len++] = '/';
1084 rdr_path_prefix[len] = 0;
1085 }
1086 }
1087 return SCPE_OK;
1088 }
1089
1090 static t_stat rdr_show_path (UNUSED FILE * st, UNUSED UNIT * uptr,
1091 UNUSED int val, UNUSED const void * desc)
1092 {
1093 if (rdr_path_prefix [0])
1094 {
1095 sim_printf("\rPath to card reader directories is \"%s\".\r\n", rdr_path_prefix);
1096 }
1097 else
1098 {
1099 sim_printf("\rPath to card reader directories is unset.\r\n");
1100 }
1101 return SCPE_OK;
1102 }