예제 #1
0
        private void Form1_Load(object sender, EventArgs e)
        {
            // mostly just initialization is happening here in form_load

            log_to_file_now = false;

            m_pSerialPort = new SerialPort();
            m_pSerialPort.DataReceived += new SerialDataReceivedEventHandler(m_pSerialPort_DataReceived);
            foreach (string port in System.IO.Ports.SerialPort.GetPortNames())
            {
                cbPort.Items.Add(port);
            }

            // select default UI items
            cbParity.SelectedIndex = 0;
            cbStopBits.SelectedIndex = 0;
            cbDataBits.SelectedIndex = 0;
            cbPort.SelectedIndex = 0;
            cbBaudRate.Text = "9600";
            cbPollDelay.SelectedText = DEFAULT_POLL_TIME_IN_MS.ToString();
            cbPollTimeFormat.SelectedIndex = 0;
            // default polling time delay
            poll_time_in_ms = DEFAULT_POLL_TIME_IN_MS;
            // background var for the channel
            //current_channel = channel_sel.undefined;

            // make sure the right things are disabled and enabled
            change_ui_to_disconnected();

            // the lock to synchronize cross thread communications
            monitor_lock = new object();

            thready = new Thread(new ThreadStart(thread_invoke));
            thready.Name = "th";
            thready.IsBackground = true;
            thready.Start();

            progress_bar_tick = new System.Threading.Timer(progress_bar_tick_run, null, 0, 100);

            // serial buffer
            received_buffer = new char[1024];

            // semaphore is owned by parent
            safe_to_access_buffer = new Semaphore(0, 1);
            safe_to_access_status = new Semaphore(0, 1);
            // allow anyone access to the semaphore
            safe_to_access_buffer.Release();
            safe_to_access_status.Release();

            safe_to_access_status.WaitOne();
            current_status = connection_status.unconnected;
            safe_to_access_status.Release();

            clear_buffer();

            pbPollCountdown.Value = 100;
        }
예제 #2
0
        // will change the output of the power supply
        // 0=off
        // 1=on
        private void change_output(int state)
        {
            if (state != 0 && state != 1)
            {
                Console.WriteLine("Attempting to change to unknown state! (value={0})", state.ToString());
                return;
            }

            connection_status t = pause_polling_thread();

            thread_safe_update_status_bar("Changing output.");

            // send the change output to x command
            string s = "";
            s = quick_clear_write_read("OUTP:STAT " + (state == 0 ? "OFF" : "ON") + "\n");

            current_status = t;

            if (state == 0)
            {
                ui_to_output_off();

                // stop the polling thread (pulse below)
                safe_to_access_status.WaitOne();
                current_status = connection_status.connected;
                safe_to_access_status.Release();
            }
            else if (state == 1)
            {
                ui_to_output_on();

                // resume the polling thread
                safe_to_access_status.WaitOne();
                current_status = connection_status.identified;
                safe_to_access_status.Release();
            }
            else
            {
                ui_to_output_undefined();
            }

            // clear existing output
            // the limits, current channel, and ovp can stay
            thread_safe_current_text_update(UNKNOWN_CURRENT_TEXT);
            thread_safe_voltage_text_update(UNKNOWN_VOLTAGE_TEXT);
            thread_safe_power_text_update(UNKNOWN_POWER_TEXT);

            resume_polling_thread(t);
        }
예제 #3
0
        private string connection_status_to_string(connection_status c)
        {
            switch (c)
            {
                case connection_status.connected: return "connected";
                case connection_status.done: return "done";
                case connection_status.identified: return "identified";
                case connection_status.polling: return "polling";
                case connection_status.unconnected: return "unconnected";

                case connection_status.undefined:
                default:
                    return "undefined";
            }
        }
예제 #4
0
        // changes state from connected to ID'd, will start polling continuously on success
        private void btnIdentify_Click(object sender, EventArgs e)
        {
            // return if not connected
            if (btnConnect.Enabled == true)
                return;

            // going to do a couple things before letting the user proceed,
            // but all of these checks need to be successful
            int init_device = 0;

            init_device = quick_identify();
            if (init_device <= 0)
            {
                return;
            }

            // failing a limit read isn't fatal, so the return value can be ignored
            quick_limit_read();

            // failling to identify the current channel is not fatal, so the return value can be ignored
            quick_channel_read();

            // failing to read the over voltage protection value is not fatal, so the return value can be ignored
            quick_ovp_read();

            // If the output is currently off, there's no need to start the polling thread yet
            int output = quick_output_onoff_read();
            btnStopStart.Text = (output==0?"Start":"Stop");

            // now that the device is known, list the available power modes
            populate_modes(); // adds available items
            quick_power_mode_read(); // reads current power mode and selects it in the combo box

            // and update the max values in the 'set' boxes
            update_max_values();

            // start the polling if things are good to go
            if (init_device > 0 && output == 1)
            {
                safe_to_access_status.WaitOne();
                current_status = connection_status.identified;
                safe_to_access_status.Release();

                lock (monitor_lock)
                {
                    Monitor.Pulse(monitor_lock);
                }
            }
            else
            {
                safe_to_access_status.WaitOne();
                current_status = connection_status.undefined;
                safe_to_access_status.Release();
            }

            return;
        }
