From d705087a22c1eb037b5d2e2e6ae6c4c9af03a985 Mon Sep 17 00:00:00 2001 From: Richard Cornwell Date: Wed, 19 Jan 2022 09:46:58 -0500 Subject: [PATCH] SCP: Updated to current. --- scp.c | 73 +++---- sim_console.c | 4 +- sim_ether.c | 69 ++++--- sim_ether.h | 4 +- sim_serial.c | 101 +++------- sim_tmxr.c | 547 ++++++++++++++++++++++++++++++++++++++++++++------ sim_tmxr.h | 10 +- sim_video.c | 20 +- 8 files changed, 626 insertions(+), 202 deletions(-) diff --git a/scp.c b/scp.c index fcd3a60..8e493cd 100644 --- a/scp.c +++ b/scp.c @@ -1575,6 +1575,7 @@ static const char simh_help2[] = "+sh{ow} {arg,...} show unit parameters\n" "+sh{ow} ethernet show ethernet devices\n" "+sh{ow} serial show serial devices\n" + "+sh{ow} synchronous show DDCMP synchronous interface devices\n" "+sh{ow} multiplexer {dev} show open multiplexer device info\n" "+sh{ow} video show video capabilities\n" "+sh{ow} clocks show calibrated timer information\n" @@ -1603,6 +1604,7 @@ static const char simh_help2[] = #define HLP_SHOW_ASYNCH "*Commands SHOW" #define HLP_SHOW_ETHERNET "*Commands SHOW" #define HLP_SHOW_SERIAL "*Commands SHOW" +#define HLP_SHOW_SYNC "*Commands SHOW" #define HLP_SHOW_MULTIPLEXER "*Commands SHOW" #define HLP_SHOW_VIDEO "*Commands SHOW" #define HLP_SHOW_CLOCKS "*Commands SHOW" @@ -2643,6 +2645,7 @@ static SHTAB show_glob_tab[] = { { "ASYNCH", &sim_show_asynch, 0, HLP_SHOW_ASYNCH }, { "ETHERNET", ð_show_devices, 0, HLP_SHOW_ETHERNET }, { "SERIAL", &sim_show_serial, 0, HLP_SHOW_SERIAL }, + { "SYNCHRONOUS", &tmxr_show_sync_devices, 0, HLP_SHOW_SYNC }, { "MULTIPLEXER", &tmxr_show_open_devices, 0, HLP_SHOW_MULTIPLEXER }, { "MUX", &tmxr_show_open_devices, 0, HLP_SHOW_MULTIPLEXER }, { "VIDEO", &vid_show, 0, HLP_SHOW_VIDEO }, @@ -5844,7 +5847,7 @@ else { } } if (!dptr) - return SCPE_NXDEV; /* no match */ + return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\n", gbuf);/* no match */ lvl = MTAB_VDV; /* device match */ uptr = dptr->units; /* first unit */ } @@ -5865,7 +5868,7 @@ while (*cptr != 0) { /* do all mods */ if (((lvl & mptr->mask) & ~MTAB_XTD) == 0) return SCPE_ARG; if ((lvl == MTAB_VUN) && (uptr->flags & UNIT_DIS)) - return SCPE_UDIS; /* unit disabled? */ + return sim_messagef (SCPE_UDIS, "Unit disabled: %s\n", sim_uname (uptr)); if (mptr->valid) { /* validation rtn? */ if (cvptr && MODMASK(mptr,MTAB_QUOTE)) { svptr = get_glyph_quoted (svptr, gbuf, ','); @@ -5895,7 +5898,7 @@ while (*cptr != 0) { /* do all mods */ if (cvptr) /* = value? */ return SCPE_ARG; if (uptr->flags & UNIT_DIS) /* disabled? */ - return SCPE_UDIS; + return sim_messagef (SCPE_UDIS, "Unit disabled: %s\n", sim_uname (uptr)); if ((mptr->valid) && /* invalid? */ ((r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc)) != SCPE_OK)) return r; @@ -5913,7 +5916,7 @@ while (*cptr != 0) { /* do all mods */ } else if (!dptr->modifiers) /* no modifiers? */ return SCPE_NOPARAM; - else return SCPE_NXPAR; + else return sim_messagef (SCPE_NXPAR, "%s device: Non-existent parameter - %s\n", dptr->name, gbuf); } /* end if no mat */ } /* end while */ return SCPE_OK; /* done all */ @@ -6191,7 +6194,7 @@ while (*cptr != 0) { /* do all mods */ if (!dptr->modifiers) /* no modifiers? */ return sim_messagef (SCPE_NOPARAM, "%s device has no parameters\n", dptr->name); else - return sim_messagef (SCPE_NXPAR, "Non-existent parameter: %s\n", gbuf); + return sim_messagef (SCPE_NXPAR, "%s device: Non-existent parameter: %s\n", dptr->name, gbuf); } } /* end if */ } /* end while */ @@ -6477,6 +6480,8 @@ const char *cpp = ""; const char *build = ""; const char *arch = ""; +#define S_xstr(a) S_str(a) +#define S_str(a) #a if (cptr && (*cptr != 0)) return SCPE_2MARG; sprintf (vmaj_s, "%d", vmaj); @@ -6496,8 +6501,16 @@ if (vdelt) { fprintf (st, " delta %d", vdelt); } #if defined (SIM_VERSION_MODE) -fprintf (st, " %s", SIM_VERSION_MODE); -setenv ("SIM_VERSION_MODE", SIM_VERSION_MODE, 1); +if (1) { + char mode[] = S_xstr(SIM_VERSION_MODE); + + if (NULL != strchr (mode, '\"')) { /* Quoted String? */ + mode[strlen (mode) - 1] = '\0'; /* strip quotes */ + memmove (mode, mode + 1, strlen (mode)); + } + fprintf (st, " %s", mode); + setenv ("SIM_VERSION_MODE", mode, 1); + } #endif if (flag) { t_bool idle_capable; @@ -6541,11 +6554,7 @@ if (flag) { #elif defined (__DECC_VER) fprintf (st, "\n Compiler: DEC C %c%d.%d-%03d", ("T SV")[((__DECC_VER/10000)%10)-6], __DECC_VER/10000000, (__DECC_VER/100000)%100, __DECC_VER%10000); #elif defined (SIM_COMPILER) -#define S_xstr(a) S_str(a) -#define S_str(a) #a fprintf (st, "\n Compiler: %s", S_xstr(SIM_COMPILER)); -#undef S_str -#undef S_xstr #endif #if defined(__GNUC__) #if defined(__OPTIMIZE__) @@ -6574,19 +6583,11 @@ if (flag) { #if !defined (SIM_BUILD_OS) fprintf (st, "\n Simulator Compiled as %s%s%s on %s at %s", cpp, arch, build, __DATE__, __TIME__); #else -#define S_xstr(a) S_str(a) -#define S_str(a) #a fprintf (st, "\n Simulator Compiled as %s%s%s on %s at %s %s", cpp, arch, build, __DATE__, __TIME__, S_xstr(SIM_BUILD_OS)); -#undef S_str -#undef S_xstr #endif #endif #if defined (SIM_BUILD_TOOL) -#define S_xstr(a) S_str(a) -#define S_str(a) #a fprintf (st, "\n Build Tool: %s", S_xstr(SIM_BUILD_TOOL)); -#undef S_str -#undef S_xstr #else fprintf (st, "\n Build Tool: undefined (probably cmake)"); #endif @@ -6689,8 +6690,6 @@ if (flag) { setenv ("SIM_OSTYPE", os_type, 1); } #if defined(SIM_ARCHIVE_GIT_COMMIT_ID) -#define S_xstr(a) S_str(a) -#define S_str(a) #a if (NULL == strchr (S_xstr(SIM_ARCHIVE_GIT_COMMIT_ID), '$')) { const char *extras = strchr (S_xstr(SIM_ARCHIVE_GIT_COMMIT_ID), '+'); @@ -6704,12 +6703,8 @@ if (NULL == strchr (S_xstr(SIM_ARCHIVE_GIT_COMMIT_TIME), '$')) { fprintf (st, "%ssimh git commit time: %s", "\n ", S_xstr(SIM_ARCHIVE_GIT_COMMIT_TIME)); } #endif -#undef S_str -#undef S_xstr #endif #if defined(SIM_GIT_COMMIT_ID) -#define S_xstr(a) S_str(a) -#define S_str(a) #a if (1) { const char *extras = strchr (S_xstr(SIM_GIT_COMMIT_ID), '+'); @@ -6721,19 +6716,15 @@ setenv ("SIM_GIT_COMMIT_TIME", S_xstr(SIM_GIT_COMMIT_TIME), 1); if (flag) fprintf (st, "%sgit commit time: %s", "\n ", S_xstr(SIM_GIT_COMMIT_TIME)); #endif -#undef S_str -#undef S_xstr #endif #if defined(SIM_BUILD) -#define S_xstr(a) S_str(a) -#define S_str(a) #a fprintf (st, "%sBuild: %s", flag ? "\n " : " ", S_xstr(SIM_BUILD)); -#undef S_str -#undef S_xstr #endif fprintf (st, "\n"); if (sim_vm_release_message != NULL) /* if a release message string is defined */ fprintf (st, "\n%s", sim_vm_release_message); /* then display it */ +#undef S_str +#undef S_xstr return SCPE_OK; } @@ -7627,7 +7618,7 @@ if (strcmp (gbuf, "ALL") == 0) return (reset_all (0)); dptr = find_dev (gbuf); /* locate device */ if (dptr == NULL) /* found it? */ - return SCPE_NXDEV; + return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\n", gbuf); if (dptr->reset != NULL) return dptr->reset (dptr); else return SCPE_OK; @@ -7970,7 +7961,7 @@ if (*cptr == 0) /* now eol? */ return SCPE_2FARG; dptr = find_unit (gbuf, &uptr); /* locate unit */ if (dptr == NULL) /* found dev? */ - return SCPE_NXDEV; + return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\n", gbuf); if (uptr == NULL) /* valid unit? */ return SCPE_NXUN; if (uptr->flags & UNIT_ATT) { /* already attached? */ @@ -7982,7 +7973,7 @@ if (uptr->flags & UNIT_ATT) { /* already attached? */ } else { if (!(uptr->dynflags & UNIT_ATTMULT)) - return SCPE_ALATT; /* Already attached */ + return sim_messagef (SCPE_ALATT, "%s: Already attached\n", sim_uname (uptr)); } } gbuf[sizeof(gbuf)-1] = '\0'; @@ -7996,7 +7987,7 @@ return scp_attach_unit (dptr, uptr, gbuf); /* attach */ t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr) { if (uptr->flags & UNIT_DIS) /* disabled? */ - return SCPE_UDIS; + return sim_messagef (SCPE_UDIS, "Unit disabled: %s\n", sim_uname (uptr)); if (dptr->attach != NULL) /* device routine? */ return dptr->attach (uptr, (CONST char *)cptr); /* call it */ return attach_unit (uptr, (CONST char *)cptr); /* no, std routine */ @@ -8116,7 +8107,7 @@ if (strcmp (gbuf, "ALL") == 0) return (detach_all (0, FALSE)); dptr = find_unit (gbuf, &uptr); /* locate unit */ if (dptr == NULL) /* found dev? */ - return SCPE_NXDEV; + return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\n", gbuf); if (uptr == NULL) /* valid unit? */ return SCPE_NXUN; return scp_detach_unit (dptr, uptr); /* detach */ @@ -8237,7 +8228,7 @@ if (*cptr == 0) /* now eol? */ return SCPE_2FARG; dptr = find_dev (gbuf); /* locate device */ if (dptr == NULL) /* found dev? */ - return SCPE_NXDEV; + return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\n", gbuf); cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ if (*cptr != 0) /* must be eol */ return SCPE_2MARG; @@ -8274,7 +8265,7 @@ if (*cptr != 0) /* now eol? */ return SCPE_2MARG; dptr = find_dev (gbuf); /* locate device */ if (dptr == NULL) /* found dev? */ - return SCPE_NXDEV; + return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\n", gbuf); return deassign_device (dptr); } @@ -9038,13 +9029,13 @@ else if (flag == RU_BOOT) { /* boot */ return SCPE_2MARG; dptr = find_unit (gbuf, &uptr); /* locate unit */ if (dptr == NULL) /* found dev? */ - return SCPE_NXDEV; + return sim_messagef (SCPE_NXDEV, "Non-existent device: %s\n", gbuf); if (uptr == NULL) /* valid unit? */ return SCPE_NXUN; if (dptr->boot == NULL) /* can it boot? */ return SCPE_NOFNC; if (uptr->flags & UNIT_DIS) /* disabled? */ - return SCPE_UDIS; + return sim_messagef (SCPE_UDIS, "Unit disabled: %s\n", sim_uname (uptr)); if ((uptr->flags & UNIT_ATTABLE) && /* if attable, att? */ !(uptr->flags & UNIT_ATT)) return SCPE_UNATT; @@ -9551,7 +9542,7 @@ t_stat reason; int32 saved_switches = sim_switches; if (uptr->flags & UNIT_DIS) /* disabled? */ - return SCPE_UDIS; + return sim_messagef (SCPE_UDIS, "Unit disabled: %s\n", sim_uname (uptr)); mask = (t_addr) width_mask[dptr->awidth]; if ((low > mask) || (high > mask) || (low > high)) return SCPE_ARG; diff --git a/sim_console.c b/sim_console.c index 6f5411f..13a26b0 100644 --- a/sim_console.c +++ b/sim_console.c @@ -2897,8 +2897,10 @@ if (!sim_rem_master_mode) { } } tmxr_poll_rx (&sim_con_tmxr); /* poll for input */ -if ((c = (t_stat)tmxr_getc_ln (&sim_con_ldsc))) /* any char? */ +if ((c = (t_stat)tmxr_getc_ln (&sim_con_ldsc))) { /* any char? */ + sim_debug (DBG_RCV, &sim_con_telnet, "sim_poll_kbd() tmxr_getc_ln() returning: '%c' (0x%02X)\n", sim_isprint (c & 0xFF) ? c & 0xFF : '.', c); return (c & (SCPE_BREAK | 0377)) | SCPE_KFLAG; + } return SCPE_OK; } diff --git a/sim_ether.c b/sim_ether.c index 95e9489..5c29f6e 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -383,6 +383,9 @@ /* Internal routine - forward declaration */ static int _eth_get_system_id (char *buf, size_t buf_size); +static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname, int set_on); + +static const unsigned char framer_oui[3] = { 0xaa, 0x00, 0x03 }; /*============================================================================*/ /* OS-independant ethernet routines */ @@ -780,13 +783,11 @@ return eth_show (st, uptr, val, NULL); } #if defined (USE_NETWORK) || defined (USE_SHARED) -/* Internal routine - forward declaration */ -static int _eth_devices (int max, ETH_LIST* dev); /* get ethernet devices on host */ static const char* _eth_getname(int number, char* name, char *desc) { ETH_LIST list[ETH_MAX_DEVICE]; - int count = _eth_devices(ETH_MAX_DEVICE, list); + int count = eth_devices(ETH_MAX_DEVICE, list, FALSE); if ((number < 0) || (count <= number)) return NULL; @@ -803,7 +804,7 @@ static const char* _eth_getname(int number, char* name, char *desc) const char* eth_getname_bydesc(const char* desc, char* name, char *ndesc) { ETH_LIST list[ETH_MAX_DEVICE]; - int count = _eth_devices(ETH_MAX_DEVICE, list); + int count = eth_devices(ETH_MAX_DEVICE, list, FALSE); int i; size_t j=strlen(desc); @@ -829,7 +830,7 @@ const char* eth_getname_bydesc(const char* desc, char* name, char *ndesc) char* eth_getname_byname(const char* name, char* temp, char *desc) { ETH_LIST list[ETH_MAX_DEVICE]; - int count = _eth_devices(ETH_MAX_DEVICE, list); + int count = eth_devices(ETH_MAX_DEVICE, list, FALSE); size_t n; int i, found; @@ -849,7 +850,7 @@ char* eth_getname_byname(const char* name, char* temp, char *desc) char* eth_getdesc_byname(char* name, char* temp) { ETH_LIST list[ETH_MAX_DEVICE]; - int count = _eth_devices(ETH_MAX_DEVICE, list); + int count = eth_devices(ETH_MAX_DEVICE, list, FALSE); size_t n; int i, found; @@ -894,7 +895,7 @@ t_stat eth_show (FILE* st, UNIT* uptr, int32 val, CONST void* desc) ETH_LIST list[ETH_MAX_DEVICE]; int number; - number = _eth_devices(ETH_MAX_DEVICE, list); + number = eth_devices(ETH_MAX_DEVICE, list, FALSE); fprintf(st, "ETH devices:\n"); if (number == -1) fprintf(st, " network support not available in simulator\n"); @@ -965,6 +966,8 @@ t_stat eth_filter_hash (ETH_DEV* dev, int addr_count, ETH_MAC* const addresses, {return SCPE_NOFNC;} const char *eth_version (void) {return NULL;} +int eth_devices(int max, ETH_LIST* list, ETH_BOOL framers) + {return 0;} void eth_show_dev (FILE* st, ETH_DEV* dev) {} t_stat eth_show (FILE* st, UNIT* uptr, int32 val, CONST void* desc) @@ -1112,13 +1115,14 @@ for (i=0; inext, ++used) { + for (used=0, dev=alldevs; dev && (used < max); dev=dev->next) { + edev.eth_api = ETH_API_PCAP; + eth_get_nic_hw_addr (&edev, dev->name, 0); + if ((memcmp (edev.host_nic_phy_hw_addr, framer_oui, 3) == 0) != framers) + continue; if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) continue; strlcpy(list[used].name, dev->name, sizeof(list[used].name)); @@ -1137,6 +1145,7 @@ else { strlcpy(list[used].desc, dev->description, sizeof(list[used].desc)); else strlcpy(list[used].desc, "No description available", sizeof(list[used].desc)); + ++used; } /* free device list */ @@ -1152,6 +1161,9 @@ if ((used == 0) && (errbuf[0])) { sim_printf ("Eth: pcap_findalldevs warning: %s\n", errbuf); } +if (framers) + return used; /* don't add pseudo-ethernet devices */ + #ifdef HAVE_TAP_NETWORK if (used < max) { #if defined(__OpenBSD__) @@ -1736,7 +1748,7 @@ static int pcap_mac_if_vms(const char *AdapterName, unsigned char MACAddress[6]) } #endif /* defined (__VMS) && !defined(__VAX) */ -static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname) +static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname, int set_on) { memset(&dev->host_nic_phy_hw_addr, 0, sizeof(dev->host_nic_phy_hw_addr)); dev->have_host_nic_phy_addr = 0; @@ -1755,24 +1767,26 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname) int i; char tool[CBUFSIZE]; const char *turnon[] = { - "ip link set dev %.*s up", - "ifconfig %.*s up", + "ip link set dev %.*s up 2>/dev/null", + "ifconfig %.*s up 2>/dev/null", NULL}; const char *patterns[] = { - "ip link show %.*s | grep [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]", - "ip link show %.*s | egrep [0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]", - "ifconfig %.*s | grep [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]", - "ifconfig %.*s | egrep [0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]", + "ip link show %.*s 2>/dev/null | grep [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]", + "ip link show %.*s 2>/dev/null | egrep [0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]", + "ifconfig %.*s 2>/dev/null | grep [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]", + "ifconfig %.*s 2>/dev/null | egrep [0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]", NULL}; memset(command, 0, sizeof(command)); - /* try to force an otherwise unused interface to be turned on */ - for (i=0; turnon[i]; ++i) { - snprintf(command, sizeof(command), turnon[i], (int)(sizeof(command) - (2 + strlen(patterns[i]))), devname); - get_glyph_nc (command, tool, 0); - if (sim_get_tool_path (tool)[0]) { - if (NULL != (f = popen(command, "r"))) - pclose(f); + if (set_on) { + /* try to force an otherwise unused interface to be turned on */ + for (i=0; turnon[i]; ++i) { + snprintf(command, sizeof(command), turnon[i], (int)(sizeof(command) - (2 + strlen(patterns[i]))), devname); + get_glyph_nc (command, tool, 0); + if (sim_get_tool_path (tool)[0]) { + if (NULL != (f = popen(command, "r"))) + pclose(f); + } } } for (i=0; patterns[i] && (0 == dev->have_host_nic_phy_addr); ++i) { @@ -2500,12 +2514,13 @@ if (bufsz < ETH_MAX_JUMBO_FRAME) /* initialize device */ eth_zero(dev); -/* translate name of type "ethX" to real device name */ -if ((strlen(name) == 4) +/* translate name of type "eth" to real device name */ +if ((strlen(name) == 4 || strlen(name) == 5) && (tolower(name[0]) == 'e') && (tolower(name[1]) == 't') && (tolower(name[2]) == 'h') && isdigit(name[3]) + && (strlen(name) == 4 || isdigit(name[4])) ) { num = atoi(&name[3]); savname = _eth_getname(num, temp, desc); @@ -2545,7 +2560,7 @@ if (!strcmp (desc, "No description available")) sim_messagef (SCPE_OK, "Eth: opened OS device %s%s%s\n", savname, desc[0] ? " - " : "", desc); /* get the NIC's hardware MAC address */ -eth_get_nic_hw_addr(dev, savname); +eth_get_nic_hw_addr(dev, savname, 1); /* save name of device */ dev->name = (char *)malloc(strlen(savname)+1); @@ -4368,7 +4383,7 @@ int bpf_compile_skip_count = 0; memset (ð_tst, 0, sizeof(eth_tst)); -eth_device_count = _eth_devices(ETH_MAX_DEVICE, eth_list); +eth_device_count = eth_devices(ETH_MAX_DEVICE, eth_list, FALSE); eth_opened = 0; for (eth_num=0; eth_numd_name, "..")) { char path[1024], devicepath[1024], driverpath[1024]; - sprintf (path, "/sys/class/tty/%s", namelist[i]->d_name); - sprintf (devicepath, "/sys/class/tty/%s/device", namelist[i]->d_name); - sprintf (driverpath, "/sys/class/tty/%s/device/driver", namelist[i]->d_name); + snprintf (path, sizeof (path), "/sys/class/tty/%s", namelist[i]->d_name); + snprintf (devicepath, sizeof (devicepath), "/sys/class/tty/%s/device", namelist[i]->d_name); + snprintf (driverpath, sizeof (driverpath), "/sys/class/tty/%s/device/driver", namelist[i]->d_name); if ((lstat(devicepath, &st) == 0) && S_ISLNK(st.st_mode)) { char buffer[1024]; memset (buffer, 0, sizeof(buffer)); if (readlink(driverpath, buffer, sizeof(buffer)) > 0) { - sprintf (list[ports].name, "/dev/%s", basename (path)); + snprintf (list[ports].name, sizeof (list[ports].name), "/dev/%s", basename (path)); port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK); /* open the port */ if (port != -1) { /* open OK? */ - if (isatty (port)) /* is device a TTY? */ + if ((ports < max) && /* room for another? */ + (isatty (port))) /* is device a TTY? */ ++ports; close (port); } @@ -990,7 +989,7 @@ if (1) { } #elif defined(__hpux) for (i=0; (ports < max) && (i < 64); ++i) { - sprintf (list[ports].name, "/dev/tty%dp%d", i/8, i%8); + snprintf (list[ports].name, sizeof (list[ports].name), "/dev/tty%dp%d", i/8, i%8); port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK); /* open the port */ if (port != -1) { /* open OK? */ if (isatty (port)) /* is device a TTY? */ @@ -999,44 +998,27 @@ for (i=0; (ports < max) && (i < 64); ++i) { } } #else /* Non Linux/HP-UX, just try some well known device names */ +/* modern UNIX serial port names - usually USB */ +static char *serial_unix_serial_names[] = { "S", "U", "USB", ".serial", ".usbserial", NULL}; +char **sp; + +for (sp = serial_unix_serial_names; *sp; sp++) { + for (i=0; (ports < max) && (i <= 64); ++i) { + if (i < 64) + snprintf (list[ports].name, sizeof (list[ports].name), "/dev/tty%s%d", *sp, i); + else /* no trailing number */ + snprintf (list[ports].name, sizeof (list[ports].name), "/dev/tty%s", *sp); + port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK); /* open the port */ + if (port != -1) { /* open OK? */ + if (isatty (port)) /* is device a TTY? */ + ++ports; + close (port); + } + } + } +/* now the traditional UNIX serial port names */ for (i=0; (ports < max) && (i < 64); ++i) { - sprintf (list[ports].name, "/dev/ttyS%d", i); - port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK); /* open the port */ - if (port != -1) { /* open OK? */ - if (isatty (port)) /* is device a TTY? */ - ++ports; - close (port); - } - } -for (i=0; (ports < max) && (i < 64); ++i) { - sprintf (list[ports].name, "/dev/ttyUSB%d", i); - port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK); /* open the port */ - if (port != -1) { /* open OK? */ - if (isatty (port)) /* is device a TTY? */ - ++ports; - close (port); - } - } -for (i=1; (ports < max) && (i < 64); ++i) { - sprintf (list[ports].name, "/dev/tty.serial%d", i); - port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK); /* open the port */ - if (port != -1) { /* open OK? */ - if (isatty (port)) /* is device a TTY? */ - ++ports; - close (port); - } - } -for (i=0; (ports < max) && (i < 64); ++i) { - sprintf (list[ports].name, "/dev/tty%02d", i); - port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK); /* open the port */ - if (port != -1) { /* open OK? */ - if (isatty (port)) /* is device a TTY? */ - ++ports; - close (port); - } - } -for (i=0; (ports < max) && (i < 8); ++i) { - sprintf (list[ports].name, "/dev/ttyU%d", i); + snprintf (list[ports].name, sizeof (list[ports].name), "/dev/tty%02d", i); port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK); /* open the port */ if (port != -1) { /* open OK? */ if (isatty (port)) /* is device a TTY? */ @@ -1044,6 +1026,7 @@ for (i=0; (ports < max) && (i < 8); ++i) { close (port); } } + #endif return ports; } @@ -1127,10 +1110,6 @@ if (tcgetattr (port, &tio)) { /* get the terminal attr return INVALID_HANDLE; /* and return failure to caller */ } -// which of these methods is best? - -#if 1 - tio.c_iflag = (tio.c_iflag & ~i_clear) | i_set; /* configure the serial line for raw mode */ tio.c_oflag = (tio.c_oflag & ~o_clear) | o_set; tio.c_cflag = (tio.c_cflag & ~c_clear) | c_set; @@ -1142,24 +1121,6 @@ tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; #endif -#elif 0 - -tio.c_iflag &= ~(IGNBRK | BRKINT | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF); -tio.c_iflag |= PARMRK | IGNPAR; -tio.c_oflag &= ~(OPOST); -tio.c_cflag &= ~(HUPCL); -tio.c_cflag |= CREAD | CLOCAL; -tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | NOFLSH | TOSTOP | IEXTEN); - -#elif 0 - -tio.c_iflag = PARMRK | IGNPAR; -tio.c_oflag = 0; -tio.c_cflag = tio.c_cflag | CLOCAL | CREAD; -tio.c_lflag = 0; - -#endif - if (tcsetattr (port, TCSANOW, &tio)) { /* set the terminal attributes */ sim_error_serial ("tcsetattr", errno); /* function failed; report unexpected error */ close (port); /* close the port */ diff --git a/sim_tmxr.c b/sim_tmxr.c index e5e40f9..cf831d8 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -336,6 +336,7 @@ #include "sim_sock.h" #include "sim_timer.h" #include "sim_tmxr.h" +#include "sim_ether.h" #include "scp.h" #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -422,6 +423,43 @@ #define TNOS_DONT 001 /* Don't has been sent */ #define TNOS_WONT 002 /* Won't has been sent */ +/* Lifted from ddcmp.c in the framer firmware */ +struct status_msg_t +{ + uint8 dc1; + uint8 on; /* "on" flags */ + uint16 mflags; + uint32 speed; + uint32 txspeed; + uint32 rxframes; + uint32 rxbytes; + uint32 txframes; + uint32 txbytes; + uint32 hcrc_err; + uint32 crc_err; + uint32 len_err; + uint32 nobuf_err; + uint32 last_cmd_sts; /* Response code from last command */ + uint32 freq; /* Measured frequency */ + char version[64]; +}; +#define ON_ACT 1 +#define ON_SYN 2 +#define ON_CLKOK 4 + +/* This struct is internal to sim_tmxr, used when a line is attached + * to a DDCMP synchronous framer device (a USB peripheral that looks + * like an Ethernet interface). + */ +typedef struct framer_data { + ETH_DEV *eth; /* Ethernet device pointer if framer */ + uint16 fmode; /* Framer mode from attach command */ + uint32 fspeed; /* Framer link speed from attach command */ + struct status_msg_t status; /* Last received status message */ + int status_cnt; /* Count of status messages seen */ + t_bool connect_pending; /* True if connected not yet reported */ +} FRAMER; + static BITFIELD tmxr_modem_bits[] = { BIT(DTR), /* Data Terminal Ready */ BIT(RTS), /* Request To Send */ @@ -445,6 +483,9 @@ static u_char mantra[] = { /* Telnet Option Negotiation Mantra #define TMXR_LINE_DISABLED (-1) /* Local routines */ +static void tmxr_setup_framer(TMLN *line, ETH_PACK *packet, int len); +static int tmxr_framer_read (TMLN *line, char *buf, int nbytes); +static int tmxr_framer_write (TMLN *line, const char *buf, int32 length); static void tmxr_add_to_open_list (TMXR* mux); @@ -685,8 +726,12 @@ if (lp->loopback) return loop_read (lp, &(lp->rxb[i]), length); if (lp->serport) /* serial port connection? */ return sim_read_serial (lp->serport, &(lp->rxb[i]), length, &(lp->rbr[i])); -else /* Telnet connection */ - return sim_read_sock (lp->sock, &(lp->rxb[i]), length); +else { + if (lp->framer) + return tmxr_framer_read (lp, &(lp->rxb[i]), length); + else /* Telnet connection */ + return sim_read_sock (lp->sock, &(lp->rxb[i]), length); + } } @@ -712,23 +757,27 @@ if (lp->serport) { /* serial port connectio written = sim_write_serial (lp->serport, &(lp->txb[i]), length); } else { - if (lp->sock) { /* Telnet connection */ - written = sim_write_sock (lp->sock, &(lp->txb[i]), length); - - if (written == SOCKET_ERROR) { /* did an error occur? */ - lp->txdone = TRUE; - if (lp->datagram) - return written; /* ignore errors on datagram sockets */ - else - return -1; /* return error indication */ - } - } + if (lp->framer) + written = tmxr_framer_write (lp, &(lp->txb[i]), length); else { - if ((lp->conn == TMXR_LINE_DISABLED) || - ((lp->conn == 0) && lp->txbfd)){ - written = length; /* Count here output timing is correct */ - if (lp->conn == TMXR_LINE_DISABLED) - lp->txdrp += length; /* Record as having been dropped on the floor */ + if (lp->sock) { /* Telnet connection */ + written = sim_write_sock (lp->sock, &(lp->txb[i]), length); + + if (written == SOCKET_ERROR) { /* did an error occur? */ + lp->txdone = TRUE; + if (lp->datagram) + return written; /* ignore errors on datagram sockets */ + else + return -1; /* return error indication */ + } + } + else { + if ((lp->conn == TMXR_LINE_DISABLED) || + ((lp->conn == 0) && lp->txbfd)){ + written = length; /* Count here output timing is correct */ + if (lp->conn == TMXR_LINE_DISABLED) + lp->txdrp += length; /* Record as having been dropped on the floor */ + } } } } @@ -1091,6 +1140,9 @@ if (mp->master) { for (j = 0; j < mp->lines; j++, i++) { /* find next avail line */ lp = mp->ldsc + j; /* get pointer to line descriptor */ + if (lp->framer) + continue; + if ((lp->conn == FALSE) && /* is the line available? */ (lp->destination == NULL) && (lp->master == 0) && @@ -1172,6 +1224,17 @@ for (i = 0; i < mp->lines; i++) { /* check each line in se return i; } + /* Framer: report connected. */ + if (lp->framer) { + if (lp->framer->connect_pending) { + /* Say "connected" when first asked */ + lp->framer->connect_pending = FALSE; + lp->conn = TRUE; /* record connection */ + return i; + } + continue; + } + /* Don't service network connections for loopbacked lines */ if (lp->loopback) @@ -1660,10 +1723,14 @@ return SCPE_OK; Implementation note: - If a line is connected to a serial port, then these values affect - and reflect the state of the serial port. If the line is connected - to a network socket (or could be) then the network session state is - set, cleared and/or returned. + If a line is connected to a serial port, then these values + affect and reflect the state of the serial port. If the line + is connected to a network socket (or could be) then the network + session state is set, cleared and/or returned. If the line is + connected to a DDCMP sync framer, only DTR and RTS set/clear + are acted on, and the returned modem state bits are constructed + based on the framer state. For the framer, setting DTR starts + the framer, and clearing DTR stops it. */ t_stat tmxr_set_get_modem_bits (TMLN *lp, int32 bits_to_set, int32 bits_to_clear, int32 *status_bits) { @@ -1676,6 +1743,37 @@ if ((bits_to_set & ~(TMXR_MDM_OUTGOING)) || /* Assure only settable bits (bits_to_clear & ~(TMXR_MDM_OUTGOING)) || (bits_to_set & bits_to_clear)) /* and can't set and clear the same bits */ return SCPE_ARG; +if (lp->framer) { + /* DDCMP framer attached, ignore set except for DTR and RTS. + * Given the most recently received framer status, report DSR if + * the framer is currently on, and CTS and Carrier Detect if a + * carrier has been received. + */ + bits_to_set &= TMXR_MDM_DTR | TMXR_MDM_RTS; + bits_to_clear &= TMXR_MDM_DTR | TMXR_MDM_RTS; + if ((bits_to_set & TMXR_MDM_DTR) && !(lp->modembits & TMXR_MDM_DTR)) { + /* DTR being set, start framer if we're using one. Use DMC + * mode for now. + */ + tmxr_start_framer (lp, TRUE); + } + else { + if ((bits_to_clear & TMXR_MDM_DTR) && (lp->modembits & TMXR_MDM_DTR)) + /* DTR being cleared, stop framer if we're using one. */ + tmxr_stop_framer (lp); + } + incoming_state = lp->modembits | bits_to_set; + incoming_state &= ~bits_to_clear; + if (lp->framer->status.on) + incoming_state |= TMXR_MDM_DSR; + if (lp->framer->status.on & ON_SYN) + /* Carrier detected */ + incoming_state |= TMXR_MDM_CTS | TMXR_MDM_DCD; + lp->modembits = incoming_state; + if (status_bits) + *status_bits = incoming_state; + return SCPE_OK; +} before_modem_bits = lp->modembits; lp->modembits |= bits_to_set; lp->modembits &= ~bits_to_clear; @@ -2023,7 +2121,7 @@ TMLN *lp; tmxr_debug_trace (mp, "tmxr_poll_rx()"); for (i = 0; i < mp->lines; i++) { /* loop thru lines */ lp = mp->ldsc + i; /* get line desc */ - if (!(lp->sock || lp->serport || lp->loopback) || + if (!(lp->sock || lp->serport || lp->loopback || lp->framer) || !(lp->rcve)) /* skip if not connected */ continue; @@ -2031,9 +2129,11 @@ for (i = 0; i < mp->lines; i++) { /* loop thru lines */ if (lp->rxbpi == 0) /* need input? */ nbytes = tmxr_read (lp, /* yes, read */ lp->rxbsz - TMXR_GUARD); /* leave spc for Telnet cruft */ - else if (lp->tsta) /* in Telnet seq? */ - nbytes = tmxr_read (lp, /* yes, read to end */ - lp->rxbsz - lp->rxbpi); + else { + if (lp->tsta) /* in Telnet seq? */ + nbytes = tmxr_read (lp, /* yes, read to end */ + lp->rxbsz - lp->rxbpi); + } if (nbytes < 0) { /* line error? */ if (!lp->datagram) { /* ignore errors reading UDP sockets */ @@ -2538,6 +2638,17 @@ return 0; /* not done */ static void _mux_detach_line (TMLN *lp, t_bool close_listener, t_bool close_connecting) { +if (lp->framer) { + /* DDCMP framer in use, close that up. Begin by making sure it is + * stopped. + */ + tmxr_stop_framer (lp); + /* Finished with the framer's Ethernet interface */ + eth_close (lp->framer->eth); + free (lp->framer->eth); + free (lp->framer); + lp->framer = NULL; + } if (close_listener && lp->master) { sim_close_sock (lp->master); lp->master = 0; @@ -2700,6 +2811,21 @@ if (lp->o_uptr) return SCPE_OK; } +static const char* _tmxr_getname(int number, char* name) +{ + ETH_LIST list[ETH_MAX_DEVICE]; + int count = eth_devices(ETH_MAX_DEVICE, list, TRUE); + + if ((number < 0) || (count <= number)) + return NULL; + if (list[number].eth_api != ETH_API_PCAP) { + sim_printf ("Tmxr: Synchronous line device not found. You may need to run as root\n"); + return NULL; + } + + strcpy(name, list[number].name); + return name; +} /* Open a master listening socket (and all of the other variances of connections). @@ -2719,6 +2845,12 @@ int32 i, line, nextline = -1; char tbuf[CBUFSIZE], listen[CBUFSIZE], destination[CBUFSIZE], logfiletmpl[CBUFSIZE], buffered[CBUFSIZE], hostport[CBUFSIZE], port[CBUFSIZE], option[CBUFSIZE], speed[CBUFSIZE], dev_name[CBUFSIZE]; +char framer[CBUFSIZE],fr_eth[CBUFSIZE]; +int num; +int8 fr_mode; +int32 fr_speed; +FRAMER *framer_s; +ETH_DEV *eth; SOCKET sock; SERHANDLE serport; CONST char *tptr = cptr; @@ -2752,6 +2884,7 @@ while (*tptr) { memset(port, '\0', sizeof(port)); memset(option, '\0', sizeof(option)); memset(speed, '\0', sizeof(speed)); + memset(framer, '\0', sizeof(framer)); nolog = loopback = disabled = FALSE; datagram = mp->datagram; packet = mp->packet; @@ -2852,6 +2985,13 @@ while (*tptr) { strlcpy (destination, cptr, sizeof(destination)); continue; } + if (0 == MATCH_CMD (gbuf, "SYNC")) { + if ((NULL == cptr) || ('\0' == *cptr)) + return sim_messagef (SCPE_2FARG, "Missing Framer Specifier\n"); + strlcpy (framer, cptr, sizeof(framer)); + nomessage = notelnet = datagram = TRUE; + continue; + } if (0 == MATCH_CMD (gbuf, "DISABLED")) { if ((NULL != cptr) && ('\0' != *cptr)) return sim_messagef (SCPE_2FARG, "Unexpected Disabled Specifier: %s\n", cptr); @@ -2922,11 +3062,13 @@ while (*tptr) { } } if (disabled) { - if (destination[0] || listen[0] || loopback) - return sim_messagef (SCPE_ARG, "Can't disable line with%s%s%s%s%s\n", destination[0] ? " CONNECT=" : "", destination, listen[0] ? " " : "", listen, loopback ? " LOOPBACK" : ""); + if (destination[0] || listen[0] || loopback || framer[0]) + return sim_messagef (SCPE_ARG, "Can't disable line with%s%s%s%s%s%s%s\n", destination[0] ? " CONNECT=" : "", destination, listen[0] ? " " : "", listen, loopback ? " LOOPBACK" : "", framer[0] ? " SYNC=" : "", framer); } if (destination[0]) { /* Validate destination */ + if (framer[0]) + return sim_messagef (SCPE_ARG, "Can't combine CONNECT=%s with SYNC=%s\n", destination, framer); serport = sim_open_serial (destination, NULL, &r); if (serport != INVALID_HANDLE) { sim_close_serial (serport); @@ -2961,9 +3103,62 @@ while (*tptr) { return sim_messagef (SCPE_ARG, "Invalid destination: %s\n", hostport); } } + if (framer[0]) { + if (listen[0] || loopback || (!notelnet) || (!datagram)) + return sim_messagef (SCPE_ARG, "Can't combined SYNC=%s with%s%s%s%s%s\n", framer, + listen[0] ? " " : "", listen, loopback ? " LOOPBACK" : "", + notelnet ? "" : " TELNET", + datagram ? "" : " STREAM"); + /* Validate framer spec */ + cptr = get_glyph_nc (framer, fr_eth, ':'); + cptr = get_glyph (cptr, option, ':'); + if (0 == MATCH_CMD (option, "INTEGRAL") || + 0 == MATCH_CMD (option, "COAX")) + fr_mode = 1; + else { + if (0 == MATCH_CMD (option, "LOOPBACK")) + fr_mode = 1 | 4; /* Integral modem, loopback */ + else + if (0 == MATCH_CMD (option, "RS232_DCE")) + fr_mode = 2; + else + if (0 == MATCH_CMD (option, "RS232_DTE")) + fr_mode = 0; + else + return sim_messagef (SCPE_ARG, "Invalid framer mode: %s\n", cptr); + } + /* Speed is a third value in the SYNC argument. We don't + * use the SPEED parameter because that only accepts the + * standard UART rates, which for the most part are not normal + * DDCMP line rates. + */ + fr_speed = 0; + if (cptr) + fr_speed = atoi (cptr); + /* Note that the framer ignores the speed parameter for DTE + * mode, but we require it here in order to have a speed value + * to control the scheduling machinery. It would be possible + * to make it optional and default it to some useable value + * like 56k, or to default it that way and then later set it + * according to the measured data rate reported by the framer. + * For now, don't bother. + * + * Also, while the minimum speed is usually 500 bps, it is 56k + * for integral modem mode -- the transformer coupling does + * not work reliably at speeds lower than that, and this + * matches the lowest speed supported by DEC hardware for that + * interface type. + */ + if (fr_speed < 500 || fr_speed > 1000000 || + (fr_speed < 56000 && (fr_mode & 1))) { + return sim_messagef (SCPE_ARG, "Invalid framer speed %d\n", fr_speed); + } + } if (line == -1) { if (disabled) return sim_messagef (SCPE_ARG, "Must specify line to disable\n"); + if (framer[0]) + return sim_messagef (SCPE_ARG, "Must specify line for framer\n"); if (modem_control != mp->modem_control) return SCPE_ARG; if (logfiletmpl[0]) { @@ -3016,6 +3211,8 @@ while (*tptr) { } } } + if (lp->framer) + continue; /* skip framer lines */ if ((listen[0]) && (!datagram)) { sock = sim_master_sock (listen, &r); /* make master socket */ if (r) @@ -3145,6 +3342,57 @@ while (*tptr) { else { /* line specific attach */ lp = &mp->ldsc[line]; lp->mp = mp; + if (framer[0]) { + /* translate name of type "sync" to real eth device name */ + if ((strlen(fr_eth) == 5 || strlen(fr_eth) == 6) + && (tolower(fr_eth[0]) == 's') + && (tolower(fr_eth[1]) == 'y') + && (tolower(fr_eth[2]) == 'n') + && (tolower(fr_eth[3]) == 'c') + && isdigit(fr_eth[4]) + && (strlen(fr_eth) == 5 || isdigit(fr_eth[5])) + ) { + num = atoi(&fr_eth[4]); + if (_tmxr_getname(num, fr_eth) == NULL) /* didn't translate */ + return SCPE_OPENERR; + } + /* Open the Ethernet device */ + framer_s = (FRAMER *)malloc (sizeof (FRAMER)); + memset (framer_s, 0, sizeof (*framer_s)); + eth = (ETH_DEV *)malloc (sizeof (ETH_DEV)); + memset (eth, 0, sizeof (*eth)); + eth->dptr = mp->dptr; + framer_s->eth = eth; + framer_s->connect_pending = TRUE; + r = eth_open (eth, fr_eth, mp->dptr, 0); + if (r != SCPE_OK) { + sim_messagef (r, "Eth open error %d\n", r); + free (eth); + free (framer_s); + return r; + } + /* Set the filters: our address, not all multi, not promiscuous */ + r = eth_filter (eth, 1, &(eth->host_nic_phy_hw_addr), 0, 0); + if (r != SCPE_OK) { + sim_messagef (r, "Eth set address filter error %d\n", r); + eth_close (eth); + free (eth); + free (framer_s); + return r; + } + lp = &mp->ldsc[line]; + lp->framer = framer_s; + lp->datagram = lp->notelnet = TRUE; + /* Remember these parameters for later; the framer is + * started separately; in the DMC/DMP emulation this is + * done at DDCMP startup to allow a DMP driver to select + * the mode via the device API. */ + framer_s->fmode = fr_mode; + framer_s->fspeed = fr_speed; + /* Set the scheduling parameters from the line speed */ + lp->txdeltausecs = lp->rxdeltausecs = (uint32) (8000000 / fr_speed); + tmxr_init_line (lp); /* initialize line state */ + } if (logfiletmpl[0]) { sim_close_logfile (&lp->txlogref); lp->txlog = NULL; @@ -3182,7 +3430,7 @@ while (*tptr) { } if ((listen[0]) && (!datagram)) { if ((mp->lines == 1) && (mp->master)) - return sim_messagef (SCPE_ARG, "Single Line MUX can have either line specific OR MUS listener but NOT both\n"); + return sim_messagef (SCPE_ARG, "Single Line MUX can have either line specific OR MUX listener but NOT both\n"); sock = sim_master_sock (listen, &r); /* make master socket */ if (r) return sim_messagef (SCPE_ARG, "Invalid Listen Specification: %s\n", listen); @@ -3219,34 +3467,36 @@ while (*tptr) { tmxr_report_connection (mp, lp); /* report the connection to the line */ } else { - lp->datagram = datagram; - if (datagram) { - if (listen[0]) { - lp->port = (char *)realloc (lp->port, 1 + strlen (listen)); - strcpy (lp->port, listen); /* save port */ + if (!lp->framer) { + lp->datagram = datagram; + if (datagram) { + if (listen[0]) { + lp->port = (char *)realloc (lp->port, 1 + strlen (listen)); + strcpy (lp->port, listen); /* save port */ + } + else + return sim_messagef (SCPE_ARG, "Missing listen port for Datagram socket\n"); + } + sock = sim_connect_sock_ex (datagram ? listen : NULL, hostport, "localhost", NULL, (datagram ? SIM_SOCK_OPT_DATAGRAM : 0) | + (packet ? SIM_SOCK_OPT_NODELAY : 0)); + if (sock != INVALID_SOCKET) { + _mux_detach_line (lp, FALSE, TRUE); + lp->destination = (char *)malloc(1+strlen(hostport)); + strcpy (lp->destination, hostport); + if (!lp->modem_control || (lp->modembits & TMXR_MDM_DTR)) { + lp->connecting = sock; + lp->ipad = (char *)malloc (1 + strlen (lp->destination)); + strcpy (lp->ipad, lp->destination); + } + else + sim_close_sock (sock); + lp->notelnet = notelnet; + lp->nomessage = nomessage; + tmxr_init_line (lp); /* init the line state */ } else - return sim_messagef (SCPE_ARG, "Missing listen port for Datagram socket\n"); + return sim_messagef (SCPE_ARG, "Can't open %s socket on %s%s%s\n", datagram ? "Datagram" : "Stream", datagram ? listen : "", datagram ? "<->" : "", hostport); } - sock = sim_connect_sock_ex (datagram ? listen : NULL, hostport, "localhost", NULL, (datagram ? SIM_SOCK_OPT_DATAGRAM : 0) | - (packet ? SIM_SOCK_OPT_NODELAY : 0)); - if (sock != INVALID_SOCKET) { - _mux_detach_line (lp, FALSE, TRUE); - lp->destination = (char *)malloc(1+strlen(hostport)); - strcpy (lp->destination, hostport); - if (!lp->modem_control || (lp->modembits & TMXR_MDM_DTR)) { - lp->connecting = sock; - lp->ipad = (char *)malloc (1 + strlen (lp->destination)); - strcpy (lp->ipad, lp->destination); - } - else - sim_close_sock (sock); - lp->notelnet = notelnet; - lp->nomessage = nomessage; - tmxr_init_line (lp); /* init the line state */ - } - else - return sim_messagef (SCPE_ARG, "Can't open %s socket on %s%s%s\n", datagram ? "Datagram" : "Stream", datagram ? listen : "", datagram ? "<->" : "", hostport); } } if (loopback) { @@ -4305,7 +4555,7 @@ TMLN *lp; for (i = 0; i < mp->lines; i++) { /* loop thru conn */ lp = mp->ldsc + i; - if (!lp->destination && lp->sock) { /* not serial and is connected? */ + if (!lp->destination && lp->sock) { /* not serial and is connected? */ tmxr_report_disconnection (lp); /* report disconnection */ tmxr_reset_ln (lp); /* disconnect line */ } @@ -4978,7 +5228,7 @@ static const char *dsab = "off"; if (ln >= 0) fprintf (st, "Line %d:", ln); -if ((!lp->sock) && (!lp->connecting) && (!lp->serport)) +if ((!lp->sock) && (!lp->connecting) && (!lp->serport) && (!lp->framer)) fprintf (st, " not connected\n"); else { if (ln >= 0) @@ -5410,6 +5660,35 @@ if (any == 0) return SCPE_OK; } +/* Show synchronous devices */ + +t_stat tmxr_show_sync_devices (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char *desc) +{ +return tmxr_show_sync (st, uptr, val, NULL); +} + +t_stat tmxr_show_sync (FILE* st, UNIT* uptr, int32 val, CONST void *desc) +{ + ETH_LIST list[ETH_MAX_DEVICE]; + int number, fcnt = 0; + + number = eth_devices(ETH_MAX_DEVICE, list, TRUE); + fprintf(st, "DDCMP synchronous link devices:\n"); + if (number == -1) + fprintf(st, " network support not available in simulator\n"); + else + if (number == 0) + fprintf(st, " no dddcmp synchronous link devices are available\n"); + else { + int i; + for (i=0; ilines > 1) { } return stat; } + +static int framer_await_status (TMLN *line, int cnt) +{ +int i, stat, xtry, flen; +ETH_PACK framer_rpkt; + +i = line->framer->status_cnt; +xtry = 0; +while (xtry < 5) { + stat = eth_read (line->framer->eth, &framer_rpkt, NULL); + if (stat) { + flen = framer_rpkt.msg[14] + (framer_rpkt.msg[15] << 8); + if (framer_rpkt.msg[18] == 021) { + /* DC1, so it's a framer status message. Save it. */ + if (flen > sizeof (struct status_msg_t)) + flen = sizeof (struct status_msg_t); + memcpy (&line->framer->status, framer_rpkt.msg + 18, flen); + line->framer->status_cnt++; + continue; + } + } + if (i != line->framer->status_cnt) + return 1; + xtry++; + sim_os_ms_sleep (50); + } +tmxr_debug_trace_line (line, "no status received\n"); +return 0; +} + +static void tmxr_setup_framer(TMLN *line, ETH_PACK *packet, int len) +{ +/* First clear everything */ +memset (packet, 0, sizeof (*packet)); +/* Set up the MAC header */ +memcpy (&packet->msg[0], line->framer->eth->physical_addr, 6); +memcpy (&packet->msg[6], line->framer->eth->physical_addr, 6); +/* Framer address is one higher than host interface MAC address */ +packet->msg[5]++; +/* Set ethertype 60-06 */ +packet->msg[12] = 0x60; +packet->msg[13] = 0x06; +/* Set length */ +packet->msg[14] = len & 0xff; +packet->msg[15] = len >> 8; +/* Set length and padded length */ +len += 16; /* Add in header length */ +if (len < 60) + len = 60; +packet->len = len; +packet->crc_len = len + 4; +} + +void tmxr_start_framer (TMLN *line, int dmc_mode) +{ +t_stat ret; +int cnt; +ETH_PACK framer_start; + +if (!line->framer) + /* Not a framer line, NOP */ + return; + +tmxr_setup_framer (line, &framer_start, 8); +framer_start.msg[16] = 0x11; +framer_start.msg[17] = 1; /* Command 1: start framer */ +/* Set DMC mode (DDCMP 3.1) if requested */ +if (dmc_mode) + line->framer->fmode |= 32; +else + line->framer->fmode &= ~32; +/* Set mode in the command buffer */ +framer_start.msg[18] = line->framer->fmode & 0xff; +framer_start.msg[19] = line->framer->fmode >> 8; +/* Set speed in the command buffer */ +framer_start.msg[20] = line->framer->fspeed & 0xff; +framer_start.msg[21] = (line->framer->fspeed >> 8) & 0xff; +framer_start.msg[22] = (line->framer->fspeed >> 16) & 0xff; +framer_start.msg[23] = line->framer->fspeed >> 24; +/* Send the request */ +cnt = line->framer->status_cnt; +ret = eth_write (line->framer->eth, &framer_start, NULL); +framer_await_status (line, cnt); +} + +void tmxr_stop_framer (TMLN *line) +{ +t_stat ret; +int cnt; +ETH_PACK framer_stop; + +if (!line->framer) + /* Not a framer line, NOP */ + return; + +tmxr_setup_framer (line, &framer_stop, 2); +framer_stop.msg[16] = 0x11; +framer_stop.msg[17] = 2; /* Command 2: stop framer */ +/* Send the request */ +cnt = line->framer->status_cnt; +ret = eth_write (line->framer->eth, &framer_stop, NULL); +/* Mark the framer off right now */ +line->framer->status.on = 0; +framer_await_status (line, cnt); +} + +static int tmxr_framer_read (TMLN *line, char *buf, int nbytes) +{ +int stat, flen, fstat; +ETH_PACK framer_rpkt; + +while (1) { + stat = eth_read (line->framer->eth, &framer_rpkt, NULL); + if (!stat) + return 0; + /* Size reported by framer includes status, subtract that */ + flen = (framer_rpkt.msg[14] + (framer_rpkt.msg[15] << 8)) - 2; + fstat = framer_rpkt.msg[16] + (framer_rpkt.msg[17] << 8); + if (framer_rpkt.msg[18] == 021) { + /* DC1, so it's a framer status message. Save it. */ + if (flen > sizeof (struct status_msg_t)) + flen = sizeof (struct status_msg_t); + memcpy (&line->framer->status, + framer_rpkt.msg + 18, flen); + /* report interesting bits */ + sim_debug (TMXR_DBG_RCV, line->dptr, + "framer status, on %d, last_cmd_sts %d\n", + line->framer->status.on, + line->framer->status.last_cmd_sts); + line->framer->status_cnt++; + /* Look for another packet */ + continue; + } + else { + /* Real DDCMP packet. Pass the buffer pointer/len */ + if (flen > nbytes) + flen = nbytes; + memcpy (buf, framer_rpkt.msg + 18, flen); + return flen; + } + } +} + +static int tmxr_framer_write (TMLN *line, const char *buf, int32 length) +{ +t_stat ret; +ETH_PACK framer_tx; + +tmxr_setup_framer (line, &framer_tx, length); +memcpy (&framer_tx.msg[16], buf, length); +/* Send the request */ +ret = eth_write (line->framer->eth, &framer_tx, NULL); +/* Always report the whole thing was written */ +return length; +} + diff --git a/sim_tmxr.h b/sim_tmxr.h index b2b6d86..00933e1 100644 --- a/sim_tmxr.h +++ b/sim_tmxr.h @@ -123,7 +123,8 @@ typedef struct SERPORT *SERHANDLE; #define TMLN_SPD_80000_BPS 125 /* usec per character */ #define TMLN_SPD_115200_BPS 86 /* usec per character */ - +/* Internal struct */ +struct framer_data; typedef struct tmln TMLN; typedef struct tmxr TMXR; @@ -206,6 +207,7 @@ struct tmln { DEVICE *dptr; /* line specific device */ EXPECT expect; /* Expect rules */ SEND send; /* Send input state */ + struct framer_data *framer; /* ddcmp framer data */ }; struct tmxr { @@ -297,6 +299,8 @@ t_stat tmxr_show_summ (FILE *st, UNIT *uptr, int32 val, CONST void *desc); t_stat tmxr_show_cstat (FILE *st, UNIT *uptr, int32 val, CONST void *desc); t_stat tmxr_show_lines (FILE *st, UNIT *uptr, int32 val, CONST void *desc); t_stat tmxr_show_open_devices (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* desc); +t_stat tmxr_show_sync_devices (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char *desc); +t_stat tmxr_show_sync (FILE* st, UNIT* uptr, int32 val, CONST void *desc); t_stat tmxr_flush_log_files (void); t_stat tmxr_activate (UNIT *uptr, int32 interval); t_stat tmxr_activate_abs (UNIT *uptr, int32 interval); @@ -317,6 +321,10 @@ t_stat tmxr_shutdown (void); t_stat tmxr_sock_test (DEVICE *dptr); t_stat tmxr_start_poll (void); t_stat tmxr_stop_poll (void); +/* Framer support. These are a NOP if called on a non-framer line. */ +void tmxr_start_framer (TMLN *line, int dmc_mode); +void tmxr_stop_framer (TMLN *line); + void _tmxr_debug (uint32 dbits, TMLN *lp, const char *msg, char *buf, int bufsize); #define tmxr_debug(dbits, lp, msg, buf, bufsize) do {if (sim_deb && (lp)->mp && (lp)->mp->dptr && ((dbits) & (lp)->mp->dptr->dctrl)) _tmxr_debug (dbits, lp, msg, buf, bufsize); } while (0) #define tmxr_debug_msg(dbits, lp, msg) do {if (sim_deb && (lp)->mp && (lp)->mp->dptr && ((dbits) & (lp)->mp->dptr->dctrl)) sim_debug (dbits, (lp)->mp->dptr, "%s", msg); } while (0) diff --git a/sim_video.c b/sim_video.c index 2b713dc..a39b4ce 100644 --- a/sim_video.c +++ b/sim_video.c @@ -2044,15 +2044,25 @@ while (vid_active) { /* EVENT_SCREENSHOT to take a screenshot */ /* EVENT_BEEP to emit a beep sound */ while (vid_active && event.user.code) { - vptr = vid_get_event_window (&event, event.user.windowID); - if (vptr == NULL) + /* Handle Beep first since it isn't a window oriented event */ + if (event.user.code == EVENT_BEEP) { + vid_beep_event (); + event.user.code = 0; /* Mark as done */ continue; + } + vptr = vid_get_event_window (&event, event.user.windowID); + if (vptr == NULL) { + sim_debug (SIM_VID_DBG_VIDEO, vptr->vid_dev, "vid_thread() - Ignored event not bound to a window\n"); + event.user.code = 0; /* Mark as done */ + break; + } if (event.user.code == EVENT_REDRAW) { vid_update (vptr); event.user.code = 0; /* Mark as done */ -if (0) while (SDL_PeepEvents (&event, 1, SDL_GETEVENT, SDL_USEREVENT, SDL_USEREVENT)) { - if (event.user.code == EVENT_REDRAW) { - /* Only do a single video update between waiting for events */ + while (SDL_PeepEvents (&event, 1, SDL_GETEVENT, SDL_USEREVENT, SDL_USEREVENT)) { + if ((event.user.code == EVENT_REDRAW) && + (vptr == vid_get_event_window (&event, event.user.windowID))) { + /* Only do a single video update to the same window between waiting for events */ sim_debug (SIM_VID_DBG_VIDEO, vptr->vid_dev, "vid_thread() - Ignored extra REDRAW Event\n"); event.user.code = 0; /* Mark as done */ continue;