SlideShare a Scribd company logo
1 of 9
// Basic autopilot for heart-lung machine, monitor reservoir level and control
roller pump
// used with a softshell reservoir and Omega load cell and meter, Stockert CAPS
roller pump
// and Omega digital-to-analog converter
// Kenneth Wilkerson 2008 Midwestern University

using   System;
using   System.Globalization;
using   System.IO;
using   System.Collections;
using   System.Collections.Generic;
using   System.ComponentModel;
using   System.Data;
using   System.Drawing;
using   System.Text;
using   System.Windows.Forms;
using   System.Runtime.InteropServices;
using   SpeechLib;
using   System.Media;

namespace hlmautopilot
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            serialPort1.Open();
            //setup request to load cell meter
            weightreq[0] = '*';
            weightreq[1] = 'X';
            weightreq[2] = '0';
            weightreq[3] = '1';
            weightreq[4] = 'r';
            weightreq[5] = '0';

              //setup initial values
              minreslevel = (double)minreslvlctl.Value;
              lowreslevel = (double)lowreslvlctl.Value;
              maxflowrate = (double)flowctl.Value;
              maxrpm = (int)((maxflowrate * 1000) / strokevolume);
              pumpon = false;
              curreslevel = 0;
              waterbtn.Checked = true;
              density = waterdensity;
              recordon = false;
              nfi = new CultureInfo("en-US", false).NumberFormat;
              nfi.NumberDecimalDigits = 1;
              greenuparrow = new Bitmap(@"greenuparrow.bmp", false);
              reddownarrow = new Bitmap(@"reddownarrow.bmp", false);
              lvlchangerate.Minimum = 0;
              lvlchangerate.Maximum = (int)(maxflowrate * 1000);
              lvlchangerate.Value = 0;
              minpercentflow = (int)pctflowctl.Value;

              //Create voice object
              voice = new SpVoice();
         }

         //Start monitoring reservoir event
         private void monstart_click(object sender, EventArgs e)
         {
             monstopbtn.Enabled = true;
monstartbtn.Enabled = false;
            timer1.Enabled = true;
            monitortime = 0.0;
            reslevels = new Queue();
        }

        //Stop monitoring reservoir event
        private void monstop_click(object sender, EventArgs e)
        {
            monstartbtn.Enabled = true;
            monstopbtn.Enabled = false;
            timer1.Enabled = false;
            curreslvl.Text = "";

        }
        //Start roller pump event
        private void pumpstart_click(object sender, EventArgs e)
        {
            int rc = 0;
            ushort numcards;

            //rc = omega.pioda.PIODA_DriverInit();
            if (rc != omega.pioda.PIODA_NoError)
            {
                throw new System.ApplicationException("DriverInit failed");
            }
            unsafe
            {
               // rc = omega.pioda.PIODA_SearchCard(&numcards,
omega.pioda.PIO_DA);
                if (rc != omega.pioda.PIODA_NoError)
                {
                     throw new System.ApplicationException("SearchCard failed");
                }
            }
            pumpstartbtn.Enabled = false;
            pumpstopbtn.Enabled = true;
            pumpon = true;
            pumpstate = pumpstates.FullFlow;
            oldpumpstate = pumpstates.FullFlow;
        }

        //Stop roller pump event
        private void pumpstop_click(object sender, EventArgs e)
        {
            omega.pioda.PIODA_Voltage(0, 0, 0.0F);
            omega.pioda.PIODA_Voltage(0, 1, 0.0F);
            omega.pioda.PIODA_Voltage(0, 2, 0.0F);
            omega.pioda.PIODA_Voltage(0, 3, 0.0F);
            omega.pioda.PIODA_DriverClose();
            pumpstartbtn.Enabled = true;
            pumpstopbtn.Enabled = false;
            pumpon = false;

        }

        //Process timer event
        private void timer_tick(object sender, EventArgs e)
        {
            char[] buf = new char[15];
            int nread;
            char chrread;
            double pctflow;
            int changerate;
//Increment times
      elapsedtime += timer1.Interval / 1000.0;
      monitortime += timer1.Interval / 1000.0;

      //Send request to load cell meter and process response
      serialPort1.Write(weightreq, 0, 5);
      nread = 0;
      chrread = '0';
      while ((chrread != 'n') && (nread < 15))
      {
          chrread = (char)serialPort1.ReadChar();
          buf[nread] = chrread;
          nread++;
      }

      weight = parseweightrsp(buf);
      curreslevel = (weight * 1000) / density;
      reslevels.Enqueue(curreslevel);
      curreslvl.Text = curreslevel.ToString("F");

      //Keep five seconds of weight responses
      if (monitortime < 5.0)
      {
      }
      else if (monitortime >= 5.0)
      {
          previousreslevel = (double)reslevels.Dequeue();
          if (curreslevel - previousreslevel > 25.0)
          {//res level rising
              leveltrend.Image = (Image)greenuparrow;
              changerate = (int)((curreslevel - previousreslevel) / 5) *
60;
              if (changerate > (int)(maxflowrate * 1000))
              {
                  changerate = (int)(maxflowrate * 1000);
              }
              lvlchangerate.Value = changerate;
          }
          else if (previousreslevel - curreslevel > 25.0)
          {//res level falling
              leveltrend.Image = (Image)reddownarrow;
              changerate = (int)((previousreslevel - curreslevel) / 5) *
60;
              if (changerate > (int)(maxflowrate * 1000))
              {
                  changerate = (int)(maxflowrate * 1000);
              }
              lvlchangerate.Value = changerate;
          }
          else
          {//res level steady
               leveltrend.Image = null;
               lvlchangerate.Value = 0;
          }
      }

      if (pumpon == true)
      {
          oldpumpstate = pumpstate;// save current pump state
          pctflow = manageflow();
          //Set status colors based on amount of flow from pump
          if (pctflow == 100.0)// full flow
          {
pumpstate = pumpstates.FullFlow;
                    curreslvl.BackColor = Color.LightGreen;
                    curflow.BackColor = Color.LightGreen;
                }
                else if (pctflow == 0.0)// no flow
                {
                    pumpstate = pumpstates.Stopped;
                    curreslvl.BackColor = Color.Red;
                    curflow.BackColor = Color.Red;
                }
                else //partial flow
                {
                    pumpstate = pumpstates.PartialFlow;
                    curreslvl.BackColor = Color.Yellow;
                    curflow.BackColor = Color.Yellow;
                }

                setrpm(maxrpm, pctflow);// set pumps rpm for this amount of flow
                curflowrate = maxflowrate * (pctflow / 100.0);
                curflow.Text = Convert.ToString(curflowrate);

                // If state of pump is changing, make announcement
                if (oldpumpstate == pumpstates.FullFlow)
                {
                    if (pumpstate == pumpstates.PartialFlow)
                    {
                        SystemSounds.Exclamation.Play();
                        voice.Speak("warning reservoir low, slowing pump",
SpFlags);
                    }
                    else if (pumpstate == pumpstates.Stopped)
                    {
                        SystemSounds.Exclamation.Play();
                        voice.Speak("warning, reservoir critical, stopping
pump", SpFlags);
                    }
                }
                else if (oldpumpstate == pumpstates.PartialFlow)
                {
                    if (pumpstate == pumpstates.FullFlow)
                    {
                        SystemSounds.Exclamation.Play();
                        voice.Speak("resuming full flow", SpFlags);
                    }
                    else if (pumpstate == pumpstates.Stopped)
                    {
                        SystemSounds.Exclamation.Play();
                        voice.Speak("warning, reservoir critical, stopping
pump", SpFlags);
                    }
                }
                else if (oldpumpstate == pumpstates.Stopped)
                {
                    if (pumpstate == pumpstates.FullFlow)
                    {
                        SystemSounds.Exclamation.Play();
                        voice.Speak("resuming full flow", SpFlags);
                    }
                    else if (pumpstate == pumpstates.PartialFlow)
                    {
                        SystemSounds.Exclamation.Play();
                        voice.Speak("restarting pump, partial flow", SpFlags);
                    }
                }
if (recordon)// record res level and flow rate
                {
                    logfile.Write(elapsedtime);
                    logfile.Write(",");
                    logfile.Write(curreslvl.Text);
                    logfile.Write(",");
                    logfile.WriteLine(curflow.Text);
                }
            }
            else // pump off
            {
                curreslvl.BackColor = Color.White;
                curflow.BackColor = Color.White;
            }
        }

        // Parse response from load cell meter
        private double parseweightrsp(char[] rsp)
        {
            char[] buf = new char[6];
            double weight;
            int i;
            String swght;

            for (i = 0; i < 5; i++)
            {
                buf[i] = rsp[i + 3];
            }
            buf[5] = '0';

            swght = new String(buf);

            weight = Double.Parse(swght);

            return weight;
        }

        //determine proper pump flow rate based on max flow rate, current,
minimum and low
        // reservoir levels
        private double manageflow()
        {
            double pctflow = 0.0;

            if (curreslevel > lowreslevel)// current above low
            {
                pctflow = 100.0;
            }
            else if ((curreslevel <= lowreslevel) && (curreslevel >
minreslevel))
            {// current between low and minimum
                switch (pumpstate)
                {
                    case pumpstates.FullFlow://pump slowing
                    case pumpstates.PartialFlow:
                        pctflow = minpercentflow + (int)((100.0 -
minpercentflow) *
                                   ((curreslevel - minreslevel) / (lowreslevel -
minreslevel)));
                        break;

                    case pumpstates.Stopped:// resuming from stopped
                        if (curreslevel > lowreslevel)
                        {
pctflow = 100.0;
                        }
                        else if (curreslevel >= minreslevel + 75)
                        {
                            pctflow = minpercentflow + (int)((100.0 -
minpercentflow) *
                                ((curreslevel - minreslevel) / (lowreslevel -
minreslevel)));
                        }
                        else
                        {
                            pctflow = 0.0;
                        }
                        break;
                }
            }
            else // current level at or below minimum level
            {
                pctflow = 0.0;
            }

            return pctflow;
       }

       // change in minimum res level event
       private void minres_click(object sender, EventArgs e)
       {
           minreslevel = (double)minreslvlctl.Value;
       }

       //change in low res level event
       private void lowres_click(object sender, EventArgs e)
       {
           lowreslevel = (double)lowreslvlctl.Value;
       }

       //change in maximum flow event
       private void maxflow_click(object sender, EventArgs e)
       {
           maxflowrate = (double)flowctl.Value;
           maxrpm = (int)((maxflowrate * 1000) / strokevolume);
           lvlchangerate.Maximum = (int)(maxflowrate * 1000);
       }

       //Stop recording evengt
       private void rcrdstop_click(object sender, EventArgs e)
       {
           logfile.Close();
           recordon = false;
           recordstartbtn.Enabled = true;
           recordstopbtn.Enabled = false;
       }


       //Start recording event
       private void rcrdstart_click(object sender, EventArgs e)
       {
           SaveFileDialog saveFileDialog1 = new SaveFileDialog();
           saveFileDialog1.Title = "Save log data";
           saveFileDialog1.Filter = "Text files (*.txt)|*.txt";
           saveFileDialog1.ShowDialog();
           if (saveFileDialog1.FileName != "")
           {
               logdata = saveFileDialog1.OpenFile();
logfile = new StreamWriter(logdata);
            }
            recordon = true;
            elapsedtime = 0.0;
            recordstopbtn.Enabled = true;
            recordstartbtn.Enabled = false;
            logfile.WriteLine("Max flow rate,Min percent flow,Min res level,low
res level");
            logfile.Write(flowctl.Value);
            logfile.Write(",");
            logfile.Write(pctflowctl.Value);
            logfile.Write(",");
            logfile.Write(minreslvlctl.Value);
            logfile.Write(",");
            logfile.WriteLine(lowreslvlctl.Value);
            logfile.WriteLine("Elapsed Time, Volume, Flowrate");

        }

        //Set fluid to water event
        private void waterbtn_click(object sender, EventArgs e)
        {
             density = waterdensity;
        }

        //Set fluid to blood event
        private void bloodbtn_click(object sender, EventArgs e)
        {
            density = blooddensity;
        }

        // set minimum amount of flow relative to max flow before
        // stop pump
        private void minpctflow_click(object sender, EventArgs e)
        {
            minpercentflow = (int)pctflowctl.Value;
        }

        //set pump rpm based on max rpm and percent flow
        private int setrpm(int maxrpm, double pctflow)
        {
            int rc = 0;
            float currpm;

            if ((maxrpm >= 0) && (maxrpm <= 175))
            {
                if (pctflow > 0.0)
                {
                    currpm = (float)(maxrpm * pctflow / 100.0);

                 //     rc = omega.pioda.PIODA_CalVoltage(0, 0, channel0_base +
0);
                      if (rc != omega.pioda.PIODA_NoError)
                      {
                          throw new System.ApplicationException("set voltage
channel 0 failed");
                     }
                    // rc = omega.pioda.PIODA_CalVoltage(0, 1, channel1_base +
(channel1_vrpm * currpm));
                     if (rc != omega.pioda.PIODA_NoError)
                     {
                         throw new System.ApplicationException("set voltage
channel 1 failed");
                     }
//   rc = omega.pioda.PIODA_CalVoltage(0, 2, channel2_base +
(channel2_vrpm * currpm));
                      if (rc != omega.pioda.PIODA_NoError)
                      {
                          throw new System.ApplicationException("set voltage
channel 2 failed");
                      }
                   //   rc = omega.pioda.PIODA_CalVoltage(0, 3, channel3_base +
(channel3_vrpm * currpm));
                      if (rc != omega.pioda.PIODA_NoError)
                      {
                          throw new System.ApplicationException("set voltage
channel 3 failed");
                      }
                 }
                 else // Stop pump
                 {
                    // rc = omega.pioda.PIODA_CalVoltage(0, 0, 0.0F);
                      if (rc != omega.pioda.PIODA_NoError)
                      {
                          throw new System.ApplicationException("set voltage
channel 0 failed");
                      }
                   //   rc = omega.pioda.PIODA_CalVoltage(0, 1, 0.0F);
                      if (rc != omega.pioda.PIODA_NoError)
                      {
                          throw new System.ApplicationException("set voltage
channel 1 failed");
                      }
               //       rc = omega.pioda.PIODA_CalVoltage(0, 2, 0.0F);
                      if (rc != omega.pioda.PIODA_NoError)
                      {
                          throw new System.ApplicationException("set voltage
channel 2 failed");
                      }
                 //     rc = omega.pioda.PIODA_CalVoltage(0, 3, 0.0F);
                      if (rc != omega.pioda.PIODA_NoError)
                      {
                          throw new System.ApplicationException("set voltage
channel 3 failed");
                      }
                 }
                 return 0;
            }
            else
            {
                 return -1;
            }
        }
        enum pumpstates { Stopped, PartialFlow, FullFlow };
        pumpstates pumpstate, oldpumpstate;
        const float channel0_base = 0.0739F; //Yellow
        const float channel1_base = 0.0739F; //Gray
        const float channel2_base = 0.1148F; // Blue
        const float channel3_base = 0.0792F; //Brown
        const float channel0_vrpm = 0.0097F; //Yellow
        const float channel1_vrpm = 0.0097F; //Gray
        const float channel2_vrpm = 0.0557F; // Blue
        const float channel3_vrpm = 0.0239F; //Brown
        const float strokevolume = 46.0F;

        const float waterdensity = 0.99823F; // tap water 20 C
        const float blooddensity = 1.06F;
        float density = 1.0F;
double weight;
        char[] weightreq = new char[6]; //"*X01";
        double minreslevel;
        double lowreslevel;
        Double curreslevel;
        double previousreslevel;
        double maxflowrate;
        int maxrpm;
        Boolean pumpon;
        double curflowrate;
        StreamWriter logfile;
        Stream logdata;
        double elapsedtime;
        Boolean recordon;
        NumberFormatInfo nfi;
        double monitortime;
        Queue reslevels;
        Bitmap greenuparrow, reddownarrow;
        SpVoice voice;
        SpeechVoiceSpeakFlags SpFlags = SpeechVoiceSpeakFlags.SVSFlagsAsync;
        int minpercentflow;
    }
}

namespace omega
{
    class pioda
    {
        // return co
        public const int PIODA_NoError = 0;

        // ID
        public const int PIO_DA = 0x800400;

        // Driver functions
        [DllImport("PIODA.DLL")]
        static public extern ushort PIODA_DriverInit();
        [DllImport("PIODA.DLL")]
        static public extern void PIODA_DriverClose();

        [DllImport("PIODA.DLL")]
        static public unsafe extern ushort PIODA_SearchCard
               (ushort* wBoards, int dwPIOCardID);

        // DA functions
        [DllImport("PIODA.DLL")]
        static public extern ushort PIODA_Voltage
                   (ushort wBoardNo, ushort wChannel,   float fValue);
        [DllImport("PIODA.DLL")]
        static public extern ushort PIODA_Current
                   (ushort wBoardNo, ushort wChannel,   float fValue);
        [DllImport("PIODA.DLL")]
        static public extern ushort PIODA_CalVoltage
                   (ushort wBoardNo, ushort wChannel,   float fValue);
        [DllImport("PIODA.DLL")]
        static public extern ushort PIODA_CalCurrent
                   (ushort wBoardNo, ushort wChannel,   float fValue);
    }
}

More Related Content

Similar to Form1.Cs

Removal Of Recursion
Removal Of RecursionRemoval Of Recursion
Removal Of RecursionRicha Sharma
 
Chaining et composition de fonctions avec lodash / underscore
Chaining et composition de fonctions avec lodash / underscoreChaining et composition de fonctions avec lodash / underscore
Chaining et composition de fonctions avec lodash / underscoreNicolas Carlo
 
java compilerCompiler1.javajava compilerCompiler1.javaimport.docx
java compilerCompiler1.javajava compilerCompiler1.javaimport.docxjava compilerCompiler1.javajava compilerCompiler1.javaimport.docx
java compilerCompiler1.javajava compilerCompiler1.javaimport.docxpriestmanmable
 
public class LunarLander {    double currentFuelFlowRate;    d.pdf
public class LunarLander {    double currentFuelFlowRate;    d.pdfpublic class LunarLander {    double currentFuelFlowRate;    d.pdf
public class LunarLander {    double currentFuelFlowRate;    d.pdfanjalitimecenter11
 
public void turnRight(double degrees) {rotationInDegrees + - = deg.pdf
public void turnRight(double degrees) {rotationInDegrees + - = deg.pdfpublic void turnRight(double degrees) {rotationInDegrees + - = deg.pdf
public void turnRight(double degrees) {rotationInDegrees + - = deg.pdfisenbergwarne4100
 
PHP Enums - PHPCon Japan 2021
PHP Enums - PHPCon Japan 2021PHP Enums - PHPCon Japan 2021
PHP Enums - PHPCon Japan 2021Ayesh Karunaratne
 
help me Java projectI put problem and my own code in the linkmy .pdf
help me Java projectI put problem and my own code in the linkmy .pdfhelp me Java projectI put problem and my own code in the linkmy .pdf
help me Java projectI put problem and my own code in the linkmy .pdfarihantmum
 
b. (10 pts) Implement the rotate left method for AVL trees.c. (10 .pdf
b. (10 pts) Implement the rotate left method for AVL trees.c. (10 .pdfb. (10 pts) Implement the rotate left method for AVL trees.c. (10 .pdf
b. (10 pts) Implement the rotate left method for AVL trees.c. (10 .pdfakanshanawal
 
Single server queue (Simulation Project)
Single server queue (Simulation Project)Single server queue (Simulation Project)
Single server queue (Simulation Project)Md.zahedul Karim Tuhin
 
6 c control statements branching &amp; jumping
6 c control statements branching &amp; jumping6 c control statements branching &amp; jumping
6 c control statements branching &amp; jumpingMomenMostafa
 
Programming Fundamentals lecture 8
Programming Fundamentals lecture 8Programming Fundamentals lecture 8
Programming Fundamentals lecture 8REHAN IJAZ
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSAdam L Barrett
 
Chaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscoreChaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscoreNicolas Carlo
 

Similar to Form1.Cs (20)

Menu Driven programs in Java
Menu Driven programs in JavaMenu Driven programs in Java
Menu Driven programs in Java
 
Michael kontopoulos
Michael kontopoulosMichael kontopoulos
Michael kontopoulos
 
Memory Manglement in Raku
Memory Manglement in RakuMemory Manglement in Raku
Memory Manglement in Raku
 
Removal Of Recursion
Removal Of RecursionRemoval Of Recursion
Removal Of Recursion
 
Chaining et composition de fonctions avec lodash / underscore
Chaining et composition de fonctions avec lodash / underscoreChaining et composition de fonctions avec lodash / underscore
Chaining et composition de fonctions avec lodash / underscore
 
java compilerCompiler1.javajava compilerCompiler1.javaimport.docx
java compilerCompiler1.javajava compilerCompiler1.javaimport.docxjava compilerCompiler1.javajava compilerCompiler1.javaimport.docx
java compilerCompiler1.javajava compilerCompiler1.javaimport.docx
 
public class LunarLander {    double currentFuelFlowRate;    d.pdf
public class LunarLander {    double currentFuelFlowRate;    d.pdfpublic class LunarLander {    double currentFuelFlowRate;    d.pdf
public class LunarLander {    double currentFuelFlowRate;    d.pdf
 
Php Enums
Php EnumsPhp Enums
Php Enums
 
PHP 8.1: Enums
PHP 8.1: EnumsPHP 8.1: Enums
PHP 8.1: Enums
 
public void turnRight(double degrees) {rotationInDegrees + - = deg.pdf
public void turnRight(double degrees) {rotationInDegrees + - = deg.pdfpublic void turnRight(double degrees) {rotationInDegrees + - = deg.pdf
public void turnRight(double degrees) {rotationInDegrees + - = deg.pdf
 
PHP Enums - PHPCon Japan 2021
PHP Enums - PHPCon Japan 2021PHP Enums - PHPCon Japan 2021
PHP Enums - PHPCon Japan 2021
 
The most exciting features of PHP 7.1
The most exciting features of PHP 7.1The most exciting features of PHP 7.1
The most exciting features of PHP 7.1
 
help me Java projectI put problem and my own code in the linkmy .pdf
help me Java projectI put problem and my own code in the linkmy .pdfhelp me Java projectI put problem and my own code in the linkmy .pdf
help me Java projectI put problem and my own code in the linkmy .pdf
 
b. (10 pts) Implement the rotate left method for AVL trees.c. (10 .pdf
b. (10 pts) Implement the rotate left method for AVL trees.c. (10 .pdfb. (10 pts) Implement the rotate left method for AVL trees.c. (10 .pdf
b. (10 pts) Implement the rotate left method for AVL trees.c. (10 .pdf
 
Assignment 3
Assignment 3Assignment 3
Assignment 3
 
Single server queue (Simulation Project)
Single server queue (Simulation Project)Single server queue (Simulation Project)
Single server queue (Simulation Project)
 
6 c control statements branching &amp; jumping
6 c control statements branching &amp; jumping6 c control statements branching &amp; jumping
6 c control statements branching &amp; jumping
 
Programming Fundamentals lecture 8
Programming Fundamentals lecture 8Programming Fundamentals lecture 8
Programming Fundamentals lecture 8
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJS
 
Chaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscoreChaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscore
 

Form1.Cs

  • 1. // Basic autopilot for heart-lung machine, monitor reservoir level and control roller pump // used with a softshell reservoir and Omega load cell and meter, Stockert CAPS roller pump // and Omega digital-to-analog converter // Kenneth Wilkerson 2008 Midwestern University using System; using System.Globalization; using System.IO; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; using SpeechLib; using System.Media; namespace hlmautopilot { public partial class Form1 : Form { public Form1() { InitializeComponent(); serialPort1.Open(); //setup request to load cell meter weightreq[0] = '*'; weightreq[1] = 'X'; weightreq[2] = '0'; weightreq[3] = '1'; weightreq[4] = 'r'; weightreq[5] = '0'; //setup initial values minreslevel = (double)minreslvlctl.Value; lowreslevel = (double)lowreslvlctl.Value; maxflowrate = (double)flowctl.Value; maxrpm = (int)((maxflowrate * 1000) / strokevolume); pumpon = false; curreslevel = 0; waterbtn.Checked = true; density = waterdensity; recordon = false; nfi = new CultureInfo("en-US", false).NumberFormat; nfi.NumberDecimalDigits = 1; greenuparrow = new Bitmap(@"greenuparrow.bmp", false); reddownarrow = new Bitmap(@"reddownarrow.bmp", false); lvlchangerate.Minimum = 0; lvlchangerate.Maximum = (int)(maxflowrate * 1000); lvlchangerate.Value = 0; minpercentflow = (int)pctflowctl.Value; //Create voice object voice = new SpVoice(); } //Start monitoring reservoir event private void monstart_click(object sender, EventArgs e) { monstopbtn.Enabled = true;
  • 2. monstartbtn.Enabled = false; timer1.Enabled = true; monitortime = 0.0; reslevels = new Queue(); } //Stop monitoring reservoir event private void monstop_click(object sender, EventArgs e) { monstartbtn.Enabled = true; monstopbtn.Enabled = false; timer1.Enabled = false; curreslvl.Text = ""; } //Start roller pump event private void pumpstart_click(object sender, EventArgs e) { int rc = 0; ushort numcards; //rc = omega.pioda.PIODA_DriverInit(); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("DriverInit failed"); } unsafe { // rc = omega.pioda.PIODA_SearchCard(&numcards, omega.pioda.PIO_DA); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("SearchCard failed"); } } pumpstartbtn.Enabled = false; pumpstopbtn.Enabled = true; pumpon = true; pumpstate = pumpstates.FullFlow; oldpumpstate = pumpstates.FullFlow; } //Stop roller pump event private void pumpstop_click(object sender, EventArgs e) { omega.pioda.PIODA_Voltage(0, 0, 0.0F); omega.pioda.PIODA_Voltage(0, 1, 0.0F); omega.pioda.PIODA_Voltage(0, 2, 0.0F); omega.pioda.PIODA_Voltage(0, 3, 0.0F); omega.pioda.PIODA_DriverClose(); pumpstartbtn.Enabled = true; pumpstopbtn.Enabled = false; pumpon = false; } //Process timer event private void timer_tick(object sender, EventArgs e) { char[] buf = new char[15]; int nread; char chrread; double pctflow; int changerate;
  • 3. //Increment times elapsedtime += timer1.Interval / 1000.0; monitortime += timer1.Interval / 1000.0; //Send request to load cell meter and process response serialPort1.Write(weightreq, 0, 5); nread = 0; chrread = '0'; while ((chrread != 'n') && (nread < 15)) { chrread = (char)serialPort1.ReadChar(); buf[nread] = chrread; nread++; } weight = parseweightrsp(buf); curreslevel = (weight * 1000) / density; reslevels.Enqueue(curreslevel); curreslvl.Text = curreslevel.ToString("F"); //Keep five seconds of weight responses if (monitortime < 5.0) { } else if (monitortime >= 5.0) { previousreslevel = (double)reslevels.Dequeue(); if (curreslevel - previousreslevel > 25.0) {//res level rising leveltrend.Image = (Image)greenuparrow; changerate = (int)((curreslevel - previousreslevel) / 5) * 60; if (changerate > (int)(maxflowrate * 1000)) { changerate = (int)(maxflowrate * 1000); } lvlchangerate.Value = changerate; } else if (previousreslevel - curreslevel > 25.0) {//res level falling leveltrend.Image = (Image)reddownarrow; changerate = (int)((previousreslevel - curreslevel) / 5) * 60; if (changerate > (int)(maxflowrate * 1000)) { changerate = (int)(maxflowrate * 1000); } lvlchangerate.Value = changerate; } else {//res level steady leveltrend.Image = null; lvlchangerate.Value = 0; } } if (pumpon == true) { oldpumpstate = pumpstate;// save current pump state pctflow = manageflow(); //Set status colors based on amount of flow from pump if (pctflow == 100.0)// full flow {
  • 4. pumpstate = pumpstates.FullFlow; curreslvl.BackColor = Color.LightGreen; curflow.BackColor = Color.LightGreen; } else if (pctflow == 0.0)// no flow { pumpstate = pumpstates.Stopped; curreslvl.BackColor = Color.Red; curflow.BackColor = Color.Red; } else //partial flow { pumpstate = pumpstates.PartialFlow; curreslvl.BackColor = Color.Yellow; curflow.BackColor = Color.Yellow; } setrpm(maxrpm, pctflow);// set pumps rpm for this amount of flow curflowrate = maxflowrate * (pctflow / 100.0); curflow.Text = Convert.ToString(curflowrate); // If state of pump is changing, make announcement if (oldpumpstate == pumpstates.FullFlow) { if (pumpstate == pumpstates.PartialFlow) { SystemSounds.Exclamation.Play(); voice.Speak("warning reservoir low, slowing pump", SpFlags); } else if (pumpstate == pumpstates.Stopped) { SystemSounds.Exclamation.Play(); voice.Speak("warning, reservoir critical, stopping pump", SpFlags); } } else if (oldpumpstate == pumpstates.PartialFlow) { if (pumpstate == pumpstates.FullFlow) { SystemSounds.Exclamation.Play(); voice.Speak("resuming full flow", SpFlags); } else if (pumpstate == pumpstates.Stopped) { SystemSounds.Exclamation.Play(); voice.Speak("warning, reservoir critical, stopping pump", SpFlags); } } else if (oldpumpstate == pumpstates.Stopped) { if (pumpstate == pumpstates.FullFlow) { SystemSounds.Exclamation.Play(); voice.Speak("resuming full flow", SpFlags); } else if (pumpstate == pumpstates.PartialFlow) { SystemSounds.Exclamation.Play(); voice.Speak("restarting pump, partial flow", SpFlags); } }
  • 5. if (recordon)// record res level and flow rate { logfile.Write(elapsedtime); logfile.Write(","); logfile.Write(curreslvl.Text); logfile.Write(","); logfile.WriteLine(curflow.Text); } } else // pump off { curreslvl.BackColor = Color.White; curflow.BackColor = Color.White; } } // Parse response from load cell meter private double parseweightrsp(char[] rsp) { char[] buf = new char[6]; double weight; int i; String swght; for (i = 0; i < 5; i++) { buf[i] = rsp[i + 3]; } buf[5] = '0'; swght = new String(buf); weight = Double.Parse(swght); return weight; } //determine proper pump flow rate based on max flow rate, current, minimum and low // reservoir levels private double manageflow() { double pctflow = 0.0; if (curreslevel > lowreslevel)// current above low { pctflow = 100.0; } else if ((curreslevel <= lowreslevel) && (curreslevel > minreslevel)) {// current between low and minimum switch (pumpstate) { case pumpstates.FullFlow://pump slowing case pumpstates.PartialFlow: pctflow = minpercentflow + (int)((100.0 - minpercentflow) * ((curreslevel - minreslevel) / (lowreslevel - minreslevel))); break; case pumpstates.Stopped:// resuming from stopped if (curreslevel > lowreslevel) {
  • 6. pctflow = 100.0; } else if (curreslevel >= minreslevel + 75) { pctflow = minpercentflow + (int)((100.0 - minpercentflow) * ((curreslevel - minreslevel) / (lowreslevel - minreslevel))); } else { pctflow = 0.0; } break; } } else // current level at or below minimum level { pctflow = 0.0; } return pctflow; } // change in minimum res level event private void minres_click(object sender, EventArgs e) { minreslevel = (double)minreslvlctl.Value; } //change in low res level event private void lowres_click(object sender, EventArgs e) { lowreslevel = (double)lowreslvlctl.Value; } //change in maximum flow event private void maxflow_click(object sender, EventArgs e) { maxflowrate = (double)flowctl.Value; maxrpm = (int)((maxflowrate * 1000) / strokevolume); lvlchangerate.Maximum = (int)(maxflowrate * 1000); } //Stop recording evengt private void rcrdstop_click(object sender, EventArgs e) { logfile.Close(); recordon = false; recordstartbtn.Enabled = true; recordstopbtn.Enabled = false; } //Start recording event private void rcrdstart_click(object sender, EventArgs e) { SaveFileDialog saveFileDialog1 = new SaveFileDialog(); saveFileDialog1.Title = "Save log data"; saveFileDialog1.Filter = "Text files (*.txt)|*.txt"; saveFileDialog1.ShowDialog(); if (saveFileDialog1.FileName != "") { logdata = saveFileDialog1.OpenFile();
  • 7. logfile = new StreamWriter(logdata); } recordon = true; elapsedtime = 0.0; recordstopbtn.Enabled = true; recordstartbtn.Enabled = false; logfile.WriteLine("Max flow rate,Min percent flow,Min res level,low res level"); logfile.Write(flowctl.Value); logfile.Write(","); logfile.Write(pctflowctl.Value); logfile.Write(","); logfile.Write(minreslvlctl.Value); logfile.Write(","); logfile.WriteLine(lowreslvlctl.Value); logfile.WriteLine("Elapsed Time, Volume, Flowrate"); } //Set fluid to water event private void waterbtn_click(object sender, EventArgs e) { density = waterdensity; } //Set fluid to blood event private void bloodbtn_click(object sender, EventArgs e) { density = blooddensity; } // set minimum amount of flow relative to max flow before // stop pump private void minpctflow_click(object sender, EventArgs e) { minpercentflow = (int)pctflowctl.Value; } //set pump rpm based on max rpm and percent flow private int setrpm(int maxrpm, double pctflow) { int rc = 0; float currpm; if ((maxrpm >= 0) && (maxrpm <= 175)) { if (pctflow > 0.0) { currpm = (float)(maxrpm * pctflow / 100.0); // rc = omega.pioda.PIODA_CalVoltage(0, 0, channel0_base + 0); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("set voltage channel 0 failed"); } // rc = omega.pioda.PIODA_CalVoltage(0, 1, channel1_base + (channel1_vrpm * currpm)); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("set voltage channel 1 failed"); }
  • 8. // rc = omega.pioda.PIODA_CalVoltage(0, 2, channel2_base + (channel2_vrpm * currpm)); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("set voltage channel 2 failed"); } // rc = omega.pioda.PIODA_CalVoltage(0, 3, channel3_base + (channel3_vrpm * currpm)); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("set voltage channel 3 failed"); } } else // Stop pump { // rc = omega.pioda.PIODA_CalVoltage(0, 0, 0.0F); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("set voltage channel 0 failed"); } // rc = omega.pioda.PIODA_CalVoltage(0, 1, 0.0F); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("set voltage channel 1 failed"); } // rc = omega.pioda.PIODA_CalVoltage(0, 2, 0.0F); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("set voltage channel 2 failed"); } // rc = omega.pioda.PIODA_CalVoltage(0, 3, 0.0F); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("set voltage channel 3 failed"); } } return 0; } else { return -1; } } enum pumpstates { Stopped, PartialFlow, FullFlow }; pumpstates pumpstate, oldpumpstate; const float channel0_base = 0.0739F; //Yellow const float channel1_base = 0.0739F; //Gray const float channel2_base = 0.1148F; // Blue const float channel3_base = 0.0792F; //Brown const float channel0_vrpm = 0.0097F; //Yellow const float channel1_vrpm = 0.0097F; //Gray const float channel2_vrpm = 0.0557F; // Blue const float channel3_vrpm = 0.0239F; //Brown const float strokevolume = 46.0F; const float waterdensity = 0.99823F; // tap water 20 C const float blooddensity = 1.06F; float density = 1.0F;
  • 9. double weight; char[] weightreq = new char[6]; //"*X01"; double minreslevel; double lowreslevel; Double curreslevel; double previousreslevel; double maxflowrate; int maxrpm; Boolean pumpon; double curflowrate; StreamWriter logfile; Stream logdata; double elapsedtime; Boolean recordon; NumberFormatInfo nfi; double monitortime; Queue reslevels; Bitmap greenuparrow, reddownarrow; SpVoice voice; SpeechVoiceSpeakFlags SpFlags = SpeechVoiceSpeakFlags.SVSFlagsAsync; int minpercentflow; } } namespace omega { class pioda { // return co public const int PIODA_NoError = 0; // ID public const int PIO_DA = 0x800400; // Driver functions [DllImport("PIODA.DLL")] static public extern ushort PIODA_DriverInit(); [DllImport("PIODA.DLL")] static public extern void PIODA_DriverClose(); [DllImport("PIODA.DLL")] static public unsafe extern ushort PIODA_SearchCard (ushort* wBoards, int dwPIOCardID); // DA functions [DllImport("PIODA.DLL")] static public extern ushort PIODA_Voltage (ushort wBoardNo, ushort wChannel, float fValue); [DllImport("PIODA.DLL")] static public extern ushort PIODA_Current (ushort wBoardNo, ushort wChannel, float fValue); [DllImport("PIODA.DLL")] static public extern ushort PIODA_CalVoltage (ushort wBoardNo, ushort wChannel, float fValue); [DllImport("PIODA.DLL")] static public extern ushort PIODA_CalCurrent (ushort wBoardNo, ushort wChannel, float fValue); } }