예제 #5
0
        private void btnStopStart_Click(object sender, EventArgs e)
        {
            UInt64 i = lock_connected_ui();

            // the thread is running and needs to be stopped
            if (btnStopStart.Text == "Stop")
            {

                thread_safe_update_status_bar("Stopping pending communications.");

                // first, stop the polling thread
                lock (monitor_lock)
                {
                    // attempt to wait, but if it's already stopped, then timeout
                    if (current_status == connection_status.polling)
                    {
                        Monitor.Wait(monitor_lock);

                        // wait for any pending commands to finish
                        Thread.Sleep(THREAD_AFTER_INTERRUPT_WAIT);

                    }
                    else
                        Monitor.Wait(monitor_lock, THREAD_WAIT_TIMEOUT);

                    safe_to_access_status.WaitOne();
                    current_status = connection_status.connected;
                    safe_to_access_status.Release();
                }
                thread_safe_update_status_bar("Ready.");
                btnStopStart.Text = "Start";
            }
            // the thread is stopped and needs to be resumed
            else if (btnStopStart.Text == "Start")
            {
                lock (monitor_lock)
                {
                    safe_to_access_status.WaitOne();
                    current_status = connection_status.identified;
                    safe_to_access_status.Release();

                    Monitor.Pulse(monitor_lock);

                }
                btnStopStart.Text = "Stop";
            }

            unlock_connected_ui(i);
        }
