📄 pidloop.c
字号:
return 1;
}
return 0;
}
/*********************************************************
*
* Function: ParseValue
*
* Parameters: const PARAM_PARSE pp, pointer to a structure
* containing the acceptable limits for a
* PID parameter value
*
* const char *cp, points to a C string,
* array of chars terminated by '\0'
*
* const double *d, pointer to a double where
* the value represented by the text string will
* be stored if it is witing range
*
* Returns: zero if a successful conversion is made and
* stored, non zero if not
*
* Description: validates, converts, and stores a value
*
********************************************************/
static int
ParseValue(const PARAM_PARSE *pp, const char *cp, double *d)
{
char *end_ptr;
double val;
/* see if strtod() can convert to a double */
val = strtod(cp, &end_ptr);
/* strtod() sets end_ptr to the input parameter if */
/* it could not perform a conversion */
if (end_ptr == cp)
{
fprintf(stderr, "error: non number entered for '%c'\n",
pp->token);
return 1;
}
/* did convert a value, check it for range */
if ((val < pp->min_val) || (val > pp->max_val))
{
fprintf(stderr, "error: %0.4f out of range for '%c'\n",
val, pp->token);
return 1;
}
/* see if the value should be forced to an integer */
if (pp->force_to_int)
{
val = (long)val;
}
/* value is valid, build a pointer to store it */
*d = val;
return 0;
}
/*********************************************************
*
* Function: FindParseParam
*
* Parameters: const char *cp, points to a C string,
* array of chars terminated by '\0'
*
* Returns: NULL if the string does not start with the
* sequence of a letter followed by an equal
* sign, or the letter does not match one
* of the PARAM_PARSE structures in the array
*
* if there is a match, a pointer to the
* matching PARAM_PARSE pointer is returned
*
* Description: find a match for a properly formed string
* which indicates a parameter to be changed
*
********************************************************/
static PARAM_PARSE
*FindParseParams(const char *cp)
{
PARAM_PARSE *pp = NULL;
int upper;
/* must have at least 2 chars for token and '=' */
if (cp && strlen(cp) >= 2)
{
/* make all letters uppercase for comparison */
upper = toupper(*(unsigned char *)cp);
/* converted copy of first character must be an */
/* upper case letter and the second character */
/* must be an equal sign */
if (isupper(upper) && '=' == cp[1])
{
/* look for a match in the parse[] array */
pp = bsearch(&upper, parse,
sizeof parse / sizeof *parse,
sizeof *parse, Compare);
}
}
return pp;
}
/*********************************************************
*
* Function: ParseEvent
*
* Parameters: const char *cp, pointing to a string
* beginning with the character '@'
*
* Returns: zero if an event was successfully parsed and
* stored, non zero if not
*
* Description: if there is space remaining in the events
* array, parses the string for a pattern of
*
* "@#####[optional white space]letter=#####"
*
* where the first "#####' is convertable into
* an unsigned long value representing the cycle
* count at which the event is to take effect,
* and the "letter=#####" is an ordinary parameter
* setting, or is 'q' or 'Q' for quit
*
********************************************************/
static int
ParseEvent(const char *cp)
{
char *end_ptr;
PARAM_PARSE *pp;
EVENT ev = { 0 };
/* make sure of room to store the event */
if (event_index >= MAX_EVENTS)
{
return 1;
}
/* now get the time value after the '@' */
ev.event_time = strtoul(cp + 1, &end_ptr, 10);
/* check for errors, strtoul unable to perform a */
/* conversion or the value is 0 */
if (end_ptr == cp || 0 == ev.event_time)
{
return 1;
}
/* skip any white space between time and token */
if (NULL == (end_ptr = SkipWhiteSpace(end_ptr)))
{
return 1;
}
/* now see if the remaining string contains a valid */
/* parameter specifier */
if (NULL == (pp = FindParseParams(end_ptr)))
{
/* it might still be a 'q' or 'Q' for a command */
/* to quit the program */
if ('q' == *end_ptr || 'Q' == *end_ptr)
{
/* it is a quit command, fill in the token and */
/* store it, return successful indication */
ev.event_token = 'Q';
events[event_index++] = ev;
fputs("Stored Quit Event\n", stderr);
return 0;
}
return 1;
}
if (ParseValue(pp, end_ptr + 2, &ev.event_value))
{
return 1;
}
/* ev.event_time and ev.event_value contain valid */
/* values, ev_event_token is 0, just need to fill */
/* in the event_dest value from the pp structure */
ev.event_dest = pp->destination;
ev.event_token = toupper(*(unsigned char *)end_ptr);
events[event_index++] = ev;
fprintf(stderr, "Event @%lu, value %f, to %l\n",
ev.event_time, ev.event_value,
(long)((double *)ev.event_dest - ¶ms.p_gain));
return 0;
}
/*********************************************************
*
* Function: ParseImmediate
*
* Parameters: const char *cp, pointing to a string
* beginning with a latter, to be checked
* for containing a valid parameter setting
*
* Returns: zero if a parameter setting was successfully
* parsed and stored, non zero if not
*
* Description: test for a properly formatted parameter
* setting, then verifies that the value
* is within range, and sets the parameter
* if so
*
********************************************************/
static int
ParseImmediate(const char *cp)
{
PARAM_PARSE *pp;
/* now see if the remaining string contains a valid */
/* parameter specifier */
if (NULL == (pp = FindParseParams(cp)))
{
return 1;
}
if (ParseValue(pp, cp + 2, pp->destination))
{
return 1;
}
else
{
return 0;
}
}
/*********************************************************
*
* Function: ParseParams
*
* Parameters: const char *cp, a command line argument
* assumed to be the name of a file containing
* immediate parameter settings and timed
* events
*
* Returns: nothing
*
* Description: attempts to used the string to open a file
*
* if successful, the file is read and
* parameter settings and timed events are
* parsed and stored
*
********************************************************/
static void
ParseParams(const char *fname)
{
FILE *fin;
char inbuff[1000];
int upper;
if (NULL == (fin = fopen(fname, "r")))
{
fprintf(stderr, "error: can't open %s\n", fname);
return;
}
while (NULL != (fgets(inbuff, sizeof inbuff, fin)))
{
upper = toupper(*(unsigned char *)inbuff);
/* check for an event command */
if ('@' == upper)
{
if (ParseEvent(inbuff))
{
fprintf(stderr, "bad event: %s", inbuff);
}
}
else if (isupper(upper))
{
if (ParseImmediate(inbuff))
{
fprintf(stderr, "bad param: %s", inbuff);
}
}
} /* end of the while loop, finished reading file */
fclose(fin);
/* must sort the events array into time order if any */
/* were entered */
if (event_index > 1)
{
qsort(events, event_index, sizeof *events, EventCompare);
}
event_index = 0;
for (upper = 0; upper < event_index; ++upper)
{
fprintf(stderr, "%3d: time %6lu ", upper, events[upper].event_time);
if ('Q' == events[upper].event_token)
{
fprintf(stderr, "Q = Quit!\n");
}
else
{
fprintf(stderr, "%c %f to %p\n", events[upper].event_token,
events[upper].event_value,
(void *)events[upper].event_dest);
}
}
fprintf(stderr, "Set Point @ %p\n", (void *)¶ms.setpt);
fprintf(stderr, "Cycles @ %p\n", (void *)¶ms.cycles);
}
/*********************************************************
*
* Function: CheckEvents
*
* Parameters: unsigned long count, the count of cycles
* executed in the simulation so far
*
* Returns: 1 if the simulation should continue to run,
* 0 if the program should exit
*
* Description: controls the process of the simulation
* when not running a preset number of cycles
*
* on each iteration it checks for timed
* events ready to be processed
*
* returns 0 if a 'Q' event is processed,
* otherwise 1 after processing all events
* whose time has come
*
********************************************************/
static int
CheckEvents(unsigned long count)
{
int quit = 0;
/* except for the very first pass, check for timed */
/* events ready to be executed */
if (0 != count)
{
/* look for events with lower cycle counts not */
/* yet executed as well as the current count, in */
/* case running preset cycles passed them up */
while (0 != events[event_index].event_time
&& events[event_index].event_time <= count)
{
/* if event token is 'Q', exit the simulation */
if ('Q' == events[event_index].event_token)
{
quit = 1;
}
else
{
*events[event_index].event_dest =
events[event_index].event_value;
}
++event_index;
}
}
return quit;
}
/*********************************************************
*
* Function: Continue
*
* Parameters: none
*
* Returns: 1 if the simulation should continue to run,
* 0 if the program should exit
*
* Description: controls the process of the simulation
* when not running a preset number of cycles
*
* allows parameter setting by entries of the
* form token=value, or just a token letter
* in which case it displays a prompt and
* accepts the value entry
*
* continues until one of the following:
*
* receives a 'q' or 'Q' from stdin, or sees EOF
* on stdin, all of which cause it to return 0
* to terminate the simulation
*
* processes a '\n' not part of a parameter
* entry, causing it to return 1 to continue
* the simulation
*
* processes a parameter setting which sets
* cycle count to a non-zero value, indicating
* that the simulation should run the new
* number of cycles without user input, in
* which case it also returns 1 to continue
*
********************************************************/
static int
Continue(void)
{
char inbuff[100];
int ch;
int show_params;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -