- /***********************************************************************************************
- * Main forms program for mannequin-DIS translator program.
- * Author: Josh Estes
- * Usage: read data from a mannequin, translate data to DIS format, broadcast DIS data to other
- * simulators on the network.
- **********************************************************************************************/
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Text;
- using System.Windows.Forms;
- using LaerdalSimulatorAPI;
- using System.Net;
- using System.Net.Sockets;
- using System.Threading;
- using System.Timers;
- namespace SimpleWinFormsDemo
- {
- public partial class MainForm : Form, INotifyPropertyChanged
- {
- // The object which will be used for communication with the manikin
- IManikin manikin;
- /// The event that happens each time a property changes
- public event PropertyChangedEventHandler PropertyChanged;
- // A manikin parameter which will represent the state of the pulse oximeter.
- IParameterAppValue<int> pulseOximeter;
- IParameterModelDouble heartRate;
- IParameterModelDouble overrideHeartRate;
- IParameterModelDouble PAPsystolic;
- IParameterModelDouble overridePAPSystolic;
- // Parameters used for pausing and starting the session
- IParameterAppEventBool pauseEvent;
- IParameterAppEventBool startEvent;
- //Timer parameterUpdateTimer;
- byte[] data, bytes;
- UdpClient server;
- IPEndPoint sender;
- // hasControl defines whether or not the simulation has control of the entity
- bool hasControl;
- // Starts the Reader program
- Reader readingObj;
- // Starts the Writer program
- Writer w;
- UInt32 request = 0;
- /********************************************************************************************
- * This method constructs the main window and initializes all of the gui components. It also
- * creates the UDP network and passes it on to the writer thread. So we can write from this
- * thread and the writer thread.
- ********************************************************************************************/
- public MainForm(IManikin manikin)
- {
- this.manikin = manikin;
- InitializeComponent();
- /***************************************************************************************
- * This values are the default values for the Low Fidelity Variable Paramter (VP)
- * record. All of these are enumerated lists. Below is the given all the options
- * and which is the initialized value.
- *
- * Weight by Age (weightList) is 3-bit enumeration with
- * Field Value Weight by Age
- * 0 Not Specified
- * 1 Underweight
- * 2 Normal *** Initial Value ***
- * 3 Overweight
- * 4 Obese
- * 5 Morbidly Obese
- * 6 Other
- **************************************************************************************/
- weightList.SelectedIndex = 2;
- /***************************************************************************************
- * Sex (sexList) is 2-bit enumeration with
- * Field Value Sex
- * 0 Not Specified
- * 1 Male *** Initial Value ***
- * 2 Female
- * 3 Indeterminate
- **************************************************************************************/
- sexList.SelectedIndex = 1;
- /***************************************************************************************
- * Consciousness (conList) is 3-bit enumeration with
- * Field Value Consciousness
- * 0 Not Specified
- * 1 Alert *** Initial Value ***
- * 2 Confused
- * 3 In-and-Out
- * 4 Unconscious
- **************************************************************************************/
- conList.SelectedIndex = 1;
- /***************************************************************************************
- * Chest Rise (chestList) is 2-bit enumeration with
- * Field Value Chest Rise
- * 0 Not Specified
- * 1 Normal *** Initial Value ***
- * 2 Paradoxical
- * 3 Labored
- **************************************************************************************/
- chestList.SelectedIndex = 1;
- /***************************************************************************************
- * Respirations (respList) is 3-bit enumeration with
- * Field Value Respirations
- * 0 Not Specified
- * 1 Normal *** Initial Value ***
- * 2 Slow
- * 3 Rapid
- * 4 Labored
- **************************************************************************************/
- respList.SelectedIndex = 1;
- /***************************************************************************************
- * Airway (airList) is 2-bit enumeration with
- * Field Value Airway
- * 0 Not Specified
- * 1 Open *** Initial Value ***
- * 2 Blocked
- **************************************************************************************/
- airList.SelectedIndex = 1;
- /***************************************************************************************
- * Pulse (PulseList) is 2-bit enumeration with
- * Field Value Pulse
- * 0 Not Specified
- * 1 Normal *** Initial Value ***
- * 2 Thready
- * 3 Fast
- **************************************************************************************/
- pulseList.SelectedIndex = 1;
- /***************************************************************************************
- * Heart Rate (hrList) is 3-bit enumeration with
- * Field Value Heart Rate
- * 0 Not Specified
- * 1 Normal *** Initial Value ***
- * 2 Faint
- * 3 Low
- * 4 High
- * 5 Very High
- **************************************************************************************/
- hrList.SelectedIndex = 1;
- /***************************************************************************************
- * Blood Pressure (bpList) is 3-bit enumeration with
- * Field Value Blood Pressure
- * 0 Not Specified
- * 1 Normal *** Initial Value ***
- * 2 Low
- * 3 Very Low
- * 4 High
- * 5 Very High
- * 6 Stroke
- **************************************************************************************/
- bpList.SelectedIndex = 1;
- /***************************************************************************************
- * Fluid (fluidList) is 2-bit enumeration with
- * Field Value Fluid
- * 0 Not Specified
- * 1 Normal *** Initial Value ***
- * 2 Low
- * 3 Very Low
- **************************************************************************************/
- fluidList.SelectedIndex = 1;
- /***************************************************************************************
- * O2 (Oxygen) Saturation (oxyLList) is 2-bit enumeration with
- * Field Value O2 Saturation
- * 0 Not Specified
- * 1 Normal *** Initial Value ***
- * 2 Low
- * 3 Very Low
- **************************************************************************************/
- oxyLList.SelectedIndex = 1;
- /***************************************************************************************
- * Train-of-Four (tofList) is 3-bit enumeration with
- * Field Value Train-of-Four
- * 0 Not Specified
- * 1 No Twitches *** Initial Value ***
- * 2 One Twitch
- * 3 Two Twitches
- * 4 Three Twitches
- * 5 Four Twitches
- **************************************************************************************/
- tofList.SelectedIndex = 0;
- // From the manikin, get the parameter representing the pulse oximeter
- pulseOximeter = manikin.GetParameterAppValue<int>("PulseOximeter");
- // From the manikin, get the parameter representing the heart rate
- heartRate = manikin.GetParameterModelDouble("heartRate");
- overrideHeartRate = manikin.GetParameterModelDouble("override HeartRate");
- heartRate.ValueChanged += new PropertyChangedEventHandler(OnHeartRateChanged);
- // heartRateLabel.DataBindings.Add("Text", this, "HeartRate");
- // Get the Pulmonary Arterial Pressure (Systolic) value from the manikin.
- PAPsystolic = manikin.GetParameterModelDouble("PAPSystolic");
- overridePAPSystolic = manikin.GetParameterModelDouble("override PAPSystolic");
- PAPsystolic.ValueChanged += new PropertyChangedEventHandler(OnPAPSystolicChanged);
- // The events that pauses and starts the simulation
- pauseEvent = manikin.GetParameterAppEventBool("Pause Simulation");
- startEvent = manikin.GetParameterAppEventBool("Start Simulation");
- // allocates new byte array of length 160
- bytes = new byte[160];
- //creates a new UDPClient, which can read and write on port 9050
- server = new UdpClient("255.255.255.255", 9050);
- // Creates new IPEndPoint
- sender = new IPEndPoint(IPAddress.Any, 0);
- hasControl = true;
- // Creates an instance of the Reader class and puts it in a thread.
- readingObj = new Reader(server, sender, this);
- Thread readerThread = new Thread(readingObj.DoWork);
- // Start the thread
- readerThread.Start();
- // Creates a new instance of Writer class.
- w = new Writer(server, bytes, this);
- }
- /// Gets/sets the heart rate from the Manikin
- public double HeartRate
- {
- get
- {
- return heartRate.Value;
- }
- set
- {
- overrideHeartRate.Value = value;
- if (PropertyChanged != null)
- PropertyChanged(this, new PropertyChangedEventArgs("HeartRate"));
- }
- }
- //Gets and sets Systolic Pulmonary Arterial Pressure from the Manikin
- public double PapSystolic
- {
- get
- {
- return PAPsystolic.Value;
- }
- set
- {
- overridePAPSystolic.Value = value;
- if (PropertyChanged != null)
- PropertyChanged(this, new PropertyChangedEventArgs("PapSystolic"));
- }
- }
- /// Happens when the main window is about to be closed
- protected override void OnClosing(CancelEventArgs e)
- {
- // When closing the connection should be terminated
- manikin.Disconnect();
- base.OnClosing(e);
- }
- /// Happens when the heart rate changes on the server. WHY TBD
- void OnHeartRateChanged(object obj, PropertyChangedEventArgs args)
- {
- if (PropertyChanged != null)
- PropertyChanged(this, new PropertyChangedEventArgs("HeartRate"));
- }
- // Calls an event when Pulmonary Arterial Pressure is changed
- void OnPAPSystolicChanged(object obj, PropertyChangedEventArgs args)
- {
- if (PropertyChanged != null)
- PropertyChanged(this, new PropertyChangedEventArgs("PapSystolic"));
- }
- // Used for GUI
- private void MainForm_Load(object sender, EventArgs e)
- {
- }
- /*****************************************************************************************
- * This method brings in a binary string called bin and the number of bits (called numBits)
- * the output should be. It takes the binary string, pads it with the appropriate number
- * of 0s and then returns the padded string in bin.
- ****************************************************************************************/
- private string format(string bin, int numBits)
- {
- string paddedBinString = "";
- if (bin.Length != numBits)
- {
- for (int i = 0; i < numBits - bin.Length; i++)
- {
- paddedBinString += "0";
- }
- return paddedBinString + bin;
- }
- else
- return bin;
- }
- // This method can be called from the writer class before it writes to make sure this simulation has control of the entity.
- public bool getHasControl()
- {
- return hasControl;
- }
- // Gets Heart Rate value from user and sets manikin
- private void setHR()
- {
- HeartRate = Convert.ToUInt16(heartRateBox.Text);
- }
- // Gets Pulmonary Arterial Pressure from user and sets manikin
- private void setPap()
- {
- PapSystolic = Convert.ToUInt16(spap.Text);
- }
- // TBD
- private void splitContainer1_Panel1_Paint(object sender, PaintEventArgs e)
- {
- }
- /****************************************************************************************
- * This method is called whenever the user chooses to update the variable parameter
- * (low fidelity) record. First, if there is a current writing thread active, it is
- * stopped, then data is compiled from the GUI, formed into a PDU and a new writing thread
- * is started with the new data.
- ****************************************************************************************/
- private void updateVp_Click(object sender, EventArgs e)
- {
- if (hasControl)
- {
- // Stop current writer thread
- w.requestStop();
- // data here is gathered from the drop down menus to populate the VP record
- // the method called format, takes in binary strings and returns the formatted string.
- /************************************************************************
- * The VP record first section is the record type of 63 hex or 99 dec
- ************************************************************************/
- /***************************************************************************************
- * Race is 4-bit enumeration with
- * Field Value Race
- * 0 Not Specified
- * 1 TBD *** Initial Value ***
- * 2 Other
- **************************************************************************************/
- /***************************************************************************************
- * Species is 4-bit enumeration with
- * Field Value Species
- * 0 Not Specified
- * 1 TBD *** Initial Value ***
- * 2 Other
- **************************************************************************************/
- /***************************************************************************************
- * Breed is 4-bit enumeration with
- * Field Value Breed
- * 0 Not Specified
- * 1 TBD *** Initial Value ***
- * 2 Other
- **************************************************************************************/
- /************************************************************************
- * The second section is Patient Basic Attribute with
- * Variable Race = Race & Species values together are 11 hex or 17 dec
- * Variable wt for Weight by Age
- * Breed - TBD - should be 1 for TBD?
- * Variable Sex = Sex
- ************************************************************************/
- byte[] basic = new byte[3];
- byte race = 17;
- /***************************************************************************************
- * Clinical Event/ Observation is 3-bit enumeration with
- * Field Value Clinical Event/ Observation
- * 0 Not Specified
- * 1 None *** Initial Value ***
- * 2 Blunt Trauma
- * 3 Penetrating Trauma
- * 4 Burn, Amputation
- * 5 Chemical Trauma
- * 6 Biological Traum
- * 7 Other
- **************************************************************************************/
- /***************************************************************************************
- * Location On Body 1 is 3-bit enumeration with
- * Field Value Location On Body 1
- * 0 Not Specified *** Initial Value ***
- * 1 Head and Neck
- * 2 Face
- * 3 Chest
- * 4 Abdomen
- * 5 Extremities
- * 6 External
- * 7 Other
- **************************************************************************************/
- /***************************************************************************************
- * Location On Body 2 is 2-bit enumeration with
- * Field Value Location On Body 2
- * 0 Not Specified *** Initial Value ***
- * 1 Right
- * 2 Left
- * 3 Other
- **************************************************************************************/
- /***************************************************************************************
- * Location On Body 3 is 2-bit enumeration with
- * Field Value Location On Body 3
- * 0 Not Specified *** Initial Value ***
- * 1 Proximal
- * 2 Distal
- * 3 Other
- **************************************************************************************/
- /***************************************************************************************
- * Location On Body 4 is 3-bit enumeration with
- * Field Value Location On Body 4
- * 0 Not Specified *** Initial Value ***
- * 1 Front
- * 2 Back
- * 3 Other
- **************************************************************************************/
- /***************************************************************************************
- * Bleeding is 2-bit enumeration with
- * Field Value Bleeding
- * 0 Not Specified *** Initial Value ***
- * 1 Artenial
- * 2 Venial
- * 3 None
- **************************************************************************************/
- /***************************************************************************************
- * Skin is 2-bit enumeration with
- * Field Value Skin
- * 0 Not Specified
- * 1 Normal *** Initial Value ***
- * 2 Clammy
- * 3 Cold
- **************************************************************************************/
- /************************************************************************
- * The VP record 3th section is the Patient Visual Event Details
- * The section uses the following values
- * Variable obs = Clinical Event/ Observation, Location On Body 1 & 2
- * which together are 20 hex or 32 dec
- * Variable loc = Location On Body 3, 4, & 5, Bleeding which together
- * are 3 hex or 3 dec
- * Variable skin = Skin which is 1
- * The four byte is Padding with value of zero
- ************************************************************************/
- byte[] visEvent = new byte[4];
- byte obs = 32, loc = 3, skin = 1;
- visEvent[0] = obs; visEvent[1] = loc; visEvent[2] = skin; visEvent[3] = 0;
- /***************************************************************************************
- * Intervention Name is 4-bit enumeration with
- * Field Value Intervention Name
- * 0 Not Specified
- * 1 TBD
- * 2 None *** Initial Value ***
- **************************************************************************************/
- /***************************************************************************************
- * Medication is 4-bit enumeration with
- * Field Value Medication
- * 0 Not Specified
- * 1 None *** Initial Value ***
- * 2 Antibiotic
- * 3 Pain
- * 4 Fluid
- * 5 Blood
- * 6 ACLS Drawer
- * 7 Anesthetic
- * 8 Other
- **************************************************************************************/
- /***************************************************************************************
- * Dose is 2-bit enumeration with
- * Field Value Dose
- * 0 Not Specified
- * 1 None *** Initial Value ***
- * 2 TBD
- **************************************************************************************/
- /***************************************************************************************
- * Route is 2-bit enumeration with
- * Field Value Route
- * 0 Not Specified
- * 1 None *** Initial Value ***
- * 2 TBD
- **************************************************************************************/
- /***************************************************************************************
- * Frequency is 3-bit enumeration with
- * Field Value Frequency
- * 0 Not Specified
- * 1 None *** Initial Value ***
- * 2 TBD
- **************************************************************************************/
- /***************************************************************************************
- * Appropriateness is 1-bit enumeration with
- * Field Value Appropriateness
- * 0 Not Specified *** Initial Value ***
- * 1 TBD
- **************************************************************************************/
- /***************************************************************************************
- * Effectiveness is 2-bit enumeration with
- * Field Value Effectiveness
- * 0 Not Specified
- * 1 None *** Initial Value ***
- * 2 TBD
- **************************************************************************************/
- /************************************************************************
- * The VP record 5th section is the Intervention Details
- * The section uses the following values
- * Variable intName = Intervention name and Medication values which
- * together are 21 hex or 33 dec
- * Variable dose = Dose, Route, Frequency, & Appropriateness which
- * together together are 54 hex or 84 dec
- * Variable effect = Effectiveness which is 1
- * The four byte is Padding with value of zero
- ************************************************************************/
- byte[] inter = new byte[4];
- byte intName = 33, dose = 84, effect = 1;
- inter[0] = intName; inter[1] = dose; inter[2] = effect; inter[3] = 0;
- /************************************************************************
- * The VP record 4th section is the Patient Physiology Detail
- * This section uses values from the User and Manikin
- * This code combines these variable for the record
- ************************************************************************/
- byte[] phys = new byte[4];
- string gen = format(Convert.ToString(sexList.SelectedIndex, 2), 2);
- string weigh = format(Convert.ToString(weightList.SelectedIndex, 2), 3);
- string con = format(Convert.ToString(conList.SelectedIndex, 2), 3);
- string c = format(Convert.ToString(chestList.SelectedIndex, 2), 2);
- string r = format(Convert.ToString(respList.SelectedIndex, 2), 3);
- string a = format(Convert.ToString(airList.SelectedIndex, 2), 3);
- string p = format(Convert.ToString(pulseList.SelectedIndex, 2), 2);
- string h = format(Convert.ToString(hrList.SelectedIndex, 2), 3);
- string b = format(Convert.ToString(bpList.SelectedIndex, 2), 4);
- string l = format(Convert.ToString(fluidList.SelectedIndex, 2), 2);
- string o = format(Convert.ToString(oxyLList.SelectedIndex, 2), 2);
- string t = format(Convert.ToString(tofList.SelectedIndex, 2), 8);
- weigh = "00001" + weigh;
- gen = "000000" + gen;
- con += (c + r);
- a += (p + h);
- b += (l + o);
- byte wt = Convert.ToByte(weigh, 2);
- byte sex = Convert.ToByte(gen, 2);
- byte cons = Convert.ToByte(con, 2);
- byte airway = Convert.ToByte(a, 2);
- byte blood = Convert.ToByte(b, 2);
- byte trainFour = Convert.ToByte(t, 2);
- basic[0] = race;
- basic[1] = wt;
- basic[2] = sex;
- phys[0] = cons;
- phys[1] = airway;
- phys[2] = blood;
- phys[3] = trainFour;
- // PDU Type is 1 because this is an entity state PDU
- byte pduType = 1;
- //new entity state PDU is created
- EntityState es = new EntityState(basic, visEvent, phys, inter, pduType);
- data = es.createPDU();
- //new writer thread is created
- w = new Writer(server, data, this);
- Thread writerThread = new Thread(w.DoWork);
- writerThread.Start();
- }
- else
- {
- Console.WriteLine("Simulation does not have control of entity.");
- }
- }
- /****************************************************************************************************
- * This method is called when the user choses a transfer control request.
- ***************************************************************************************************/
- private void button1_Click(object sender, EventArgs e)
- {
- request++;
- byte tType = 1;
- // A new Transfer control request PDU is created
- TransferControlReq t = new TransferControlReq(request, tType);
- byte[] tcr = t.createTCR();
- server.Send(tcr, tcr.Length);
- for (int i = 0; i < 5; i++)
- {
- // Check for ack every 1 second for 5 seconds.
- Thread.Sleep(1000);
- // Check to see if reader received acknowledgment
- if (readingObj.getGotAck())
- {
- hasControl = false;
- readingObj.setGotAck(true);
- break;
- }
- }
- }
- // Will be used for Transfer Control (push)
- private void button3_Click(object sender, EventArgs e)
- {
- }
- /********************************************************************************************
- * This method is called when the "update high fidelity" button is clicked on the main GUI.
- * Here, we take all the data from the high fidelity parameters and use classes to turn it in
- * to a DIS Attribute Record. We then send it directly from this method, as opposed to using
- * the writer class.
- ********************************************************************************************/
- private void updateAr_Click(object sender, EventArgs e)
- {
- heartRateBox.Text = Convert.ToString(HeartRate);
- spap.Text = Convert.ToString(PapSystolic);
- //Creates a new General Physical Record using values from main GUI, the record
- //is then stored in a byte array
- PhysRecord gen = new PhysRecord(Convert.ToUInt16(heightBox.Text), Convert.ToUInt16(weightBox.Text), Convert.ToUInt16(ageBox.Text));
- byte[] general = gen.createPhysRecord();
- //This line creates a new Cardio object, it converts the text in the cardio boxes to an int, byte or float.
- Cardio card = new Cardio(Convert.ToUInt16(asbp.Text), Convert.ToUInt16(adbp.Text), Convert.ToUInt16(mabp.Text),
- Convert.ToUInt16(nsbp.Text), Convert.ToUInt16(ndbp.Text), Convert.ToUInt16(mnbp.Text),
- Convert.ToSingle(temp.Text), Convert.ToSingle(ph.Text), Convert.ToUInt16(heartRateBox.Text),
- Convert.ToUInt16(co.Text), Convert.ToByte(hematocrit.Text), Convert.ToByte(pos.Text),
- Convert.ToByte(cvp.Text));
- //This line creates a new cardio record
- byte[] cardio = card.createCardio();
- //This line takes the text from the respiratory boxes and passes it to the Respiratory class to make a new object
- Respiratory resp = new Respiratory(Convert.ToUInt16(aot.Text), Convert.ToUInt16(alot.Text), Convert.ToSingle(stv.Text),
- Convert.ToSingle(tlv.Text), Convert.ToByte(rr.Text), Convert.ToByte(acdt.Text),
- Convert.ToByte(alcdt.Text), Convert.ToByte(spap.Text), Convert.ToByte(dpap.Text),
- Convert.ToByte(mpap.Text), Convert.ToByte(pcwp.Text), Convert.ToByte(ervp.Text),
- Convert.ToByte(srvp.Text));
- //This line creates a new repiratory record
- byte[] respiratory = resp.createRespiratory();
- //The following lines pass the general, repiratory, and cardio records and use them to create an attribute PDU
- Attribute att = new Attribute(general, cardio, respiratory);
- byte[] attribute = att.createAttribute();
- //The following 2 lines send the Attribute PDU in its entirity along the network.
- server.EnableBroadcast = true;
- server.Send(attribute, attribute.Length);
- setHR();
- setPap();
- Console.WriteLine("sent attribute");
- }
- }
- }