예제 #6
0
        // this is the main part of the application, and it happens mostly in the background.
        // after connecting, the device needs to be ID'd. After that succeeds, polling will
        // commence to continuously retrieve the current and voltage values. The user can
        // choose to "start logging" which will save these polled values to a file in realtime;
        // no values are stored for playback or anything.
        void thread_invoke()
        {
            int ok_to_go = 0;
            int do_it_twice = 0;
            double volt;
            double curr;
            bool monitor_response = true;

            // run this thread until the program ends
            while (true)
            {
                // wait for a device to be found...
                ok_to_go = 0;

                lock (monitor_lock)
                {
                    while (ok_to_go == 0)
                    {
                        //Console.WriteLine("Checking current_status...");

                        if (current_status == connection_status.polling)
                        {
                            //Console.WriteLine("current_status=polling");
                            ok_to_go = 1;

                            // true on interrupt, false on timeout
                            if (poll_time_in_ms - SERIAL_RESPONSE_WAIT_TIME > 10)
                                monitor_response = Monitor.Wait(monitor_lock, poll_time_in_ms - SERIAL_RESPONSE_WAIT_TIME);
                            else
                                monitor_response = Monitor.Wait(monitor_lock, poll_time_in_ms);
                        }
                        else if (current_status == connection_status.identified)
                        {
                            //Console.WriteLine("current_status=identified");
                            // if it's identified, we're about to begin polling
                            safe_to_access_status.WaitOne();
                            current_status = connection_status.polling;
                            safe_to_access_status.Release();

                            // true on interrupt, false on timeout
                            if (poll_time_in_ms - SERIAL_RESPONSE_WAIT_TIME > 10)
                                monitor_response = Monitor.Wait(monitor_lock, poll_time_in_ms - SERIAL_RESPONSE_WAIT_TIME);
                            else
                                monitor_response = Monitor.Wait(monitor_lock, poll_time_in_ms);
                        }
                        else
                        {
                            //Console.WriteLine("current_status=else");
                            // all other cases need to pause this thread indefinitely
                            ok_to_go = 0;

                            Monitor.Wait(monitor_lock);
                            monitor_response = false;
                        }

                        // if this was woken up early, then actually don't do anything
                        if (monitor_response == true)
                        {
                            ok_to_go = 0;
                        }

                        // it's possible that the status changed while inside Monitor.Wait, so make
                        // sure that this thread is still polling
                        safe_to_access_status.WaitOne();
                        if (current_status != connection_status.polling)
                        {
                            ok_to_go = 0;
                        }
                        safe_to_access_status.Release();
                    }
                }

                //Console.WriteLine("Done with lock -- ok_to_go={0}, monitor_response={1}, current_status={2}", ok_to_go, (monitor_response ? "true" : "false"), connection_status_to_string(current_status));

                volt = 0.0;
                curr = 0.0;

                // the voltage and current code are practically the same, so those two
                // are going to be done in a loop. The first time is current, the second
                // is voltage

                clear_buffer();

                //Console.WriteLine("Sending curr/volt command.");

                // disconnecting at the wrong time can cause this thread to
                // attempt to write to a com port that doesn't exist
                try
                {
                    if (do_it_twice == 0)
                    {
                        m_pSerialPort.Write("MEAS:CURR?\n");
                    }
                    else if (do_it_twice == 1)
                    {
                        m_pSerialPort.Write("MEAS:VOLT?\n");
                    }
                }
                catch
                {
                }

                // wait for a response from the device. This can probably be fine tuned a little
                // based on the baud rate and other factors.
                Thread.Sleep(SERIAL_RESPONSE_WAIT_TIME);

                // received buffer is filled in the event handler for the serial port device
                string s;
                safe_to_access_buffer.WaitOne();
                int len = 0;
                while (received_buffer[len] != '\0')
                    len++;
                s = new string(received_buffer, 0, len);
                safe_to_access_buffer.Release();

                // the response is going to be a number in scientific notation
                double d = new double();
                try
                {
                    d = double.Parse(s);
                }
                catch
                {
                    d = double.NaN;
                    if (ckBaudErrorFix.Checked == true)
                    {
                        // scale the error correcting time based on the baud rate.
                        // lower bauds have to move in larger amounts than higher baud rates
                        int baud = thread_safe_get_baud_rate();
                        if (baud == 0)
                            baud = 1;
                        int move_factor = (int)(336000/baud);
                        if (move_factor == 0)
                            move_factor = 1;

                        poll_time_in_ms += move_factor;
                        thread_safe_poll_delay_text_update(poll_time_in_ms.ToString());
                        // static wait period. The power supply needs some time to recover
                        Thread.Sleep(250);
                    }
                }

                // update the UI, and set the current and voltage values that will
                // be written to the log file.

                if (do_it_twice == 0 && current_status == connection_status.polling)
                {
                    curr = d;
                    Console.WriteLine("received current response: {0}", d);
                    if (System.Double.IsNaN(d))
                    {
                        thread_safe_current_text_update(UNKNOWN_CURRENT_TEXT);
                    }
                    else
                    {
                        thread_safe_current_text_update(d.ToString(CURRENT_TEXT_FORMAT));
                    }
                }
                else if (do_it_twice == 1 && current_status == connection_status.polling)
                {
                    volt = d;
                    Console.WriteLine("received voltage response: {0}", d);
                    if (System.Double.IsNaN(d))
                    {
                        thread_safe_voltage_text_update(UNKNOWN_VOLTAGE_TEXT);
                    }
                    else
                    {
                        thread_safe_voltage_text_update(d.ToString(VOLTAGE_TEXT_FORMAT));
                    }
                }

                do_it_twice++;
                if (do_it_twice == 2)
                    do_it_twice = 0;

                // update power usage
                if (!Double.IsNaN(curr) && !Double.IsNaN(volt) && current_status == connection_status.polling)
                {
                    thread_safe_power_text_update((curr * volt).ToString(POWER_TEXT_FORMAT));
                }
                else
                {
                    thread_safe_power_text_update(UNKNOWN_POWER_TEXT);
                }

                // done with both voltage and current
                // check to see if they need to be saved to a file
                if (log_to_file_now == true)
                {
                    StringBuilder sb = new StringBuilder();
                    sb.Append(DateTime.Now.ToString());
                    sb.Append(", ");
                    sb.Append(volt.ToString());
                    sb.Append(", ");
                    sb.AppendLine(curr.ToString());

                    byte[] ba = Encoding.ASCII.GetBytes(sb.ToString());
                    file_to_save_to.Write(ba, 0, ba.Length);
                }

                // if someone else is trying to halt this thread, allow that to happen now.
                lock (monitor_lock)
                {
                    //Console.WriteLine("pulsing monitor_lock. (end of main loop)");
                    Monitor.Pulse(monitor_lock);
                }

                // also, attempt to re-sync the status bar
                pbPollCountdown.BeginInvoke((ThreadStart)delegate
                {
                    lock (pbPollCountdown)
                    {
                        pbPollCountdown.Value = 0;
                    }
                });

            } // end of while(true)
        }
