TMXR: Update tmxr_set_lnorder and add test of same
This commit is contained in:
parent
7dda50344c
commit
287ebb3ea8
1 changed files with 171 additions and 71 deletions
242
sim_tmxr.c
242
sim_tmxr.c
|
@ -5146,117 +5146,157 @@ return SCPE_OK;
|
||||||
|
|
||||||
/* Set the line connection order.
|
/* Set the line connection order.
|
||||||
|
|
||||||
Example command for eight-line multiplexer:
|
This validation routine is called to set the connection order for the
|
||||||
|
multiplexer whose TMXR pointer is passed in the "desc" parameter. It parses
|
||||||
|
the line order list, specified by the "cptr" parameter, of commands such as:
|
||||||
|
|
||||||
SET <dev> LINEORDER=1;5;2-4;7
|
SET <dev> LINEORDER=4-7
|
||||||
|
SET <dev> LINEORDER=1;5;2-4;7;ALL
|
||||||
|
SET <dev> LINEORDER=ALL
|
||||||
|
|
||||||
Resulting connection order: 1,5,2,3,4,7,0,6.
|
Assuming an 8-channel multiplexer, the first form sets the connection order
|
||||||
|
to line numbers 4, 5, 6, and 7. The remaining lines will not be connected; a
|
||||||
|
connection attempt will be refused with "All connections busy." The second
|
||||||
|
form sets the connection order to line 1, 5, 2, 3, 4, 7, 0, and 6. The
|
||||||
|
trailing "ALL" parameter causes any unspecified lines to be added to the
|
||||||
|
connection order in ascending value. The third form sets the order to lines
|
||||||
|
0-7, which is the default order in the absence of a line connection order
|
||||||
|
array.
|
||||||
|
|
||||||
Parameters:
|
The range of accepted line numbers, including those implied by "ALL", can be
|
||||||
- uptr = (not used)
|
restricted by specifying a non-zero "val" parameter, with the upper 16 bits
|
||||||
- val = (not used)
|
specifying the maximum line number, and the lower 16 bits specifying the
|
||||||
- cptr = pointer to first character of range specification
|
minimum line number. If a minimum is specified but a maximum is not (i.e.,
|
||||||
- desc = pointer to multiplexer's TMXR structure
|
is zero), the maximum is the last line number defined by the multiplexer
|
||||||
|
descriptor.
|
||||||
|
|
||||||
On entry, cptr points to the value portion of the command string, which may
|
The "uptr" parameter is not used.
|
||||||
be either a semicolon-separated list of line ranges or the keyword ALL.
|
|
||||||
|
On entry, "cptr" points to the value portion of the command string, which may
|
||||||
|
be either a semicolon-separated list of line ranges or the keyword "ALL". If
|
||||||
|
"ALL" is specified, it must be the last (or only) item in the list.
|
||||||
|
|
||||||
If a line connection order array is not defined in the multiplexer
|
If a line connection order array is not defined in the multiplexer
|
||||||
descriptor, the command is rejected. If the specified range encompasses all
|
descriptor, or a line range string is not present, or the optional minimum
|
||||||
of the lines, the first value of the connection order array is set to -1 to
|
and maximum restrictions in the "val" parameter are not valid, the command is
|
||||||
|
rejected. If the specified range encompasses all of the lines defined by the
|
||||||
|
multiplexer, the first value of the connection order array is set to -1 to
|
||||||
indicate sequential connection order. Otherwise, the line values in the
|
indicate sequential connection order. Otherwise, the line values in the
|
||||||
array are set to the order specified by the command string. All values are
|
array are set to the order specified by the command string. If fewer values
|
||||||
populated, first with those explicitly specified in the command string, and
|
are supplied than there are lines supported by the device, and the final
|
||||||
then in ascending sequence with those not specified.
|
parameter is not ALL, the remaining lines will be inaccessible and are
|
||||||
|
indicated by a -1 value after the last specified value.
|
||||||
|
|
||||||
If an error occurs, the original line order is not disturbed.
|
If an error occurs, the original line order is not disturbed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
t_stat tmxr_set_lnorder (UNIT *uptr, int32 val, CONST char *carg, void *desc)
|
t_stat tmxr_set_lnorder (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||||||
{
|
{
|
||||||
TMXR *mp = (TMXR *) desc;
|
TMXR *mp = (TMXR *) desc;
|
||||||
char *tbuf;
|
char *tbuf = NULL;
|
||||||
char *tptr;
|
char *tptr;
|
||||||
CONST char *cptr;
|
t_addr low, high, min, max;
|
||||||
t_addr low, high, max = (t_addr) mp->lines - 1;
|
|
||||||
int32 *list;
|
int32 *list;
|
||||||
t_bool *set;
|
t_bool *set;
|
||||||
uint32 line, idx = 0;
|
uint32 line, idx;
|
||||||
|
t_addr lncount = (t_addr) (mp->lines - 1);
|
||||||
t_stat result = SCPE_OK;
|
t_stat result = SCPE_OK;
|
||||||
|
|
||||||
if (mp->lnorder == NULL) /* line connection order undefined? */
|
if (mp->lnorder == NULL) /* if the connection order array is not defined */
|
||||||
return SCPE_NXPAR; /* "Non-existent parameter" error */
|
return SCPE_NXPAR; /* then report a "Non-existent parameter" error */
|
||||||
|
|
||||||
else if ((carg == NULL) || (*carg == '\0')) /* line range not supplied? */
|
else if ((cptr == NULL) || (*cptr == '\0')) /* otherwise if a line range was not supplied */
|
||||||
return SCPE_MISVAL; /* "Missing value" error */
|
return SCPE_MISVAL; /* then report a "Missing value" error */
|
||||||
|
|
||||||
list = (int32 *) calloc (mp->lines, sizeof (int32)); /* allocate new line order array */
|
else { /* otherwise */
|
||||||
|
min = (t_addr) (val & 0xFFFF); /* split the restriction into */
|
||||||
|
max = (t_addr) ((val >> 16) & 0xFFFF); /* minimum and maximum line numbers */
|
||||||
|
|
||||||
if (list == NULL) /* allocation failed? */
|
if (max == 0) /* if the maximum line number isn't specified */
|
||||||
return SCPE_MEM; /* report it */
|
max = lncount; /* then use the defined maximum */
|
||||||
|
|
||||||
set = (t_bool *) calloc (mp->lines, sizeof (t_bool)); /* allocate line set tracking array */
|
if (min > lncount || max > lncount || min > max) /* if the restriction isn't valid */
|
||||||
|
return SCPE_IERR; /* then report an "Internal error" */
|
||||||
if (set == NULL) { /* allocation failed? */
|
|
||||||
free (list); /* free successful list allocation */
|
|
||||||
return SCPE_MEM; /* report it */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tbuf = (char *) calloc (strlen(carg)+2, sizeof(*carg));
|
list = (int32 *) calloc (mp->lines, sizeof (int32)); /* allocate the new line order array */
|
||||||
strcpy (tbuf, carg);
|
|
||||||
|
if (list == NULL) /* if the allocation failed */
|
||||||
|
return SCPE_MEM; /* then report a "Memory exhausted" error */
|
||||||
|
|
||||||
|
set = (t_bool *) calloc (mp->lines, sizeof (t_bool)); /* allocate the line set tracking array */
|
||||||
|
|
||||||
|
if (set == NULL) { /* if the allocation failed */
|
||||||
|
free (list); /* then free the successful list allocation */
|
||||||
|
return SCPE_MEM; /* and report a "Memory exhausted" error */
|
||||||
|
}
|
||||||
|
|
||||||
|
tbuf = (char *) calloc (strlen(cptr)+2, sizeof(*cptr));
|
||||||
|
if (tbuf == NULL) { /* if the allocation failed */
|
||||||
|
free (tbuf); /* then free the successful list allocation */
|
||||||
|
return SCPE_MEM; /* and report a "Memory exhausted" error */
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy (tbuf, cptr);
|
||||||
tptr = tbuf + strlen (tbuf); /* append a semicolon */
|
tptr = tbuf + strlen (tbuf); /* append a semicolon */
|
||||||
*tptr++ = ';'; /* to the command string */
|
*tptr++ = ';'; /* to the command string */
|
||||||
*tptr = '\0'; /* to make parsing easier for get_range */
|
*tptr = '\0'; /* to make parsing easier for get_range */
|
||||||
cptr = tbuf;
|
cptr = tbuf;
|
||||||
|
|
||||||
while (*cptr) { /* parse command string */
|
idx = 0; /* initialize the index of ordered values */
|
||||||
|
|
||||||
|
while (*cptr != '\0') { /* while characters remain in the command string */
|
||||||
|
if (strncasecmp (cptr, "ALL;", 4) == 0) { /* if the parameter is "ALL" */
|
||||||
|
if (val != 0 || idx > 0 && idx <= max) /* then if some lines are restrictied or unspecified */
|
||||||
|
for (line = (uint32) min; line <= max; line++) /* then fill them in sequentially */
|
||||||
|
if (set [line] == FALSE) /* setting each unspecified line */
|
||||||
|
list [idx++] = line; /* into the line order */
|
||||||
|
|
||||||
|
cptr = cptr + 4; /* advance past "ALL" and the trailing semicolon */
|
||||||
|
|
||||||
|
if (*cptr != '\0') /* if "ALL" is not the last parameter */
|
||||||
|
result = sim_messagef (SCPE_2MARG, /* then report extraneous items */
|
||||||
|
"Too many args: %s\n", cptr);
|
||||||
|
|
||||||
|
break; /* "ALL" terminates the order list */
|
||||||
|
}
|
||||||
|
|
||||||
cptr = get_range (NULL, cptr, &low, &high, 10, max, ';'); /* get a line range */
|
cptr = get_range (NULL, cptr, &low, &high, 10, max, ';'); /* get a line range */
|
||||||
|
|
||||||
if (cptr == NULL) { /* parsing error? */
|
if (cptr == NULL) { /* if a parsing error occurred */
|
||||||
result = SCPE_ARG; /* "Invalid argument" error */
|
result = SCPE_ARG; /* then report an invalid argument */
|
||||||
break;
|
break; /* and terminate the parse */
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ((low > max) || (high > max)) { /* line out of range? */
|
else if (low < min || low > max || high > max) { /* otherwise if the line number is invalid */
|
||||||
result = SCPE_SUB; /* "Subscript out of range" error */
|
result = SCPE_SUB; /* then report the subscript is out of range */
|
||||||
break;
|
break; /* and terminate the parse */
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ((low == 0) && (high == max)) { /* entire line range specified? */
|
else /* otherwise it's a valid range */
|
||||||
list [0] = -1; /* set sequential order flag */
|
for (line = (uint32) low; line <= high; line++) /* so add the line(s) to the order */
|
||||||
idx = (uint32) max + 1; /* indicate no fill-in needed */
|
if (set [line] == FALSE) { /* if the line number has not been specified */
|
||||||
break;
|
set [line] = TRUE; /* then now it is */
|
||||||
}
|
list [idx++] = line; /* and add it to the connection order */
|
||||||
|
|
||||||
else
|
|
||||||
for (line = (uint32) low; line <= (uint32) high; line++) /* see if previously specified */
|
|
||||||
if (set [line] == FALSE) { /* not already specified? */
|
|
||||||
set [line] = TRUE; /* now it is */
|
|
||||||
list [idx] = line; /* add line to connection order */
|
|
||||||
idx = idx + 1; /* bump "specified" count */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == SCPE_OK) { /* assignment successful? */
|
if (result == SCPE_OK) { /* if the assignment succeeded */
|
||||||
if (idx <= max) /* any lines not specified? */
|
if (idx <= max) /* then if any lines were not specified */
|
||||||
for (line = 0; line <= max; line++) /* fill them in sequentially */
|
list [idx] = -1; /* then terminate the order list after the last one */
|
||||||
if (set [line] == FALSE) { /* specified? */
|
|
||||||
list [idx] = line; /* no, so add it */
|
memcpy (mp->lnorder, list, /* copy the working array to the connection array */
|
||||||
idx = idx + 1;
|
mp->lines * sizeof (int32));
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy (mp->lnorder, list, mp->lines * sizeof (int32)); /* copy working array to connection array */
|
free (list); /* free the list allocation */
|
||||||
|
free (set); /* and the set allocation */
|
||||||
|
free (tbuf); /* and the arg copy with ; */
|
||||||
|
|
||||||
|
return result; /* return the status */
|
||||||
}
|
}
|
||||||
|
|
||||||
free (list); /* free list allocation */
|
/* Show the line connection order.
|
||||||
free (set); /* free set allocation */
|
|
||||||
free (tbuf); /* free arg copy with ; */
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Show line connection order.
|
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- st = stream on which output is to be written
|
- st = stream on which output is to be written
|
||||||
|
@ -5268,7 +5308,8 @@ return result;
|
||||||
command is rejected. If the first value of the connection order array is set
|
command is rejected. If the first value of the connection order array is set
|
||||||
to -1, then the connection order is sequential. Otherwise, the line values
|
to -1, then the connection order is sequential. Otherwise, the line values
|
||||||
in the array are printed as a semicolon-separated list. Ranges are printed
|
in the array are printed as a semicolon-separated list. Ranges are printed
|
||||||
where possible to shorten the output.
|
where possible to shorten the output. A -1 value within the array indicates
|
||||||
|
the end of the order list.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
t_stat tmxr_show_lnorder (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
t_stat tmxr_show_lnorder (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||||||
|
@ -5287,7 +5328,7 @@ if (*iptr < 0) /* sequential order indi
|
||||||
else {
|
else {
|
||||||
low = last = *iptr++; /* set first line value */
|
low = last = *iptr++; /* set first line value */
|
||||||
|
|
||||||
for (j = 1; j <= mp->lines; j++) { /* print remaining lines in order list */
|
for (j = 1; last != -1; j++) { /* print the remaining lines in the order list */
|
||||||
if (j < mp->lines) /* more lines to process? */
|
if (j < mp->lines) /* more lines to process? */
|
||||||
i = *iptr++; /* get next line in list */
|
i = *iptr++; /* get next line in list */
|
||||||
else /* final iteration */
|
else /* final iteration */
|
||||||
|
@ -5622,6 +5663,64 @@ if ((dptr) && (dbits & dptr->dctrl)) {
|
||||||
|
|
||||||
/* Testing of sim_sock and tmxr */
|
/* Testing of sim_sock and tmxr */
|
||||||
|
|
||||||
|
static struct lnorder_test {
|
||||||
|
const char *orderspec;
|
||||||
|
int32 valspec;
|
||||||
|
t_stat expected_stat;
|
||||||
|
int32 expected_orderlist[8];
|
||||||
|
} lnorders[] = {
|
||||||
|
{NULL, 0, SCPE_MISVAL},
|
||||||
|
{"", 0, SCPE_MISVAL},
|
||||||
|
{"4-7", 0x3FFF3FFF, SCPE_IERR},
|
||||||
|
{"6-8", 0, SCPE_SUB},
|
||||||
|
{"9-11", 0, SCPE_SUB},
|
||||||
|
{"4-7", 0, SCPE_OK,
|
||||||
|
{ 4, 5, 6, 7, -1}},
|
||||||
|
{"1;5;2-4;7;ALL", 0, SCPE_OK,
|
||||||
|
{ 1, 5, 2, 3, 4, 7, 0, 6}},
|
||||||
|
{"ALL", 0, SCPE_OK,
|
||||||
|
{ -1}},
|
||||||
|
};
|
||||||
|
|
||||||
|
static t_stat _lnorder_test (TMXR *tmxr,
|
||||||
|
struct lnorder_test *t)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
char msg[80] = "";
|
||||||
|
int i;
|
||||||
|
|
||||||
|
r = tmxr_set_lnorder (NULL, t->valspec, t->orderspec, tmxr);
|
||||||
|
if (r != t->expected_stat) {
|
||||||
|
snprintf (msg, sizeof (msg), "Unexpected lnorder result status for \"%s\" Expected: %s", t->orderspec, sim_error_text (t->expected_stat));
|
||||||
|
return sim_messagef (SCPE_ARG, "%s, Got: %s\n", msg, sim_error_text (r));
|
||||||
|
}
|
||||||
|
if (r == SCPE_OK) {
|
||||||
|
for (i = 0; i<8; i++)
|
||||||
|
if (t->expected_orderlist[i] != tmxr->lnorder[i])
|
||||||
|
return sim_messagef (SCPE_ARG, "Unexpected order entry for line %d: %d vs %d\n", i, tmxr->lnorder[i], t->expected_orderlist[i]);
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_stat sim_tmxr_test_lnorder (TMXR *tmxr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int32 *saved_lnorder = tmxr->lnorder;
|
||||||
|
int32 saved_lines = tmxr->lines;
|
||||||
|
|
||||||
|
tmxr->lnorder = calloc (tmxr->lines, sizeof (*tmxr->lnorder));
|
||||||
|
if (tmxr->lines >= 8) {
|
||||||
|
tmxr->lines = 8;
|
||||||
|
for (i = 0; i < (sizeof (lnorders)/sizeof (lnorders[0])); ++i)
|
||||||
|
_lnorder_test (tmxr, &lnorders[i]);
|
||||||
|
}
|
||||||
|
free (tmxr->lnorder);
|
||||||
|
tmxr->lnorder = saved_lnorder;
|
||||||
|
tmxr->lines = saved_lines;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
|
||||||
t_stat tmxr_sock_test (DEVICE *dptr)
|
t_stat tmxr_sock_test (DEVICE *dptr)
|
||||||
|
@ -5676,6 +5775,7 @@ if (tmxr->lines > 1) {
|
||||||
sim_close_sock (sock_line);
|
sim_close_sock (sock_line);
|
||||||
sock_line = INVALID_SOCKET;
|
sock_line = INVALID_SOCKET;
|
||||||
SIM_TEST(detach_cmd (0, dptr->name));
|
SIM_TEST(detach_cmd (0, dptr->name));
|
||||||
|
SIM_TEST(sim_tmxr_test_lnorder (tmxr));
|
||||||
}
|
}
|
||||||
return stat;
|
return stat;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue