/***************************************************************************/
/*                                                                          */
/*  int Mode07(int Last)                                                    */
/*                                                                          */
/*  Purpose:        Process all of the Dose Modes                           */
/*                                                                          */
/*  Calls:          ClearMode                                               */
/*                  ClearModePars                                           */
/*                  DelayMsg                                                */
/*                  DoseCalc                                                */
/*                  GetOptPar                                               */
/*                  KS_delay                                                */
/*                  KS_signal                                               */
/*                  TestParms                                               */
/*                  WaitMsg                                                 */
/*                                                                          */
/*  Macros:         ALARM_OFF                                               */
/*                  ALARM_ON                                                */
/*                  ALTERNATE                                               */
/*                  FOREVER                                                 */
/*                  HISTLOG                                                 */
/*                  SHOWMSG                                                 */
/*                  STUFFMSG                                                */
/*                  WAITCHAR                                                */
/*                                                                          */
/*  Inputs:         extern int mode flags                                   */
/*                  Last: Last key struck                                   */
/*                                                                          */
/*  Outputs:        int: Last key struck                                    */
/*                                                                          */
/*  Dependencies:   none.                                                   */
/*  Err Conditions: none.                                                   */
/*                                                                          */
/*  Notes:          This function gets control when the user enters a Dose  */
/*                  Mode Option number to enter a Dose Mode.                */
/*                                                                          */
/*  History:        09/27/94 - JSS: Stub-Routine.                           */
/*                  07/28/95 - J W: Beginning with only handling ugkm in    */
/*                                  this function, add the Mcg/Kg/Min Dose  */
/*                                  Mode in Mode07().                       */
/*                  31/10/95 - J W: Dump it all and start over --           */
/*                                  Copy code from Mode04, Piggyback.       */
/*                  11/02/95 - J W: Add developed DoseCalc function.        */
/*                  11/03/95 - J W: Get clean compile and link.             */
/*                  11/09/95 - J W: Put in infusion schedule index 0.       */
/*                                  Remove test loop.                       */
/*                  11/15/95 - J W: Replace !DPFLAG with DPFLAGMASK         */
/*                                  Add RATE ERR / PUSH ENTR and ALL CLR    */
/*                                  if the calculated rate is out of range  */
/*                  11/16/95 - J W: Make sure that Dose Calc gets its data  */
/*                                  set up where it is called.              */
/*                  11/17/95 - J W: Do not reset runvol if mode was already */
/*                                  present.                                */
/*                  11/17/95 - J W: Check in for preliminary version, 2.44, */
/*                                  and check out again to continue work.   */
/*                  11/21/95 - J W: Change PPigPar to POptPar and           */
/*                                  PShowPigMsg to PShowParMsg.  Change     */
/*                                  the name of GetPigPar() to GetOptPar    */
/*                                  and add the *Ch function parameter to   */
/*                                  it. Add int ParCh in Mode07 for it.     */
/*                  11/22/95 - J W: Rewrite processing to provide the       */
/*                                  illusion to the user of being in a      */
/*                                  continuous loop even if RATE ERR occurs */
/*                                  Primary values get overwritten upon     */
/*                                  successful Dose Mode setup.             */
/*                  11/22/95 - LSO: Clear running seconds and running       */
/*                                  volume                                  */
/*                                  counters when runvol is set             */
/*                  11/27/95 - J W: Update rate.value before it needs to be */
/*                                  displayed.                              */
/*                  11/27/95 - J W: Move subroutines to after main function */
/*                  11/28/95 - J W: Require ENTER or CLEAR after RATE ERR,  */
/*                                  not just any key.                       */
/*                                  Just do modeflag = NORMAL to clear opt  */
/*                                  Move clearing operations to a function  */
/*                  11/29/95 - J W: Beep in case of RATE ERR.               */
/*                                  Turn alarm off after RATE ERR 2 min     */
/*                                  wait                                    */
/*                                  if any C_ message is received.          */
/*                                  Do not echo rate if user pressed RUN to */
/*                                  go directly to run.                     */
/*                                  Removed #if-ed out block for VolCh.     */
/*                                  Make sure Dose Mode doesn't linger with */
/*                                  unexpected settings if non-normal exit. */
/*                                  Move SHOWMSGs to here in case of        */
/*                                  ClearMode call, to allow more general   */
/*                                  use of ClearMode. Use ClearMode in case */
/*                                  of non-key messages during access here- */
/*                                  only when modifiable.                   */
/*                  11/30/95 - J W: Do not push any KeyCode if returning    */
/*                                  with IGNORE.                            */
/*                                  RUN must now exit OK, not IGNORE.       */
/*                  12/01/95 - J W: Primary mode must be handled correctly  */
/*                                  returning OK with RUN.                  */
/*                                  Keep user in here if RUN was pressed,   */
/*                                  even if no parameters are set.          */
/*                  12/04/95 - J W: At valid rate echo, do not update rate  */
/*                                  .value if the calculation was not done, */
/*                                  which is when Notmodifiable. This       */
/*                                  prevents a rate of zero from being      */
/*                                  displayed when review is done when pump */
/*                                  is running or in Keylock.               */
/*                                  Do not even display any rate when not   */
/*                                  modifiable and not even in Dose Mode    */
/*                                  yet, because there is no meaning to it  */
/*                                  then.                                   */
/*                  12/07/95 - J W: Make sure that normal battery and power */
/*                                  related messages do not cause kick-out. */
/*                                  Change concept of volume updating so    */
/*                                  that it only happens when there was no  */
/*                                  previous volume. Must also copy over    */
/*                                  pflags in that case.                    */
/*                                  Do ClearMode in final mode setup to     */
/*                                  properly clear Dose Mode and Primary    */
/*                                  Mode if there was a valid Dose Mode     */
/*                                  previously set.                         */
/*                                  Let Options key gain access to the      */
/*                                  parameter list in case of RATE ERR.     */
/*                                  Change volume error message to ERR ml   */
/*                                  Add blip in case CLEAR is pushed during */
/*                                  or after RATE ERR. Allow power off      */
/*                                  after RATE ERR.                         */
/*                                  Let Options take user back to top of    */
/*                                  the list.                               */
/*                  12/08/95 - J W: Swap concentration volume and drug mass */
/*                                  (mg) in the order of parameters so that */
/*                                  you see mg first, as you would expect   */
/*                                  for concentration.                      */
/*                  12/15/95 - J W: Put Dose prompt first, per Kathy's      */
/*                                  suggestion, then put concentration and  */
/*                                  then patient mass.                      */
/*                  12/15/95 - J W: Put specific MAX_RATE range checking    */
/*                                  external to DoseCalc to make it general.*/
/*                                  Add declaration of the DoseCalc         */
/*                                  function                                */
/*                  12/19/95 - J W: Add setting of parmflag for parameter   */
/*                                  value tracking.                         */
/*                  01/09/96 - J W: Add setting of pflags for the           */
/*                                  calculated rate. Why didn't this bug    */
/*                                  appear before?                          */
/*                  01/22/96 - J W: Change the infusion volume setting so   */
/*                                  that it is cleared if setting up a      */
/*                                  Dose Mode for the first time.           */
/*                  01/24/96 - J W: Delete some unused code. Use the        */
/*                                  GOTRATE flag if a non-normal exit makes */
/*                                  the rate invalid, and go back to the    */
/*                                  parameter user was on before the non-   */
/*                                  normal exit occurred -- or the first    */
/*                                  zero one.                               */
/*                  01/25/96 - J W: Restore the option.value for error      */
/*                                  display in case power-off happened.     */
/*                  01/29/96 - J W: Add MODEWASOK flag to make sure that    */
/*                                  the status of Dose Mode will be         */
/*                                  remembered in the case of abnormal      */
/*                                  events. Re-set option.value in case     */
/*                                  power-off happened.                     */
/*                                  Add an OPT  CLRD display if exiting due */
/*                                  to having all of the parameters cleared */
/*                  01/31/96 - J W: Add the ability to calculate the Dose   */
/*                                  from the rate if called using C_RATE.   */
/*                  02/06/96 - J W: Fix bug in clearing MODEWASOK at the    */
/*                                  beginning of the program -- must use    */
/*                                  MODEWASOKMASK to avoid clearing the     */
/*                                  whole statusflag. This fixed a FIX 99   */
/*                                  that appeared when the pump was running */
/*                                  under Primary Mode and this module was  */
/*                                  accessed.                               */
/*                                  Make sure that the calculated dose is   */
/*                                  still updated to the display if RUN is  */
/*                                  pressed right after rate is changed.    */
/*                  02/07/96 - J W: Add message that we are not in the      */
/*                                  mode selected and that the user should  */
/*                                  push stop to set up this option mode.   */
/*                  02/08/96 - J W: Make OPTIONS key stay in during the     */
/*                                  STOP PUMP / TO   SET message.           */
/*                                  Add DelayMsg calls at every D_OPT_CLRD  */
/*                                  to replace the KS_Delays, to allow the  */
/*                                  user the ability to press a key rather  */
/*                                  than waiting.                           */
/*                  02/14/96 - J W: Display resulting Ml/h rather than RATE */
/*                                  after calculation.                      */
/*                  02/15/96 - J W: Added OPT CODE at end of STOP PUMP / TO */
/*                                  SET. Removed the initial clearing block */
/*                                  because it's not used anymore.          */
/*                                  Removed the display of rate or dose     */
/*                                  because it's not needed anymore. That   */
/*                                  saves many lines of code.               */
/*                  02/21/96 - J W: Put the initial clearing block back in  */
/*                                  because it is indeed used.              */
/*                  02/26/96 - J W: Add "blip" (short blank-out) after each */
/*                                  parameter, in order to clearly separate */
/*                                  them and indicate to the user that      */
/*                                  deliberate steps are being made.        */
/*                                  Use Ch to help indicate whether or not  */
/*                                  to display the PUSH ENTR prompt.        */
/*                                  Display RATE HIGH or RATE LOW, or DOSE  */
/*                                  HIGH, or DOSE LOW, if the calculation   */
/*                                  yields an out of range value. Display   */
/*                                  DOSE ERR or RATE ERR if Dose Calc can't */
/*                                  handle the inputs.                      */
/*                  03/04/96 - J W: Internal change: replace lengthy if     */
/*                                  tests of parameters with ParmTest().    */
/*                  03/05/96 - J W: Fix and streamline return conditions;   */
/*                                  incorporate WaitMsg().                  */
/*                  03/06/96 - J W: Use STUFFMSG and make the VOLUME        */
/*                                  key accepted to set the vtbi            */
/*                  03/07/96 - J W: Clear MODEWASOK whenever setting        */
/*                                  DOSEMODE1 in modeflag for the first     */
/*                                  time.                                   */
/*                  03/12/96 - J W: Move clear of Volume to the beginning   */
/*                                  of the function, because Dose Mode has  */
/*                                  been set to stay even if abnormal cond- */
/*                                  itions occur and if the user decides to */
/*                                  back out, too bad -- he's lost his pri  */
/*                                  volume.                                 */
/*                  03/13/96 - J W: Fix having to push CLEAR twice if       */
/*                                  accessing fully set-up mode by pushing  */
/*                                  OPTIONS, 5,0, then CLEAR, by excepting  */
/*                                  the CLEAR key for redisplay of title    */
/*                                  bar on first time in.                   */
/*                                  Fix problem in which GOTRATE needs to   */
/*                                  be reasserted if we got in here during  */
/*                                  Keylock by clearing GOTRATE from the    */
/*                                  volume limit.                           */
/*                  03/14/96 - J W: Allow RUN to work right away from the   */
/*                                  OPT 50 display if OPTIONS 5,0 typed.    */
/*                  03/25/96 - J W: Clear review statusflag when returning  */
/*                                  Set REVIEW and Review following the     */
/*                                  internal PUSH ENTR prompt so that it    */
/*                                  doesn't get repeated incorrectly.       */
/*                                  Make the wait sent to WaitMsg for the   */
/*                                  local PUSH RUN prompt 100ms shorter.    */
/*                  05/13/96 - J W: Correct statusflag &= MODEWASOK to      */
/*                                  statusflag &= MODEWASOKMASK where we    */
/*                                  are clearing it when *first* setting    */
/*                                  the dose mode flag.                     */
/*                  05/16/96 - LSO: Added support for history log           */
/*                  06/05/96 - LSO: Removed handling of power-status msgs   */
/*                  07/29/96 - J W: Move clearing of parameters from Clear  */
/*                                  Mode to here                            */
/*                  08/01/96 - J W: Allow RUN to prompt for parameters if   */
/*                                  pressed following a calculation error.  */
/*                  08/07/96 - J W: Integrate support for the history log.  */
/*                  08/15/96 - J W: ClearMode() now no longer takes any     */
/*                                  parameter.                              */
/*                  09/18/96 - J W: Determine more thoroughly whether to    */
/*                                  set the DPFLAG.                         */
/*                  09/20/96 - J W: Always clear the rate when selecting    */
/*                                  this Mode while the pump is in another. */
/*                  09/25/96 - J W: Replace the handling of the power       */
/*                                  status messages to keep the non-cata-   */
/*                                  -strophic power changes transparent to  */
/*                                  the user.                               */
/*                  10/04/96 - J W: Change dosemodeugkm to dosemodedose,    */
/*                                  preparatory to adding the rest of the   */
/*                                  Dose Modes.                             */
/*                  10/07/96 - J W: Convert value in PARAMs to a pointer to */
/*                                  the value.                              */
/*                  10/14/96 - J W: Break all chains of two ='s involving   */
/*                                  structure items in arrays to ward off   */
/*                                  compiler bugs.                          */
/*                  11/08/96 - CMA: First, stubbed-out Mode07 and made      */
/*                                  Mode08 a test routine to test the new   */
/*                                  structures (see top of file) for all    */
/*                                  the Dose Modes.                         */
/*                  11/10/96 - J W: Then, re-stub Mode08 and restore Mode07 */
/*                                  with the display codes changed to       */
/*                                  reflect the new Dose Mode display msg   */
/*                                  code naming scheme.                     */
/*                  11/14/96 - J W: Changed DOSEMODE1 to DOSEMODE.          */
/*                  11/16/96 - J W: Incorporated the general Mode07 routine */
/*                                  under development since Nov. 6th, for   */
/*                                  all Dose Modes and continued rewriting  */
/*                                  and generalizing it.                    */
/*                  11/17/96 - J W: Incorporated D_set_msg and D_val_msg;   */
/*                                  no longer using PShowParMsg.            */
/*                  11/18/96 - J W: Built it up and filled it in using the  */
/*                                  previous version as a guide.            */
/*                  11/19/96 - J W: Continued building it up and filling it */
/*                                  in referring also to pprogram.c.        */
/*                  11/20/96 - J W: Go over it and make it work.            */
/*                  11/21/96 - J W: Continue going over it.                 */
/*                  11/22/96 - J W: Set the current Dose Mode upon success; */
/*                                  continue going over the whole function. */
/*                  11/23/96 - J W: Went over it again in continuing to     */
/*                                  develop it, for OPTIONS pressed and     */
/*                                  Titration. Exit Rate-to-dose if Dose is */
/*                                  out of range.                           */
/*                  11/25/96 - J W: Revised the description of Titration    */
/*                                  (comments only)                         */
/*                  11/26/96 - J W: Made sure to maintain the correct       */
/*                                  disp_val_msg in the current parameter   */
/*                                  while in the parameter acquisition and  */
/*                                  display loop.                           */
/*                                  Oops, forgot to copy over the Option    */
/*                                  Clear block.                            */
/*                                  Have to update pdmspecs when doing an   */
/*                                  abnormal exit, so that the pump doesn't */
/*                                  just wake up back in DOSE ugkm.         */
/*                  11/27/96 - J W: Send OPTIONS out under "IGNORE" in      */
/*                                  order to be able to more easily give it */
/*                                  priority in the calling function over   */
/*                                  the parmflags and prevent infinite      */
/*                                  loops. Added some action under          */
/*                                  "SOMESET" at the exit to properly set   */
/*                                  the pump if OPTIONS pressed for the OPT */
/*                                  # / DOSE <type> / PUSH ENTR prompt.     */
/*                  12/02/96 - J W: Debugged the appearance of the error    */
/*                                  msg, which wasn't showing up; needed to */
/*                                  use only the DMRetCode != OK condition. */
/*                  12/03/96 - J W: Because we're no longer clearing        */
/*                                  GOTRATE to proceed from the vtbi        */
/*                                  display to the PUSH ENTR prompt, we     */
/*                                  don't need to restore the rate if in    */
/*                                  Keylock, and so most cases of !Pumprun  */
/*                                  can be changed back to Notmodifiable.   */
/*                                  Only need to set ratetodose in one      */
/*                                  place now.                              */
/*                  12/04/96 - J W: Continue optionspressedinsetup back     */
/*                                  into here so that GoThru can be set if  */
/*                                  the OPT # / DOSE <name> / PUSH ENTR     */
/*                                  prompt was induced -- and clear it      */
/*                                  at every abnormal exit before then,     */
/*                                  now. Don't need a ClearModePars if all  */
/*                                  are clear at exit.                      */
/*                  12/04/96 - J W: Removed the temporary clearing of the   */
/*                                  minimum rate setting. Restore the rate  */
/*                                  value message for the Primary Mode.     */
/*                  12/05/96 - J W: Clear ratetodose following each exit    */
/*                                  from the list of parameters. Add VOL    */
/*                                  and OFF as keys accepted when <calc>    */
/*                                  <err> message is displayed.             */
/*                  12/06/96 - J W: Make a small move to set GoThru true if */
/*                                  ratetodose is true, rather than setting */
/*                                  it only if setting ratetodose, because  */
/*                                  ratetodose might be previously set, by  */
/*                                  routines in Pnormal1.                   */
/*                                  Break out of the param acq. loop if     */
/*                                  Titrating so as to look at only the     */
/*                                  rate or dose.                           */
/*                  12/08/96 - J W: Keep user in FOREVER loop if Titrating; */
/*                                  don't just break out if Notmodifiable.  */
/*                                  This fixes a bug in which an out-of-    */
/*                                  range calculation was being ignored and */
/*                                  the incorrect Dose spec being accepted  */
/*                                  while the pump continued to run at the  */
/*                                  same rate.                              */
/*                  12/09/96 - J W: Clear secondssofar and volumesofar if   */
/*                                  Titrating successfully in order to keep */
/*                                  track of the pumped volume correctly.   */
/*                  12/12/96 - J W: Removed MODEWASOK from the software. It */
/*                                  is not needed now that the pump returns */
/*                                  to the Primary Mode when exiting from   */
/*                                  an Option Mode.                         */
/*                  12/12/96 - J W: Added restoration of the rate if doing  */
/*                                  rate-to-dose with all parameters set up */
/*                                  and the calculation goes out of range.  */
/*                  12/16/96 - J W: Must clear secondssofar and volumesofar */
/*                                  upon total success unconditionally.     */
/*                  12/17/96 - J W: Re-show the parameter value after the   */
/*                                  brief blank-out in case the pump goes   */
/*                                  to some unexpected timeout like when    */
/*                                  the roller clamp is placed in the       */
/*                                  between position, without doing another */
/*                                  SHOWMSG. Do not stuff ENTER upon        */
/*                                  exiting.                                */
/*                  12/18/96 - J W: Rather, stuff an ENTER key if it was    */
/*                                  received while showing the calculated   */
/*                                  result / PUSH RUN prompt. Do this       */
/*                                  display even if the pump is in Keylock. */
/*                  12/18/96 - LSO: Moved display "blip" to after the       */
/*                                  priority exit (don't delay exit)        */
/*                  12/20/96 - J W: Don't need to restore any display after */
/*                                  the "blip", now. (See 12/17 above)      */
/*                                  Skip the calculation while Titrating if */
/*                                  no change was made to the parameter.    */
/*                                  Fixed bug in which RUN wasn't stopping  */
/*                                  the pump when pressed at the Opt # /    */
/*                                  DOSE <type> / PUSH ENTR prompt, by      */
/*                                  always stuffing the KeyCode, even when  */
/*                                  the pump is running - removed the       */
/*                                  !Pumprun condition from the OK KeyCode  */
/*                                  stuffing at the exit at the end of this */
/*                                  routine.                                */
/*                  12/29/96 - J W: Maintain option no to show if cleared   */
/*                  01/03/97 - J W: Fix bug in which pressing OPTIONS       */
/*                                  during the setup of other option modes  */
/*                                  causes the user to get stuck in "SET /  */
/*                                  OPT CODE".                              */
/*                  01/04/97 - J W: Continued developing the fix for that   */
/*                                  bug.                                    */
/*                  01/29/97 - J W: Moved setting of GetOptPar - specific   */
/*                                  variables into the case in which Get-   */
/*                                  OptPar is actually going to be called.  */
/*                  02/05/97 - J W: Made a comment change; added FALSE      */
/*                                  maintenance of ShowInfoMsg.             */
/*                  02/05/97 - LSO: Revised WAITCHAR and WaitMsg calls to   */
/*                                  add / CLKTICK                           */
/*                  02/11/97 - J W: Added rejection of pre-existing bad     */
/*                                  parms.                                  */
/*                  02/12/97 - J W: Continued modifying for rejection of    */
/*                                  pre-existing bad parameters. No longer  */
/*                                  clear the dose parameter if the list    */
/*                                  does not compute.                       */
/*                  02/13/97 - J W: ...continued                            */
/*                  02/18/97 - J W: Removed unnecessary setting of DPFLAGs  */
/*                  02/21/97 - J W: Fixed bug of missing initial setting of */
/*                                  DMRetCode = OK; fixed bug in which the  */
/*                                  pump was not remaining in Dose Mode if  */
/*                                  after first time setup, there was a     */
/*                                  calculation out-of-range error (and all */
/*                                  of the parameters were being cleared at */
/*                                  reentry.                                */
/*                  02/25/97 - J W: Added a warning double beep if the rate */
/*                                  has not been changed following          */
/*                                  Titration being selected.               */
/*                                  Fixed a potential bug in which saved_-  */
/*                                  while_titrating would not have gotten   */
/*                                  set properly if RATE was pressed while  */
/*                                  Titrating during the error or unchanged */
/*                                  message display. Used Ch in the final   */
/*                                  total success decision because it is    */
/*                                  easier, smaller, and more consistent,   */
/*                                  fixing a bug caused by relying on       */
/*                                  ratetodose being set after an unchanged */
/*                                  while Titrating error message. Added    */
/*                                  some parentheses to the priority exit   */
/*                                  there. Changed Temp to CalcResult for   */
/*                                  better readibility.                     */
/*                  02/26/97 - J W: Revised the error and no-change-in-     */
/*                                  titration beep-pause code to stream-    */
/*                                  line it.                                */
/*                  03/03/97 - J W: Revised to use the special new Titr-    */
/*                                  ation alarm code. Fixed a bug in which  */
/*                                  the x ml/h / PUSH RUN message was being */
/*                                  displayed twice following a dose error  */
/*                                  message in a rate-to-dose operation     */
/*                                  when the pump was previously all set up */
/*                                  and in a Dose Mode at the PUSH RUN      */
/*                                  prompt.                                 */
/*                  03/04/97 - J W: Fixed a bug in which the RUN key was    */
/*                                  failing to stop the pump if pressed     */
/*                                  during Titration.                       */
/*                  03/06/97 - J W: Moved generation of the Titration no-go */
/*                                  alarm if the typed-in value didn't      */
/*                                  change, to GetOptPar, where the alarm   */
/*                                  can easily be generated in all req'd    */
/*                                  places.                                 */
/*                  03/10/97 - LSO: Replaced C_LEVNOTOPEN in limit tests    */
/*                                  with C_LASTMSG.                         */
/*                  03/14/97 - J W: Comment change only, to the Titration   */
/*                                  explanation.                            */
/*                  04/09/97 - J W: Moved in the definition of GoThru       */
/*                  04/25/97 - J W: New format of DelayMsg.                 */
/*                  05/02/97 - J W: Added directional error messages for    */
/*                                  parameters.                             */
/*                  06/04/97 - J W: Used separate two-second specification  */
/*                                  instead of BLINKON for one-time info    */
/*                                  messages; added a slight shortening of  */
/*                                  alternation pauses to prevent re-       */
/*                                  flashing.                               */
/*                  06/09/97 - J W: Don't need ALTREDUC in TWOSEC, esp. w.  */
/*                                  only the single display.                */
/*                  06/17/97 - J W: Added support for variable Dose param   */
/*                                  decimal places.                         */
/*                  06/18/97 - J W: Revised max bound check on previously   */
/*                                  existing parameters (won't be any for   */
/*                                  now) to use CheckMax, which tests the   */
/*                                  variable number of decimal places;      */
/*                                  added clear of the Dose param's s.f.    */
/*                                  and other support for the sfexp.        */
/*                  06/19/97 - J W: Added history logging of the variable   */
/*                                  number of decimal places, for the Dose  */
/*                                  parameter only.                         */
/*                  06/24/97 - J W: Revised history logging of the varscale */
/*                                  parameter (currently only the dose) to  */
/*                                  encode the scale factor in the same log */
/*                                  entry as the mantissa.                  */
/*                  06/25/97 - J W: Revised to add varscale history-logging */
/*                                  of patient mass and IV solute amount in */
/*                                  kilounits.                              */
/*                  07/01/97 - J W: Included all sfexps in clearing of the  */
/*                                  parameters of new Dose Modes.           */
/*                  07/07/97 - J W: Added History-logging of the calculated */
/*                                  Dose parameter value in rate-to-dose.   */
/*                                  Now the History log will show a Dose    */
/*                                  and a rate, one after the other, after  */
/*                                  a rate was logged at user entry (other  */
/*                                  parameters are not entered in rate-to-  */
/*                                  dose unless they are missing).          */
/*                  07/09/97 - LSO: Revised history log value calculations  */
/*                                  to use more efficient shift instead of  */
/*                                  long multiply.                          */
/*                  07/14/97 - J W: Added the required History message type */
/*                                  for the History-logging of the calcu-   */
/*                                  lated dose amount and moved logging of  */
/*                                  the new running rate to only be in the  */
/*                                  case of dose-to-rate.                   */
/*                  07/21/97 - J W: Revised to clear the ENTER key if       */
/*                                  pressed during "STOP PUMP / TO SET /    */
/*                                  OPT CODE", which will prevent unwanted  */
/*                                  titrations if the pump is running in a  */
/*                                  dose mode.                              */
/*                  07/22/97 - J W: Revised to maintain the correct scale   */
/*                                  factor for most of the parameters.      */
/*                                  Removed incorrect placement of clearing */
/*                                  of ratetodose if OPTIONS pressed to go  */
/*                                  to the OPT # / DOSE <name> / PUSH ENTR  */
/*                                  prompt.                                 */
/*                  09/11/97 - J W: Added EightCharDispAllowed in case of   */
/*                                  units.                                  */
/*                  09/15/97 - J W: Added setting of the D_units_msg.       */
/*                  09/23/97 - J W: Removed checking for kuns when history  */
/*                                  logging, since kuns will not be used    */
/*                                  any more.                               */
/*                  12/12/97 - J W: Added support for Delayed Start.        */
/*                  12/29/97 - J W: Revised to exit the Delayed Run mode if */
/*                                  only in Delayed End and a Dose Mode is  */
/*                                  set up or changed.                      */
/*                  12/30/97 - J W: Revised to use ClrDlydEnd to exit Dlyd  */
/*                                  End.                                    */
/*                  01/13/98 - J W: Revised not to clear runvol at entry    */
/*                                  to this function when clearing          */
/*                                  volumevalue and the GOTVOL parmflag;    */
/*                                  clearing those latter two should be     */
/*                                  sufficient to make the pump request a   */
/*                                  new volume; runvol=1 is needed to       */
/*                                  determine if pump is in Delayed End.    */
/*                                  Revised to do ClrDlydEnd if clearing    */
/*                                  out of the mode because parameters      */
/*                                  were left zero, even if in Primary Mode */
/*                                  still.                                  */
/*                  01/28/98 - J W: Revised for the new separate Delayed    */
/*                                  Start and End modeflags.                */
/*                  11/03/98 - CMA: Revised to send a message to the        */
/*                                  history log stating that the option has */
/*                                  been cleared when the user passes thru  */
/*                                  the setup without entering values or if */
/*                                  the CLEAR key is pressed explicitly to  */
/*                                  clear the mode.                         */
/*              11/20/98 - CMA: Removed the work of the previous entry. */
/*                                  ClearModeCore now handles this.         */
/*                  11/30/98 - CMA: Added code to record the rate and dose  */
/*                                  calculations in the history log, as     */
/*                                  well as the rate value at which the     */
/*                                  pump has been set to run.               */
/*                  12/03/98 - CMA: Fixed a bug in logging the calculated   */
/*                                  dose amount that ignored decimal point  */
/*                                  placement.                              */
/*                  05/31/99 - J W: Revised to detect optionugot in order   */
/*                                  to set GoThru; deleted clearing of      */
/*                                  optionspressedinsetup at the beginning, */
/*                                  because GetUOptions has been revised    */
/*                                  not to set that any more.               */
/*                                                                          */
/***************************************************************************/

int Mode07(int  Last)
{
    /* VARIABLES:                                                           */

    static MSG CtrlMsg;                 /* main ctrl mbox msg element       */
    static HLE_MSG HistMsg;             /* message for History Log Entry    */

    unsigned long CalcResult = 0;       /* Hold result of DoseCalc until OK */
    char CalcQFracDigs = 0;             /* Hold result of Dose SF until OK  */
    int DMRetCode;                      /* Error return for sub functions   */
    int GoThru;                         /* eliminates nested Get functions  */
                                        /*  -causes stop at each parameter  */
    int ParNum;                         /* which parm in Mode's parm list   */
    int Ch;                             /* whether a parm has changed       */
    int Ii;                             /* loop counter                     */
    /* Whether any parameter was changed while going through the list of    */
    /* parameters.                                                          */
    int ParCh = FALSE;

    /* Hold previous rate until good new rate                               */
    unsigned long SavedRate = 0;


    /* CODE:                                                                */

    KeyCode = Last;                     /* Switch to global variable        */

    ShowInfoMsg = FALSE;                /* No extra info msgs in Dose Modes */

    /* Detect the current Dose Mode being looked at                         */

    /* Find the Option Number that was typed in or that is being looked at  */
    if (optionugot == 0)
    /* If zero, we only could have gotten in here if a Dose Mode was set    */
    /* up. Restore info from NVRAM (see Mode19() for a similar approach)    */
    {
        pdmspecsm07 = pdmspecs;         /* Which is it?                     */
        localoptno = (long)pdmspecs->OptCode;
    }
    else                                /* Came from GetUOptions            */
    {
        localoptno = optionugot;        /* pdmspecsm07 set in GetUOptions   */
    }

    /* Otherwise, if it was set, pdmspecsm07 was set in GetUOptions (qv)    */

    Pumprun = statusflag & PUMPRUN;     /* set up the convenient booleans   */
    Keylock = statusflag & KEYBDLOCK;
    Notmodifiable = Pumprun || Keylock;
    Modifiable = !Notmodifiable;
    Review = statusflag & REVIEW;

    /* Exit with message to user if pump already running in another mode    */
    if (
        (Pumprun)
        &&
        /* But not if Titrating                                             */
        !Titrating
        &&
        /* Not in Dose Mode or in Dose Mode and not in this Dose Mode       */
        /* ie DM' + (DM.S') = (DM'+DM).(DM'+S') = DM'+S' =                  */
        (
         !(modeflag & DOSEMODE)
         ||
         (pdmspecsm07 != pdmspecs)
        )
       )
    {
        ALTERNATE(3);
        SHOWMSG(D_STOP_PUMP);
        SHOWMSG(D_TO_SET);
        SHOWMSG(D_SET_OPT2);                /* "OPT CODE"                   */
        WAITCHAR((3*BLINKON-ALTREDUC) / CLKTICK);
                                            /* does not push KeyCode        */
        /* IGNORE in GetUOptions causes look at KeyCode, and if returning   */
        /* to Running, which it won't, because it can't be called from      */
        /* Running, because it is not running in this mode in the first     */
        /* place, KeyCode will be pushed.                                   */

        if (KeyCode == C_ENTER)             /* Might cause probs if in Dose */
            KeyCode = C_NULL;               /* ENTER not needed externally  */

        if (KeyCode != C_OPTIONS)
        {
            /* If OPTIONS pressed during STOP PUMP / TO SET, still "review" */
            statusflag &= REVIEWMASK;

            return(IGNORE);
        }
    }

    /* The volumevalue (not runvol) must always be cleared when setting up  */
    /* a Dose Mode for the first time.                                      */
    /* The current DoseMode is being set up for the first time if DOSEMODE  */
    /* not set or if pdmspecs differs from pdmspecsm07.                     */
    if (
        (
         !(modeflag & DOSEMODE)
         ||
         (pdmspecs != pdmspecsm07)
        )
        &&
        (KeyCode != C_CLEAR)            /* Don't clr vol if just clrng mode */
        &&
        (Modifiable)                    /* Not if Titrating                 */
       )
    {
        /* Clear out the territory, man                                     */
        for (Ii=0; Ii <= (pdmspecsm07->Q)-1; Ii++)
        {
            *(((pdmspecsm07->Pomfp)+Ii)->P->pvalue) = 0;
                                        /* Get the param sf exp too         */
            *(((pdmspecsm07->Pomfp)+Ii)->P->sfexp) = 0;
        }

        /* This is the key value upon which most PARAMs depend, through     */
        /* their sfexp pointer. The sfexp is used in ParmMsg() in optmsg.c  */
        /* where if the value pointed to is 1, its parameter is treated as  */
        /* the regularly scaled, otherwise the parameter is considered to   */
        /* be scaled according to the value pointed to by sfexp.            */

        /* This has to be maintained here because it might have been        */
        /* cleared just now and then a lot of other parameters will look    */
        /* like their values aren't scaled.                                 */

        regsfexpon = 1;


        /* We must set the rate to zero here because the Primary Rate is    */
        /* supposed to be cleared as soon as a Dose Mode is attempted.      */
        /* Do separately to ward off compiler bugs:                         */
        runrate = 0;
        schedlist[1].SchedRate  = 0;
        ratevalue = 0;
        parmflag &= GOTRATEMASK;

        /* Do separately to ward off compiler bugs:                         */
        schedlist[1].SchedVol = 0;
        volumevalue = 0;
        /* Don't clear runvol. It's needed at this time for the Delayed End */
        /* test.                                                            */

        parmflag &= GOTVOLMASK;
        parmflag &= PARMMEMMASK;
        secondssofar = 0;               /* clear running seconds count      */
        volumesofar = 0;                /* clear running volume counter     */
    }

    if (
        (KeyCode == C_CLEAR)
        &&
        Modifiable                      /* Just in case not handled in main */
       )
    /* This is here in case CLEAR was pressed after this option was         */
    /* selected by pressing OPTIONS and typing the options number, or, in a */
    /* recent addition, by just pressing OPTIONS while in the following     */
    /* setup routine, and then pressing CLEAR while the OPT # prompt was    */
    /* being displayed in the previous block.                               */
    {
        /* Will already have exited Delayed End if the pump was in a        */
        /* different Option Mode; if so, ClrDlydEnd won't do it again.      */
        ClrDlydEnd(TRUE);

        /* Clear the values from permanent memory                           */
        ClearModePars(DOSEMODE);

        /* Call the ClearMode function to return to Primary Mode            */
        ClearModeCore();                /* Clears optionvalue               */

        /* Make a blip against continuous display of the Option number      */
        SHOWMSG(D_BLANK);
        KS_delay(SELFTASK, IMMEDWAIT/CLKTICK);

        ALTERNATE(2);                   /* option value set in GetUOption   */
        SHOWMSG(D_OPT_LOCAL);           /* OPT    nn / OPT  CLRD            */
        /* DelayMsg Pushes KeyCode; all calling routines check mailbox.     */
        /* Note that the quantity in ALTERNATE includes DelayMsg            */
        DelayMsg(D_OPT_CLRD, 2*BLINKON-ALTREDUC, DLYMSG_IGMPS);
        statusflag &= REVIEWMASK;       /* Defend against any call          */

        return(OK);
    }

    /* Push Enter handled in GetUOptions, except during pump stop review    */
    /* KeyCode will be either C_NULL or C_CLEAR, or C_ENTER if from pump    */
    /* stop review. Swallow a possible C_ENTER just before the FOREVER loop */

    /* DOSEMODE is only set when leaving this function to indicate to the   */
    /* rest of the software that Dose Mode should be set up. The current    */
    /* DOSEMODE is indicated by pdmspecs. The parmflag word, using GOTRATE  */
    /* and PARMMEM, is used to indicate that the mode is all set up         */
    /* successfully.                                                        */

    /* GOTRATE is used to indicate whether Dose Mode is currently good      */

    /* Swallowing of ENTER is done in GetOptPar                             */

    /* Very clever algorithm using this Boolean, GoThru, that causes one    */
    /* guaranteed pass through the parameter list and then gets set on the  */
    /* next go-around only for the parameter that needed to be set. When    */
    /* that happens, the rest of the list gets reviewed. A review cycle is  */
    /* simulated through ReadyToRun or RunDisplay, as ENTER is pressed.     */

    if (
        (modeflag & DOSEMODE)
        &&
        !(parmflag & GOTRATE)           /* if reentering to finish job      */
       )
        GoThru = FALSE;
    else
        GoThru = TRUE;                  /* first-time setting               */

    /* Must look at each parameter if accessed via the OPT # / Mode<name> / */
    /* PUSH ENTR prompt.                                                    */
    if (optionugot != 0)
    {
        GoThru = TRUE;
    }

    if (KeyCode == C_VOLUME)
    {
        STUFFMSG;                       /* React to volume key if was Last  */
    }

    /* Titrating : set in Running() (qv)                                    */
    /* Explanation of Titration: "TITRDIS" is an optionflag in NVRAM that   */
    /* disables Titration, which means changing the running rate "on the    */
    /* fly".                                                                */
    /*                                                                      */
    /* "Titrating", visible only to pnormal3 and pdose, (and pnormal1 for   */
    /* titrating in the Primary Mode) is turned on only when the current    */
    /* run-through of this function is a Titration operation.               */
    /*                                                                      */
    /* "Titrate", visible only to here and GetOptPar, is a low-level        */
    /* indication to GetOptPar to tell it to apply the special Titration    */
    /* time delays to the parameter acquisition, which only ever applies to */
    /* Rate or Dose amount acquisition.                                     */

    FOREVER
    {
        if (KeyCode == C_RUN)
        {
            GoThru = FALSE;
        }

        /* If the RATE key was pressed, we are doing ratetodose.            */
        /* If doing ratetodose, remember that. Don't reset it just because  */
        /* of re-entry to this routine. Only set it, and only if the RATE   */
        /* key was pressed. It will be cleared to FALSE at power-up (see    */
        /* rtxcmain.c), and every time a calculation is attempted.          */
        if (KeyCode == C_RATE)
            ratetodose = TRUE;

        /* ratetodose set by RequestValues() or by GetVol() in Pnormal1     */
        if (ratetodose)
        {
            GoThru = TRUE;              /* look at even a non-zero rate     */

            /* Be able to restore the rate if we were already all set up in */
            /* Dose Mode and we just want to change the rate in rate - to - */
            /* dose. Then we don't want to lose the rate if there was a     */
            /* calculation error.                                           */
            /* In this case, we know that if the calculation goes out of    */
            /* range, that it will be totally the fault of the rate, and    */
            /* nothing else -- the for loop breaks out in that case, and    */
            /* we can simply restore the rate.                              */
            if (
                !Titrating              /* Titrating already taken care of  */
                &&
                (TestParms(DOSEMODE) == ALLSET)
                &&
                (modeflag & DOSEMODE)
                &&
                (parmflag & GOTRATE)
                &&
                (Modifiable)
                &&
                (ratevalue != 0)        /* For what more can I ask?         */
                &&                      /*  For an uncorrupted ratevalue:   */
                (SavedRate == 0)        /* --might have pressed RATE below  */
               )
                SavedRate = ratevalue;  /* Otherwise remains 0 as declared  */
        }

        if (Titrating)
        {
            Titrate = TRUE;             /* In 1st par only, ie rate or dose */
            GoThru = TRUE;              /* In case ENTER pressed to Titrate */
        }

        DMRetCode = OK;

        /* The parameter acquisition and display loop:                      */
        for(ParNum = 1; ParNum <= (pdmspecsm07->Q); ParNum++)
        {
            /* Use Pointer Arithmetic to point to the current parameter     */
            Pworkomfp = (pdmspecsm07->Pomfp) + ParNum-1;
            if (                        /* on the dose amt                  */
                (ParNum == 1)
                &&
                (ratetodose == TRUE)    /* doing rate-to-dose               */
               )                        /* replace dose setting with rate   */
                Pworkomfp = &Rate_Function_Par;

            /* There is no longer any point in continuing with ratetodose   */
            /* if the dose won't be recalculated or displayed.              */
            if (
                Notmodifiable
                &&
                !Titrating
               )
                ratetodose = FALSE;

            /* Get the data for the current parameter:                      */
            /* Get the set messages for ShowOMP_Msg():                      */
            POptPar = Pworkomfp->P;

            if (
                GoThru
                ||
                (*(POptPar->pvalue) == 0)
                ||
                (*(POptPar->pvalue) < POptPar->min_value)
                ||
                (CheckMax(POptPar) == TOOHI)
               )
            {
                D_set_msg = Pworkomfp->Setmsg;
                D_val_msg = Pworkomfp->Valmsg;
                                        /* So far, only in case of "units"  */
                D_units_msg = D_UNS_NONUM;


                if (POptPar->param_type == DOSEMODEUNS)
                    EightCharDispAllowed = TRUE;
                else
                    EightCharDispAllowed = FALSE;

                ParLoErrMsg = Pworkomfp->LoErrmsg;
                ParErrMsg = Pworkomfp->Errmsg;
                ParHiErrMsg = Pworkomfp->HiErrmsg;
                HistMsg.msgtype = Pworkomfp->histmsg;

                if (*(POptPar->pvalue) == 0)
                    GoThru = TRUE;

                /* Ch must be initialized if it is used, since GetOptPar    */
                /* only sets it TRUE if it changes.                         */
                /* use to help indicate whether to display PUSH ENTR        */
                Ch = FALSE;

                /* EnterParam uses disp_val_msg in the PARAM structure, so  */
                /* it has to be maintained to that of the current Valmsg:   */
                Pworkomfp->P->disp_val_msg = Pworkomfp->Valmsg;

                /* HERE IS THE CORE OF IT ALL, the parameter acquisition:   */

                if (GetOptPar(&Ch) != OK)
                    /* This will stay stuck on Not OK for one pass through  */
                    /* the parameter list:                                  */
                    DMRetCode = IGNORE;

                                        /* Done with any possible Unit disp */
                EightCharDispAllowed = FALSE;

                Titrate = FALSE;        /* Done GetOptPar; done "Titrate"   */
                /* Change the rate value message back for Primary Mode      */
                rate.disp_val_msg = D_RATE;
                /* Decide whether to exit; set flags                        */

                if (Ch)                 /* Record value in history log      */
                {
                    ParCh = TRUE;       /* Remember if any param changed    */

                    /* Do variably scaled parameters differently            */
                    if (
                        (POptPar->param_type == DOSEMODEDOSE)
                        ||
                        (POptPar->param_type == DOSEMODEMASS)
                       )
                    {
                        /* If the parameter type is "DOSEMODEDOSE", then    */
                        /* the log reader will understand that the number   */
                        /* is scaled by ten.                                */
                        /* The history log reader will have to strip the    */
                        /* scale factor information out of the high order   */
                        /* nibble.                                          */
                        HISTLOG(
                                ((long)*(POptPar->sfexp) << 28)
                                +
                                *(POptPar->pvalue)
                               );
                        /* All wrapped up in one History Log entry, because */
                        /* having subsequent entries present in the limited */
                        /* and reused History log space cannot be relied    */
                        /* upon. (NB: Prepositions are not words to end     */
                        /* sentences with)                                  */
                    }
                    else
                    {
                        HISTLOG(*(POptPar->pvalue));
                    }
                }

                /* Priority exit, in case of an urgent event:               */
                if (
                    (
                     (KeyCode != C_NULL)
                     &&
                     (KeyCode != C_RUN) /* must pass gauntlet for reg keys  */
                     &&
                     (KeyCode != C_ENTER)
                     /* Attempt to set up the option in the background      */
                     /* while going to the OPT no. / PUSH ENTR prompt.      */
                     &&
                     (KeyCode != C_OPTIONS)
                    )
                    ||
                    (KeyCode == C_VOLUME)
                   )
                {
                    if (KeyCode == C_RATE)
                    {
                        /* If Titrating, saved_while_titrating was updated  */
                        /* in GetOptPar                                     */
                        ratetodose = TRUE;
                        break;          /* exit and restart                 */
                    }

                    statusflag &= REVIEWMASK;
                    /* Stay in the mode, but signal that the rate will be   */
                    /* needed, for this is a non-normal exit and the rate   */
                    /* will not be calculated.                              */
                    if (Modifiable)
                    /* User wants to stay in Dose Mode                      */
                    {
                        ClrDlydEnd(ParCh);
                                        /* But exit Delayed End             */

                        modeflag = DOSEMODE | (modeflag & DELAYEDRUN);
                                        /* Keep any Delayed Mode setting    */

                        /* Must remember which Dose Mode to come back to    */
                        pdmspecs = pdmspecsm07;
                        parmflag &= GOTRATEMASK;
                        parmflag &= PARMMEMMASK;
                        optionvalue = localoptno;
                    }

                    if (KeyCode != C_VOLUME)
                        /* Still considered to be in the parm list:         */
                        ratetodose = FALSE;

                    return(IGNORE);     /* GetOptPar cleared the parameter  */
                }

                /* Add "blip" before going to the next display              */
                /* Including going to the ReadyToRun prompt                 */
                SHOWMSG(D_BLANK);
                KS_delay(SELFTASK, IMMEDWAIT/CLKTICK);
                /* This is kept following the priority exit in case that    */
                /* exit gets taken, which could otherwise lead to an        */
                /* extended blank display.                                  */

                if (
                    (ratetodose)
                    &&                  /* Do any zero parameters           */
                    (TestParms(DOSEMODE) == ALLSET)
                   )
                    break;              /* Return straight away if adj rate */

                if (Titrating)          /* Only do rate or dose             */
                    break;

                if (
                    /* Must exit or check for any 0 parameters if beeping   */
                    (RetCode == RC_TIMEOUT)
                    ||
                    (KeyCode == C_RUN)  /* or if RUN was pressed            */
                   )
                {
                    GoThru = FALSE;
                    /* || value==0 of this loop must be bypassed            */
                    break;
                }

                GoThru = TRUE;
                if (KeyCode == C_OPTIONS)
                    break;              /* GoThru is set TRUE now           */

            } /* End of if block that displays or gets the Opt Par          */
            /* Ensure that Titrate gets cleared consistently after the      */
            /* first ParNum.                                                */
            Titrate = FALSE;

        } /* End of for loop to go thru each par for the Dose Mode, once.   */
        /* (The parameter acquisition and display loop)                     */

        if (
            /* If RATE pressed during parameter entry                       */
            (KeyCode == C_RATE)         /* Go right to rate-to-dose         */
            ||
            /* "Bad Parms": found parms in NVRAM that violate their current */
            /* limits:                                                      */
            (                           /* Bad parms - redo list            */
             (DMRetCode != OK)          /* Zero values not counted          */
             &&
             (KeyCode != C_OPTIONS)     /* -unless user wants OPT # prompt  */
             &&
             Modifiable                 /* Can't keep user in otherwise     */
            )
           )
            /* Go back to first, or first bad parameter, depending upon     */
            /* GoThru                                                       */
            continue;                   /* Skip rest of FOREVER loop        */

        if (Notmodifiable)              /* ... &in case of bad pars, say OK */
            DMRetCode = OK;

        /* NB Broke out from the previous for loop if OPTIONS pressed. Will */
        /* still do calc, however:                                          */

        /* If the calculation can be done, do it                            */
        if (
            (DMRetCode == OK)
            &&
            (TestParms(DOSEMODE) == ALLSET)
            &&
            (
             Modifiable
             ||
             /* Set in Running() if RATE or ENTER pressed, also if          */
             /* doing "titration"                                           */
             (
              Titrating
              &&                        /* Skip calc if no change           */
              Ch
             )
            )
           )
        {
            /* The calculation function sees the global ratetodose, and the */
            /* pointer pdmspecsm07 which is a global. It returns as its     */
            /* return code, a value that is here assigned to DMRetCode.     */
            /* Everything needed to do the calculation is found in the      */
            /* structure pointed to by pdmspecsm07.                         */

            DMRetCode = DoseCalc(&CalcResult, &CalcQFracDigs);
        }

        /* Decision block as to whether to exit this forever loop -- this   */
        /* is the condition that forces the user to supply all or none of   */
        /* the parameters.                                                  */
        if (                            /* Can leave if all parms zero      */
            (
             (TestParms(DOSEMODE) == NONESET)
             &&
             (KeyCode != C_RUN)         /* RUN stays in if nothing yet      */
            )
            ||                          /* or, exit if all set up           */
            /* Break out if all the parameters are there and the calc       */
            /* succeeded OK, as long as we are not Titrating, in which      */
            /* case the "Titrating" group of &&'s in this if statement      */
            /* apply in the decision whether to break.                      */
            (
             (TestParms(DOSEMODE) == ALLSET)
             &&
             /* See the MultDiv function, invoked above                     */
             (DMRetCode == OK)
             &&
             !Titrating
            )
            ||
            /* Let him out; only reviewing; not fair to keep him in if he   */
            /* can't set anything.                                          */
            (
             Notmodifiable
             &&
             !Titrating
            )
            ||
            /* No error in Titrating; otherwise, stay and show err msg      */
            (
             Titrating
             &&
             (DMRetCode == OK)
             &&
             /* Stay in if Titrating, but nothing changed, in order to      */
             /* sound a warning tone.                                       */
             Ch
            )
           )
           /* That was a big IF                                             */
           break;                       /* That was a small statement       */
           /* Any OPTIONS keypress in this case will be handled after the   */
           /* end of the FOREVER loop.                                      */

        /* This was the place to clear changed parameters so that the set   */
        /* prompt will always reappear -- before breaking out due to        */
        /* OPTIONS, but now, parameters are not cleared, but left in place  */
        /* to allow the user to refer back to them.                         */
        if (DMRetCode != OK)
        {
            /* Don't need to clear anything anymore because the pump will   */
            /* now go to the OPT # / <mode name> / PUSH ENTR prompt unless  */
            /* Titrating or there was a SavedRate.                          */

            if (Titrating)
            {
                /* If titrating, restore the saved value and ignore the     */
                /* attempt.                                                 */
                if (ratetodose)
                {
                    ratevalue = *(saved_while_titrating.pvalue);
                    *(rate.sfexp) = 1;
                }
                else
                {
                    *(pdmspecsm07->Pomfp->P->pvalue)
                                            = *(saved_while_titrating.pvalue);
                    *(pdmspecsm07->Pomfp->P->sfexp)
                                            = *(saved_while_titrating.sfexp);
                }
            }
            else if (SavedRate != 0)
            {
                ratevalue = SavedRate;
            }
            /* Was using Temp to restore the DPFLAGS; don't need to mess    */
            /* with DPFLAGS all over the place anymore because the display  */
            /* routine, ParmMsg() in Optmsg.c takes care of it auto-        */
            /* matically.                                                   */
        }

        /* OPTIONS pressed while Titrating? Still go to OPT # / PUSH ENTR   */
        /* prompt; nothing would be changed, because ENTER had to be        */
        /* pressed in order to accept the changed value.                    */
        if (KeyCode == C_OPTIONS)
            /* OPTIONS did not break out above -- must set up or not        */
            break;

        /* If Block to handle out of range results, which may also occur if */
        /* Titrating, or a display in case the no change in Titration       */
        /* alarm has been sounded                                           */
        if (
            (DMRetCode != OK)
            ||
            (
             (Titrating)                /* Take out this condition later    */
             &&
             (!Ch)
            )
           )
        {
            if (
                Titrating
                &&                      /* Rate not going to change         */
                Ch                      /* User-attempted change remembered */
                /* (Otherwise Titr Alm on was done in GetOptPar)            */
               )
            {                           /* Titr a No-Go: out-of-range       */
                ALARM_ON(A_TITR_NOGO);  /* Turns itself off (a "one-shot")  */
            }
            else if (!Titrating)
            {
                ALARM_ON(A_PARM_ERR);   /* A slow alarm                     */
            }

            if (!
                (
                 Titrating
                 &&
                 (KeyCode == C_RUN)     /* Need to go stop the pump, if so. */
                 /* (NB. Recall that important pump events get handled by   */
                 /* priority exits from this function)                      */
                )
               )
            {
                if (ratetodose)
                {
                    if (
                        (Titrating)
                        &&              /* As well as the audible alarm,    */
                        (!Ch)           /*  visually demo the unchngd Dose  */
                       )
                    {
                        SHOWMSG(pdmspecsm07->Pomfp->Valmsg);
                    }
                    else if (DMRetCode == CANTDO)
                    {
                        SHOWMSG(D_DOSE_ERR);
                    }
                    else if (DMRetCode == TOOHI)
                    {
                        SHOWMSG(D_DOSE_HIGH);
                    }
                    else                /* It is less than 0.1              */
                    {
                        SHOWMSG(D_DOSE_LOW);
                    }
                }
                else
                {
                    if (
                        (Titrating)
                        &&
                        (!Ch)           /* Visually demo the unchngd rate   */
                       )
                    {
                        SHOWMSG(D_RATE_IN_MLH);
                    }
                    else if (DMRetCode == CANTDO)
                    {   /* Shows RATE ERR; D_RATE_ERR gives ERR RATE        */
                        SHOWMSG(D_CALC_ERR);
                    }                   /* DMRetCode set for rate above     */
                    else if (DMRetCode == TOOHI)
                    {
                        SHOWMSG(D_RATE_HIGH);
                    }
                    else                /* It is less than 0.1              */
                    {
                        SHOWMSG(D_RATE_LOW);
                    }
                }

                /* Pause                                                    */

                /* Discard all normal power and battery related messages    */
                /* so that they won't cause kick-out.                       */
                /* i.e., ignore C_ACIN C_ACOUT C_BATTLOW C_BATTOK           */
                /* The beep will now stop after BLINKON or if a non-ignored */
                /* message is received.                                     */

                WaitMsg(TWOSEC/CLKTICK, 4, ignorekeys);

                /* The Titration alarm finishes by itself over a 2.5 s      */
                /* period; ALARM status flag not set.                       */
                if (statusflag & ALARM)
                {
                    ALARM_OFF;
                }
                /* End of code for the error display pause                  */

            } /* End of if block to skip the display if STOP was pressed    */
              /* while titrating                                            */

            /* Clear ratetodose, because the calculation failed. Let our    */
            /* users go!                                                    */
            /* In the case of Titration, nothing changed, or else the old   */
            /* values have been restored, so it is not needed anymore.      */
            ratetodose = FALSE;

            /* React to any system message that occurred during the pause:  */

            if (
                /* User should be able to select VOL LIMIT or OFF from here */
                /* even if Titrating, because by now if Titrating, nothing  */
                /* else needs to be done in this function                   */
                (KeyCode == C_VOLUME)
                ||
                (KeyCode == C_POWEROFF)
                ||
                (
                 (KeyCode >= C_RCINST)
                 &&
                 (KeyCode <= C_LASTMSG)
                )
               )
            /* Handle strange messages. All keystrokes but CLEAR get kept   */
            /* in the current loop. Non-keystroke messages cause kick-out.  */
            {
                statusflag &= REVIEWMASK;
                /* Stay in the mode, but signal that the rate will be       */
                /* needed, for this is a non-normal exit and the rate       */
                /* will not be calculated.                                  */
                if (Modifiable)
                /* User wants to stay in Dose Mode                          */
                {
                    ClrDlydEnd(ParCh);

                    modeflag = DOSEMODE | (modeflag & DELAYEDRUN);
                                        /* Keep any Delayed Mode setting    */

                    /* Must remember which Dose Mode to come back to:       */
                    pdmspecs = pdmspecsm07;
                    parmflag &= GOTRATEMASK;
                    parmflag &= PARMMEMMASK;
                    optionvalue = localoptno;
                }
                return(IGNORE);
            }

            if (KeyCode == C_RATE)
            {
                /* Must now update saved_while_titrating in order to be     */
                /* able to restore the rate, now, in case we are Titrating. */
                /* If we are not, it doesn't hurt.                          */
                *(saved_while_titrating.pvalue) = ratevalue;
                *(saved_while_titrating.sfexp) = 1;

                ratetodose = TRUE;
                continue;
            }

            if (
                (Titrating)
                ||
                (SavedRate != 0)
               )
                break;                  /* Input restored above; just exit  */

            /* Respond to all other valid KeyCodes (none at this time)      */
            switch (KeyCode)
            {
            default:
            /* Fake-up an OPTIONS keypress in order to go to the OPT #      */
            /* / DOSE <type> / PUSH ENTR prompt now.                        */
                KeyCode = C_OPTIONS;
            }
        } /* End of out-of-range result (Modifiable or Titrating in there)  */

        if (
            (RetCode == RC_TIMEOUT)
            &&
            (DMRetCode == OK)
           )
            /* Go on to next SET prompt if timeout while viewing a param.   */
            GoThru = FALSE;
        else
            GoThru = TRUE;

        /* OPTIONS causes a return to the OPT # prompt                      */
        if (KeyCode == C_OPTIONS)
            break;

    } /* End of FOREVER loop to force the user to enter all the parms       */

    /* Do not update rate value if calculation was not done above.          */
    /* Do not do calculation above if not modifiable because the whole Dose */
    /* Mode might not even previously exist.                                */
    if (
        (TestParms(DOSEMODE) == ALLSET)
        &&
        (DMRetCode == OK)               /* Don't do if need SavedRate here  */
        &&                              /*  Rather, restore was done above  */
        (
         Modifiable
         ||
         (
          Titrating
          &&
          Ch
         )
        )
       )
    {
        /* DOSEMODE and pdmspecs are guaranteed to be set up below, now,    */
        /* because the next WAITCHAR is the last, and will be sent out the  */
        /* normal exit of this function.                                    */

        if (ratetodose)
        {
            *(pdmspecsm07->Pomfp->P->pvalue) = CalcResult;
            *(pdmspecsm07->Pomfp->P->sfexp) = CalcQFracDigs;

            /* History log the calculated dose value                        */
            HistMsg.msgtype = DOSECALC_TYPE;

            /* The history log reader will have to strip the scale factor   */
            /*  information out of the high order nibble.                   */
            HISTLOG(
                    ((long)CalcQFracDigs << 28)
                    +
                    ((long)CalcResult)
                   );
        }
        else
        {
            ratevalue = CalcResult;

            /* History log the calculated rate value                        */
            HistMsg.msgtype = RATECALC_TYPE;
            HISTLOG((long)CalcResult);
        }
    }
    /* The updates to the variables that control the running of the pump    */
    /* are done below, under "Total Success"                                */

    /* Display the calculated result or the restored SavedRate...           */
    if (
        /* ...but first, go to the PUSH ENTR prompt if OPTIONS pressed, or  */
        /* simulated by the error block above                               */
        (KeyCode != C_OPTIONS)
        &&
        (TestParms(DOSEMODE) == ALLSET)
       )
    /* Display the calculated rate or dose                                  */
    /* Now, DMRetCode is OK, because OPTIONS was simulated in that case.    */
    {
        /* Should run right away so user doesn't "skip a heartbeat" when he */
        /* pushes RUN, and sees the rate echoed and only then hears the     */
        /* pump begin to run.                                               */
        if (
            (KeyCode != C_RUN)          /* Pause to display result          */
            &&
            /* Should not display a meaningless rate while not modifiable   */
            /* and when not even set up yet; ie display when the pump is    */
            /* not running already, even if it is in Keylock.               */
            !Pumprun                    /* Not Titrating                    */
           )
        {
            /* Show a PUSH RUN prompt in here to separate the display of    */
            /* the calculation result from the display shown in ReadyToRun, */
            /* so that the same thing isn't shown twice in a row. This is   */
            /* done for looks in the case in which rate-to-dose is done.    */
            /* For example, in ratetodose, this code will show "x ugkm /    */
            /* PUSH RUN" and then ReadyToRun shows "x ugkm / y ml/h / PUSH  */
            /* RUN". Otherwise, it would show the user "x ugkm / x ugkm /   */
            /* y ml/h / PUSH RUN" which wouldn't look good.                 */
            if (                        /* We know pump is not running      */
                (modeflag & DOSEMODE)
                &&
                (volumevalue != 0)
               )
            {
                if (infusionincomplete) /* Show "IN STOP"   as well         */
                {
                    ALTERNATE(3);
                }
                else
                {
                    ALTERNATE(2);
                }
            }

            if (ratetodose)
            {                           /* Show the Dose Amount             */
                SHOWMSG(pdmspecsm07->Pomfp->Valmsg);
            }
            else
            {
                SHOWMSG(D_RATE_IN_MLH); /* macros expand; needs braces      */
            }

            Ii = 1;
            if (                        /* NB: Pump is not running          */
                (modeflag & DOSEMODE)
                &&
                (volumevalue != 0)
               )
            {
                Ii = 2;
                if (infusionincomplete)
                {
                    Ii = 3;
                    SHOWMSG(D_IN_STOP);
                }
                SHOWMSG(D_PUSH_RUN);
            }

            /* Display the calculated rate or dose with PUSH RUN, as        */
            /* applicable.                                                  */
            /* Ii * BLINKON in WAITCHAR is miserably messed-up by the       */
            /* compiler, so we must use a switch or if block, or get around */
            /* the problem using WaitMsg().                                 */
            WaitMsg(((Ii*BLINKON) - ALTREDUC) / CLKTICK, 4, ignorekeys);
            /* (Subtract 100ms to prevent any extra confusing flash)        */

            /* Possible strange messages with success can still set         */
            /* everything up, and be responded to.                          */
            /* If return(OK), we must push any codes we want considered     */
            /* back in the control mailbox.                                 */

            /* Simulate the effect of ENTER in ReadyToRun                   */
            if (KeyCode == C_ENTER)
            {
                STUFFMSG;
            }

        } /* End of if block to display the calculated rate                 */

    } /* End of if block to display the calculated rate.                    */

    if (KeyCode == C_OPTIONS)
    {
        /* Don't do STUFFMSG; rather return "IGNORE"                        */
        optionspressedinsetup = TRUE;
    }


    /* Block to exit the mode if all of the parameters got cleared          */

    if (
        (Modifiable)
        &&                              /* If all parameters are zero       */
        (TestParms(DOSEMODE) == NONESET)
       )
    {
        ClrDlydEnd(ParCh);              /* Even if user diddled the 0 key   */

        /* Clearing all parameters manually must cause correct clearing of  */
        /* Primary Mode if there was previously a valid Dose Mode. See      */
        /* ClearMode() for details.                                         */

        if (!(modeflag & NORMAL))       /* Don't bother falling off floor   */
        {
            ClearModeCore();            /* Parms already clear in here      */
        }

        if (!optionspressedinsetup)     /* if TRUE, don't pause for display */
        {
            ALTERNATE(2);               /* Display OPT    nn / OPT  CLRD    */
            SHOWMSG(D_OPT_LOCAL);
            /* Pushes KeyCode; all calling routines check mailbox           */
            /* Note that the quantity in ALTERNATE includes DelayMsg        */
            DelayMsg(D_OPT_CLRD, 2*BLINKON-ALTREDUC, DLYMSG_IGMPS);
        }
    }


    /* Default block to ensure that the pump stays in the current Dose Mode */

    /* If only some parms set, set the pump to the Dose Mode being looked   */
    /* at. This might apply if OPTIONS pressed partway through the list of  */
    /* parameters.                                                          */
    if (
        Modifiable
        &&
        (
         (TestParms(DOSEMODE) == SOMESET)
         ||
         /* Set modeflag here if going out via OPTIONS because DMRetCode    */
         /* was not OK, because we are not clearing the Dose parm upon exit */
         /* now, but we are leaving all parameters set, and we need to have */
         /* the modeflag set unconditionally so that a clear won't be done  */
         /* upon reentry from pnormal4.                                     */
         (TestParms(DOSEMODE) == ALLSET)
        )
        &&
        /* If SavedRate was set, then we either had a good CalcResult, or   */
        /* we restored SavedRate to ratevalue, and we shouldn't clear       */
        /* the GOTRATE flag. Adding this condition fixes a bug in which the */
        /* pump exited and re-entered through GetRate, ending up displaying */
        /* the rate with PUMP STOP / PUSH RUN twice. If SavedRate is set,   */
        /* then modeflag and pdmspecs are already correct.                  */
        (SavedRate == 0)
       )
    {
        ClrDlydEnd(ParCh);              /* Changes may have been made       */

        modeflag = DOSEMODE | (modeflag & DELAYEDRUN);
                                        /* Keep any Delayed Mode setting    */

        /* Must remember which Dose Mode to come back to                    */
        pdmspecs = pdmspecsm07;
        parmflag &= GOTRATEMASK;
        parmflag &= PARMMEMMASK;

        optionvalue = localoptno;
    }


    /* Total success block to update the rate and volume (not if needed     */
    /* SavedRate):                                                          */

    if (
        (
         (
          (TestParms(DOSEMODE) == ALLSET)
          &&
          Modifiable
         )
         ||
         /* Titration decision portion                                      */
         (
          Titrating
          &&
          Ch                            /* ratetodose cleared if no change  */
         )
        )
        &&
        (DMRetCode == OK)
       )
    /* Prompted by the possibility of clearing GOTRATE in order to push     */
    /* ENTER and do review (see GetVol and RequestValues):                  */
    /* Restore the GOTRATE flag if we are in Keylock, in this mode, and all */
    /* parameters are set and valid. Requires execution of calculation if   */
    /* pump is in Keylock (see above)                                       */
    /* This should cause you to be able to be in the middle of setting up   */
    /* parameters, set Keylock and get the GOTRATE flag back by continuing  */
    /* to review. Won't set GOTRATE if somehow the parameters got changed   */
    /* and are no longer valid.                                             */
    {
        /* Total success                                                    */

        ClrDlydEnd(ParCh);              /* Changes may have been made       */

        /* Change the running rate on the fly                               */
        if (Titrating)
        {
            KS_signal(STOPSEMA);
            /* In order to do Titration, we have changed motorctl() so that */
            /* it will always stop on a tick, in order to permit motorctl   */
            /* to maintain the volumevalue accurately. (If the user presses */
            /* STOP, this will cause a barely-perceptible delay of as much  */
            /* as 0.1 secs)                                                 */
            /* This means that clearing volumesofar and secondssofar here   */
            /* will not cause any runtime to be unaccounted for in the      */
            /* reduction of "volumevalue".                                  */
            /* Said clearing is necessary in order for the secondssofar to  */
            /* be multiplied only by its applicable runrate so that it will */
            /* produce the correct volumesofar and the correct Volume Incr  */
            /* for the purpose of reducing the volumevalue. See TICKSEMA    */
            /* and STOPSEMA in motorctl().                                  */
        }
        /* The same argument applies to changing the rate when the pump is  */
        /* stopped:                                                         */
        secondssofar = 0;
        volumesofar = 0;

        /* dosemodevol is not reduced while running because user might stop */
        /* and do a review and MultDiv must still give the same rate        */
        /* result. Now it is used only for concentration purposes.          */
        /* Moved clearing of vtbi to top of function                        */

        /* CalcResult should already have set rate value when all pars were */
        /* set above, but just to be safe, and if Titrating,                */
        if (!(ratetodose))
        /* if ratetodose, rate was already typed in                         */
        /* Do separately to ward off compiler bugs:                         */
        {
            runrate = CalcResult;
            schedlist[1].SchedRate = CalcResult;
            ratevalue = CalcResult;
        }
        /* but the runrate and schedlist must still be updated; otherwise,  */
        /* out-of-date values might remain there.                           */
        else                            /* Is ratetodose                    */
        {
            runrate = ratevalue;
            schedlist[1].SchedRate = ratevalue;
        }

        /* History log the rate value the pump is set to run with           */
        HistMsg.msgtype = RUNRATEVALUESET_TYPE;
        HISTLOG(runrate);

        parmflag |= GOTRATE;

        if (
            (parmflag & GOTRATE)
            &&
            (parmflag & GOTVOL)
           )
        {
            parmflag |= PARMMEM;        /* Make sure mode is all set        */
        }

        modeflag = DOSEMODE | (modeflag & DELAYEDRUN);
                                        /* Keep any Delayed Mode setting    */

        pdmspecs = pdmspecsm07;         /* Set the current Dose Mode        */
        optionvalue = localoptno;

        infcounter = 1;                 /* Replace the Primary Mode         */
        infmax = 1;

        if (Titrating)
            KS_signal(STRTSEMA);

    }

    /* Default operation is Dose to Rate unless Dose Mode first set up,     */
    /* then RATE key pressed.                                               */
    /* Exit ratetodose if OPTIONS, or anything                              */
    ratetodose = FALSE;

    statusflag &= REVIEWMASK;           /* Clear any possible review status */

    /* Shouldn't be necessary to set KeyCode = NULL. If we had an ENTER or  */
    /* a RUN, we don't want beeping, right?                                 */

    /* Return to pnormal4, pnormal3 -- ReadyToRun or Running, or pnormal1   */
    /* -- RequestValues:                                                    */
    if (
        (
         (KeyCode >= C_RCINST)
         &&
         (KeyCode <= C_LASTMSG)
        )
        ||
        (KeyCode == C_POWEROFF)
        ||
        (KeyCode == C_VOLUME)
        ||
        (KeyCode == C_RATE)
        ||
        (KeyCode == C_OPTIONS)
       )
    {   /* Not really "IGNORE", just react to the strange message           */
        return(IGNORE);
    }
    else
    {
        /* Doing return OK - KeyCodes need to be stuffed in order to be     */
        /* responded to, whether the pump is running or not                 */
        if (
            (KeyCode != C_NULL)
            &&
            (KeyCode != C_ENTER)
           )
        {
            STUFFMSG;                   /* Restore received code            */
        }

        return(OK);
    }

} /* End of Mode07. Subroutines follow.                                 */

back

First posted Oct 13, 2003

Hosted by www.Geocities.ws

1