예제 #7
0
        /// <summary>
        /// Happens when the disconnect button is clicked to disconnect
        /// the serial port from the device.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnDisconnect_Click(object sender, EventArgs e)
        {
            safe_to_access_status.WaitOne();
            current_status = connection_status.unconnected;
            safe_to_access_status.Release();

            btnDisconnect.Enabled = false;
            btnConnect.Enabled = true;
            status_bar.Text = "Disconnected";

            // wait just a bit to see if any current communications will finish
            Thread.Sleep(300);

            // I believe closing the port will always trigger an error
            m_pSerialPort.Close();

            change_ui_to_disconnected();
        }
예제 #8
0
        private void resume_polling_thread(connection_status c)
        {
            //  don't let the polling thread read in the response from the previous commands
            clear_buffer();

            // release the polling thread, if it was stopped earlier
            lock (monitor_lock)
            {
                safe_to_access_status.WaitOne();
                current_status = c;
                safe_to_access_status.Release();

                //Console.WriteLine("Resuming polling thread, status={0}", connection_status_to_string(c));

                if (current_status == connection_status.polling)
                    Monitor.Pulse(monitor_lock);
            }

            thread_safe_update_status_bar("Ready");
        }
예제 #9
0
        private void btnConnect_Click(object sender, EventArgs e)
        {
            try
            {
                #region Set Serial Settings

                m_pSerialPort.BaudRate = Convert.ToInt32(cbBaudRate.Text);
                m_pSerialPort.DataBits = Convert.ToInt32(cbDataBits.Text);
                switch (cbParity.Text)
                {
                    case "None": m_pSerialPort.Parity = Parity.None; break;
                    case "Odd": m_pSerialPort.Parity = Parity.Odd; break;
                    case "Even": m_pSerialPort.Parity = Parity.Even; break;
                    default:
                        break;
                }
                switch (cbStopBits.Text)
                {
                    case "1": m_pSerialPort.StopBits = StopBits.One; break;
                    case "2": m_pSerialPort.StopBits = StopBits.Two; break;
                    default:
                        break;
                }
                m_pSerialPort.PortName = cbPort.Text;

                m_pSerialPort.DtrEnable = true;
                m_pSerialPort.RtsEnable = true;

                #endregion

                m_pSerialPort.Open();

                status_bar.Text = "Connected to " + m_pSerialPort.PortName.ToString() + " at " + m_pSerialPort.BaudRate.ToString();
                btnConnect.Enabled = false;
                btnDisconnect.Enabled = true;

                safe_to_access_status.WaitOne();
                current_status = connection_status.connected;
                safe_to_access_status.Release();

                change_ui_to_connected();

            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message, "COM Port Connection Problem");
                safe_to_access_status.WaitOne();
                current_status = connection_status.unconnected;
                safe_to_access_status.Release();
                return;
            }
        }
예제 #10
0
        private int quick_identify()
        {
            int ret_val = 0;
            try
            {
                string s = quick_clear_write_read("*IDN?\n");

                // check to make sure this is [probably] the power supply device
                if (s.IndexOf("Agilent Technologies") >= 0)
                {
                    current_device = s;

                    if (s.Length > 3)
                        s = s.Substring(0, s.Length - 2);

                    status_bar.Text = "Found device: " + s;

                    // don't enable logging until a device is found
                    change_ui_to_identified();

                    ret_val = 1;
                }
                else
                {
                    current_device = "";

                    ret_val = -1;
                }
            }
            catch
            {
                MessageBox.Show("Something went wrong getting device id");
                safe_to_access_status.WaitOne();
                current_status = connection_status.undefined;
                safe_to_access_status.Release();

                ret_val = -2;
            }

            return ret_val;
        }
예제 #11
0
        private connection_status pause_polling_thread()
        {
            thread_safe_update_status_bar("Stopping pending communications.");

            connection_status t = connection_status.undefined;

            // first, stop the polling thread
            lock (monitor_lock)
            {
                // attempt to wait, but if it's already stopped, then timeout
                if (current_status == connection_status.polling)
                {
                    Monitor.Wait(monitor_lock);

                    // wait for any pending commands to finish
                    Thread.Sleep(THREAD_AFTER_INTERRUPT_WAIT);

                    //Console.WriteLine("pausing polling thread (connection_status=polling)");
                    t = connection_status.polling;
                }
                else
                {
                    Monitor.Wait(monitor_lock, THREAD_WAIT_TIMEOUT);
                    safe_to_access_status.WaitOne();
                    t = current_status;
                    safe_to_access_status.Release();
                    //Console.WriteLine("pausing polling thread (connection_status={0})", connection_status_to_string(t));
                }

                safe_to_access_status.WaitOne();
                current_status = connection_status.unconnected;
                safe_to_access_status.Release();
            }

            return t;
        }
예제 #12
0
 public void SetPlayerConnection(int ID, connection_status status)
 {
     ID--;
     PlayerInfos[ID].status = status;
 }