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 return IOM_CMD_DISCONNECT;
617 }
618 #if defined(TESTING)
619 sim_printf ("uid1Sent: getCardLine returned <%s>\r\n", cardImage);
620 #endif
621 l = strlen ((char *) cardImage);
622 thisCard = cardDeck;
623 if (strncasecmp ((char *) cardImage, "++input", 7) == 0) {
624 #if defined(TESTING)
625 sim_printf ("uid1Sent: switching to inputSent <%s>\r\n", cardImage);
626 #endif
627 rdr_state [unitIdx].deckState = inputSent;
628 }
629 }
630 break;
631
632
633
634 case inputSent: {
635 #if defined(TESTING)
636 sim_printf ("inputSent: format %d\r\n", rdr_state [unitIdx].deckFormat);
637 #endif
638 switch (rdr_state [unitIdx].deckFormat) {
639 case xDeck:
640 case gDeck: {
641 #if defined(TESTING)
642 sim_printf ("inputSent: xDeck or gDeck\r\n");
643 #endif
644 int rc = getCardLine (rdr_state [unitIdx].deckfd, cardImage);
645 if (rc) {
646 rdr_state [unitIdx].deckState = deckStart;
647 close (rdr_state [unitIdx].deckfd);
648
649 int rc = unlink (rdr_state [unitIdx].fname);
650 if (rc)
651 (void)sir_error ("crdrdr: Failure unlinking card reader deck: %s (Error %d)", xstrerror_l (errno), errno);
652 rdr_state [unitIdx].deckfd = -1;
653 p->stati = 04201;
654 return IOM_CMD_DISCONNECT;
655 }
656 l = strlen ((char *) cardImage);
657 }
658 thisCard = cardDeck;
659 break;
660
661 case cardDeck: {
662 #if defined(TESTING)
663 sim_printf ("inputSent: cardDeck\r\n");
664 #endif
665 int rc = getCardLine (rdr_state [unitIdx].deckfd, cardImage);
666 if (rc) {
667 strcpy ((char *) cardImage, "++EOF");
668 rdr_state [unitIdx].deckState = eof2Sent;
669 }
670 l = strlen ((char *) cardImage);
671 }
672 thisCard = cardDeck;
673 break;
674
675 case streamDeck: {
676 #if defined(TESTING)
677 sim_printf ("inputSent: streamDeck\r\n");
678 #endif
679 l = (size_t) getCardData (rdr_state [unitIdx].deckfd, (char *) cardImage);
680 if (l) {
681 thisCard = streamDeck;
682 } else {
683 strcpy ((char *) cardImage, "++EOF");
684 l = strlen ((char *) cardImage);
685 rdr_state [unitIdx].deckState = eof2Sent;
686 thisCard = cardDeck;
687 }
688 #if defined(TESTING)
689 sim_printf ("inputSent: getCardLine returned <%s>\r\n", cardImage);
690 #endif
691 }
692 break;
693
694 case bDeck:
695 #if defined(TESTING)
696 sim_printf ("inputSent: bDeck\r\n");
697 #endif
698 l = (size_t) getBinCardData (rdr_state [unitIdx].deckfd, &card);
699 if (l) {
700 thisCard = bDeck;
701 } else {
702 rdr_state [unitIdx].deckState = deckStart;
703 close (rdr_state [unitIdx].deckfd);
704
705 int rc = unlink (rdr_state [unitIdx].fname);
706 if (rc)
707 (void)sir_error ("crdrdr: Failure unlinking card reader deck: %s (Error %d)", xstrerror_l (errno), errno);
708 rdr_state [unitIdx].deckfd = -1;
709 p->stati = 04201;
710 return IOM_CMD_DISCONNECT;
711 }
712 break;
713
714 case sevenDeck: {
715 #if defined(TESTING)
716 sim_printf ("inputSent: 7Deck\r\n");
717 #endif
718 l = (size_t) getRawCardData (rdr_state [unitIdx].deckfd, rawCardImage);
719 if (l) {
720 thisCard = sevenDeck;
721 } else {
722 strcpy ((char *) cardImage, "++EOF");
723 l = strlen ((char *) cardImage);
724 rdr_state [unitIdx].deckState = eof2Sent;
725 thisCard = cardDeck;
726 }
727 }
728 break;
729
730 }
731 }
732 break;
733
734
735
736 case eof2Sent: {
737 # if defined(TESTING)
738 sim_printf ("eof2Sent\r\n");
739 # endif
740 (void)sprintf ((char *) cardImage, "++UID %d", jobNo);
741 l = strlen ((char *) cardImage);
742 thisCard = cardDeck;
743 rdr_state [unitIdx].deckState = deckStart;
744 close (rdr_state [unitIdx].deckfd);
745
746 int rc = unlink (rdr_state [unitIdx].fname);
747 if (rc)
748 (void)sir_error ("crdrdr: Failure unlinking card reader deck: %s (Error %d)", xstrerror_l (errno), errno);
749 rdr_state [unitIdx].deckfd = -1;
750 }
751 break;
752
753
754
755
756
757
758
759
760
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 word36 buffer [27];
803 switch (thisCard) {
804 case bDeck: {
805
806 uint l = 80;
807
808 uint nbits = (uint) l * 12;
809
810 uint tally = (nbits + 35) / 36;
811
812 if (tally > 27) {
813 sim_warn ("Impossible rdr tally: %d > 27; truncating.\r\n", tally);
814 tally = 27;
815 }
816
817
818
819 (void)memset (buffer, 0, sizeof (buffer));
820 for (uint col = 0; col < l; col ++) {
821 uint wordno = col / 3;
822 uint fieldno = col % 3;
823 putbits36_12 (& buffer [wordno], fieldno * 12, (word12) card.column [col]);
824 }
825 }
826 break;
827 case sevenDeck: {
828
829
830 for (uint i = 0; i < 27; i ++)
831 buffer [i] = extr36 ((uint8 *) rawCardImage, i);
832
833
834 }
835 break;
836
837 case streamDeck:
838
839
840
841
842
843
844
845
846
847
848 case xDeck:
849 case gDeck:
850 case cardDeck: {
851 if (l > 80) {
852 sim_warn ("Whups. rdr l %lu > 80; truncating.\r\n", (unsigned long)l);
853 l = 80;
854
855 }
856
857 uint hbuf [l + 1];
858
859 if (rdr_state [unitIdx].deckFormat == gDeck) {
860 asciiToHGCOS ((char *) cardImage, hbuf, l);
861 }
862 else {
863 asciiToH ((char *) cardImage, hbuf, l);
864 }
865
866
867 uint nbits = (uint) l * 12;
868
869 uint tally = (nbits + 35) / 36;
870
871 if (tally > 27) {
872 sim_warn ("Impossible rdr tally: %d > 27; truncating.\r\n", tally);
873 tally = 27;
874 }
875
876
877
878 (void)memset (buffer, 0, sizeof (buffer));
879 for (uint col = 0; col < l; col ++) {
880 uint wordno = col / 3;
881 uint fieldno = col % 3;
882 putbits36_12 (& buffer [wordno], fieldno * 12, (word12) hbuf [col]);
883 }
884 }
885 break;
886 }
887
888
889
890
891
892
893
894
895
896
897
898 p->stati = 04000;
899
900
901 uint tally = 27;
902
903 iom_indirect_data_service (iomUnitIdx, chan, buffer, & tally, true);
904 p->initiate = false;
905 p->stati = 04000;
906 p->tallyResidue = (word12) tally & MASK12;
907 p->charPos = 0;
908
909 return IOM_CMD_PROCEED;
910 }
911
912 static void submit (enum deckFormat fmt, char * fname, uint16 readerIndex)
913 {
914 if (readerIndex >= N_RDR_UNITS_MAX) {
915 sim_warn("crdrdr: submit called with invalid reader index %ld\r\n", (long) readerIndex);
916 return;
917 }
918
919 int deckfd = open (fname, O_RDONLY);
920 if (deckfd < 0)
921 (void)sir_error ("crdrdr: Failure opening card reader deck: %s (Error %d)", xstrerror_l (errno), errno);
922
923
924 #if defined(TESTING)
925 sim_printf ("submit %s\r\n", fname);
926 #endif
927 #if defined(__GNUC__)
928 # if !defined(__clang_version__)
929 # if __GNUC__ > 7
930 # if !defined(__INTEL_COMPILER)
931 # pragma GCC diagnostic push
932 # pragma GCC diagnostic ignored "-Wstringop-truncation"
933 # endif
934 # endif
935 # endif
936 #endif
937 strncpy (rdr_state [readerIndex].fname, fname, sizeof(rdr_state [readerIndex].fname) - 1);
938 rdr_state [readerIndex].fname [sizeof(rdr_state [readerIndex].fname) - 1] = '\0';
939 #if defined(__GNUC__)
940 # if !defined(__clang_version__)
941 # if __GNUC__ > 7
942 # if !defined(__INTEL_COMPILER)
943 # pragma GCC diagnostic pop
944 # endif
945 # endif
946 # endif
947 #endif
948 rdr_state [readerIndex].deckfd = deckfd;
949 rdr_state [readerIndex].deckState = deckStart;
950 rdr_state [readerIndex].deckFormat = fmt;
951 if (fmt == xDeck || fmt == gDeck || fmt == bDeck) {
952 rdr_state [readerIndex].deckState = inputSent;
953 }
954 if (deckfd >= 0)
955 rdrCardReady (readerIndex);
956 }
957
958 static void scanForCards(uint16 readerIndex)
959 {
960 char rdr_dir [2 * PATH_MAX + 8];
961
962 if (readerIndex >= N_RDR_UNITS_MAX)
963 {
964 (void)sir_error ("crdrdr: scanForCards called with invalid reader index %d", readerIndex);
965 return;
966 }
967
968 #if !defined(__MINGW64__) || !defined(__MINGW32__)
969 const char* r_tmpdir = getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp";
970 #else
971 const char* r_tmpdir = getenv("TEMP") ? getenv("TEMP") : \
972 getenv("TMP") ? getenv("TMP") : ".";
973 #endif
974 snprintf_truncat(rdr_dir, PATH_MAX + 1, "%s/%s%c",
975 r_tmpdir, rdr_name, 'a' + readerIndex);
976
977 if (rdr_path_prefix [0])
978 {
979 snprintf_truncat(rdr_dir, PATH_MAX + 1, "%s%s%c",
980 rdr_path_prefix, rdr_name, 'a' + readerIndex);
981 }
982
983 DIR * dp;
984 dp = opendir (rdr_dir);
985 if (! dp)
986 {
987 if (errno == ENOENT)
988 {
989 (void)sir_notice ("crdrdr: Punch reader %s%c input directory '%s' not found; creating it.",
990 rdr_name, 'a' + readerIndex, rdr_dir);
991 if (x_mkdir_p (rdr_dir) == -1)
992 {
993 (void)sir_error ("crdrdr: Failure creating punch reader %s%c input directory '%s': %s (Error %d)",
994 rdr_name, 'a' + readerIndex, rdr_dir, xstrerror_l (errno), errno);
995 return;
996 }
997 }
998
999 dp = opendir (rdr_dir);
1000 if (! dp)
1001 {
1002 (void)sir_error ("crdrdr: Failure opening 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 struct dirent * entry;
1009 struct stat info;
1010 char fqname [2 * PATH_MAX + 8];
1011 while ((entry = readdir (dp)))
1012 {
1013 strcpy (fqname, rdr_dir);
1014 strcat (fqname, "/");
1015 strcat (fqname, entry -> d_name);
1016
1017 if (stat(fqname, &info) != 0)
1018 {
1019 (void)sir_error ("crdrdr: scanForCards stat() failure for %s: %s (Error %d)",
1020 fqname, xstrerror_l(errno), errno);
1021 continue;
1022 }
1023
1024 if (S_ISDIR(info.st_mode))
1025 {
1026
1027 continue;
1028 }
1029
1030 if (rdr_state [readerIndex] . deckfd < 0)
1031 {
1032 if (strncmp (entry -> d_name, "xdeck.", 6) == 0)
1033 {
1034 submit (xDeck, fqname, readerIndex);
1035 break;
1036 }
1037 if (strncmp (entry -> d_name, "gdeck.", 6) == 0)
1038 {
1039 submit (gDeck, fqname, readerIndex);
1040 break;
1041 }
1042 if (strncmp (entry -> d_name, "cdeck.", 6) == 0)
1043 {
1044 submit (cardDeck, fqname, readerIndex);
1045 break;
1046 }
1047 if (strncmp (entry -> d_name, "7deck.", 6) == 0)
1048 {
1049 submit (sevenDeck, fqname, readerIndex);
1050 break;
1051 }
1052 if (strncmp (entry -> d_name, "sdeck.", 6) == 0)
1053 {
1054 submit (streamDeck, fqname, readerIndex);
1055 break;
1056 }
1057 if (strncmp (entry -> d_name, "bdeck.", 6) == 0)
1058 {
1059 submit (bDeck, fqname, readerIndex);
1060 break;
1061 }
1062 }
1063 if (strcmp (entry -> d_name, "discard") == 0)
1064 {
1065
1066 int rc = unlink (fqname);
1067 if (rc)
1068 (void)sir_error ("crdrdr: Failure unlinking card reader deck: %s (Error %d)", xstrerror_l (errno), errno);
1069 if (rdr_state [readerIndex] . deckfd >= 0)
1070 {
1071 close (rdr_state [readerIndex] . deckfd);
1072 rc = unlink (rdr_state [readerIndex] . fname);
1073 if (rc)
1074 (void)sir_error ("crdrdr: Failure unlinking card reader deck: %s (Error %d)", xstrerror_l (errno), errno);
1075 rdr_state [readerIndex] . deckfd = -1;
1076 rdr_state [readerIndex] . deckState = deckStart;
1077 break;
1078 }
1079 }
1080 }
1081 closedir (dp);
1082 }
1083
1084 void rdrProcessEvent (void)
1085 {
1086 if (rdr_path_prefix [0])
1087 {
1088
1089
1090 for (uint16 reader_idx = 0; reader_idx < rdr_dev . numunits; reader_idx++)
1091 {
1092 if (rdr_state [reader_idx] . running)
1093 scanForCards(reader_idx);
1094 }
1095 }
1096 else
1097 {
1098
1099
1100 if (! rdr_state [0] . running)
1101 return;
1102
1103 scanForCards(0);
1104 }
1105 }
1106
1107 void rdrCardReady (int unitNum)
1108 {
1109 uint ctlr_unit_idx = cables->rdr_to_urp [unitNum].ctlr_unit_idx;
1110 uint ctlr_port_num = 0;
1111 uint iom_unit_idx = cables->urp_to_iom[ctlr_unit_idx][ctlr_port_num].iom_unit_idx;
1112 uint chan_num = cables->urp_to_iom[ctlr_unit_idx][ctlr_port_num].chan_num;
1113 uint dev_code = cables->rdr_to_urp[unitNum].dev_code;
1114 send_special_interrupt (iom_unit_idx, chan_num, dev_code, 0377, 0377 );
1115 }
1116
1117 iom_cmd_rc_t rdr_iom_cmd (uint iomUnitIdx, uint chan) {
1118 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
1119 #if defined(xTESTING)
1120 uint dev_code = p->IDCW_DEV_CODE;
1121 cpu_state_t * cpup = _cpup;
1122
1123
1124
1125 #endif
1126
1127 uint ctlr_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
1128 uint unitIdx = cables->urp_to_urd[ctlr_unit_idx][p->IDCW_DEV_CODE].unit_idx;
1129 struct rdr_state * statep = & rdr_state[unitIdx];
1130 statep->running = true;
1131
1132 iom_cmd_rc_t rc = IOM_CMD_PROCEED;
1133
1134 if (IS_IDCW (p)) {
1135
1136 statep->io_mode = rdr_no_mode;
1137
1138 switch (p->IDCW_DEV_CMD) {
1139 case 000:
1140
1141 p->stati = 04000;
1142
1143
1144
1145 #if defined(TESTING)
1146 sim_printf ("Request status %04o\r\n", p->stati);
1147 #endif
1148 break;
1149
1150 case 001:
1151
1152 if (rdr_state [unitIdx].deckfd < 0) {
1153 p->stati = 04201;
1154 p->tallyResidue = 0;
1155 #if defined(TESTING)
1156 if (! empty)
1157 sim_printf ("hopper empty\r\n");
1158 empty = true;
1159 #endif
1160 return IOM_CMD_DISCONNECT;
1161 }
1162 statep->io_mode = rdr_rd_bin;
1163 p->stati = 04000;
1164
1165
1166
1167 #if defined(TESTING)
1168 sim_printf ("read binary %04o\r\n", p->stati);
1169 #endif
1170 break;
1171
1172 case 040:
1173
1174 p->stati = 04000;
1175 p->isRead = false;
1176
1177
1178
1179 #if defined(TESTING)
1180 sim_printf ("reset status %04o\r\n", p->stati);
1181 #endif
1182 break;
1183
1184 default:
1185 #if defined(TESTING)
1186 sim_printf ("unknown %o\r\n", p->IDCW_DEV_CMD);
1187 #endif
1188 if (p->IDCW_DEV_CMD != 051)
1189 sim_warn ("%s: RDR unrecognized device command %02o\r\n", __func__, p->IDCW_DEV_CMD);
1190 p->stati = 04501;
1191 p->chanStatus = chanStatIncorrectDCW;
1192 return IOM_CMD_ERROR;
1193 }
1194
1195
1196 return IOM_CMD_PROCEED;
1197 }
1198
1199
1200 switch (statep->io_mode) {
1201 case rdr_no_mode:
1202 #if defined(TESTING)
1203 sim_printf ("%s: Unexpected IOTx\r\n", __func__);
1204 #endif
1205
1206
1207 break;
1208
1209 case rdr_rd_bin: {
1210 int rc = rdrReadRecord (iomUnitIdx, chan);
1211 #if defined(TESTING)
1212 sim_printf ("rdrReadRecord returned %d\r\n", rc);
1213 #endif
1214 if (rc)
1215 return IOM_CMD_DISCONNECT;
1216 }
1217 break;
1218
1219 default:
1220 sim_warn ("%s: Unrecognized io_mode %d\r\n", __func__, statep->io_mode);
1221 return IOM_CMD_ERROR;
1222 }
1223 return rc;
1224 }
1225
1226 static t_stat rdr_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr, UNUSED int val,
1227 UNUSED const void * desc)
1228 {
1229 sim_printf("Number of RDR units in system is %d\r\n", rdr_dev . numunits);
1230 return SCPE_OK;
1231 }
1232
1233 static t_stat rdr_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value, const char * cptr,
1234 UNUSED void * desc)
1235 {
1236 if (! cptr)
1237 return SCPE_ARG;
1238 int n = atoi (cptr);
1239 if (n < 1 || n > N_RDR_UNITS_MAX)
1240 return SCPE_ARG;
1241 rdr_dev . numunits = (uint32) n;
1242 return SCPE_OK;
1243 }
1244
1245 static t_stat rdr_show_device_name (UNUSED FILE * st, UNIT * uptr,
1246 UNUSED int val, UNUSED const void * desc)
1247 {
1248 long n = RDR_UNIT_NUM (uptr);
1249 if (n < 0 || n >= N_RDR_UNITS_MAX)
1250 return SCPE_ARG;
1251 sim_printf("name : %s", rdr_state [n] . device_name);
1252 return SCPE_OK;
1253 }
1254
1255 static t_stat rdr_set_device_name (UNUSED UNIT * uptr, UNUSED int32 value,
1256 UNUSED const char * cptr, UNUSED void * desc)
1257 {
1258 long n = RDR_UNIT_NUM (uptr);
1259 if (n < 0 || n >= N_RDR_UNITS_MAX)
1260 return SCPE_ARG;
1261 if (cptr)
1262 {
1263 strncpy (rdr_state [n] . device_name, cptr, MAX_DEV_NAME_LEN - 1);
1264 rdr_state [n] . device_name [MAX_DEV_NAME_LEN - 1] = 0;
1265 }
1266 else
1267 rdr_state [n] . device_name [0] = 0;
1268 return SCPE_OK;
1269 }
1270
1271 static t_stat rdr_set_path (UNUSED UNIT * uptr, UNUSED int32 value,
1272 const UNUSED char * cptr, UNUSED void * desc)
1273 {
1274 if (! cptr)
1275 return SCPE_ARG;
1276
1277 size_t len = strlen(cptr);
1278
1279
1280
1281 if (len >= (sizeof(rdr_path_prefix) - (strlen(rdr_name) + 3)))
1282 return SCPE_ARG;
1283
1284 strncpy(rdr_path_prefix, cptr, sizeof(rdr_path_prefix) -1);
1285 rdr_path_prefix[sizeof(rdr_path_prefix) - 1] = '\0';
1286 if (len > 0)
1287 {
1288 if (rdr_path_prefix[len - 1] != '/')
1289 {
1290 if (len == sizeof(rdr_path_prefix) - 1)
1291 return SCPE_ARG;
1292 rdr_path_prefix[len++] = '/';
1293 rdr_path_prefix[len] = 0;
1294 }
1295 }
1296 return SCPE_OK;
1297 }
1298
1299 static t_stat rdr_show_path (UNUSED FILE * st, UNUSED UNIT * uptr,
1300 UNUSED int val, UNUSED const void * desc)
1301 {
1302 if (rdr_path_prefix [0])
1303 {
1304 sim_printf("\rPath to card reader directories is \"%s\".\r\n", rdr_path_prefix);
1305 }
1306 else
1307 {
1308 sim_printf("\rPath to card reader directories is unset.\r\n");
1309 }
1310 return SCPE_OK;
1311 }