using System;
using System.Drawing;
using System.Windows.Forms;
using System.Globalization;
using CommandMessenger;
using ZedGraph;
namespace DataLogging
{
public partial class ChartForm : Form
{
// In a small C# application all code would typically end up in this class.
// For a cleaner, MVP-like setup I moved higher logic to TemperatureControl.cs,
private readonly TemperatureControl _temperatureControl;
private long _previousChartUpdate;
private IPointListEdit _analog1List;
private IPointListEdit _analog3List;
private GraphPane _temperaturePane;
private GraphPane _heaterPane;
private RollingPointPairList _heaterList;
private RollingPointPairList _heaterPwmList;
private bool _connected;
private double _goalTemperature;
public ChartForm()
{
InitializeComponent();
_temperatureControl = new TemperatureControl();
}
private void ChartFormShown(object sender, EventArgs e)
{
// Run setup of view model
_temperatureControl.Setup(this);
}
// ------------------ CHARTING ROUTINES ---------------------
/// Sets up the chart.
public void SetupChart()
{
MasterPane masterPane = chartControl.MasterPane;
masterPane.PaneList.Clear();
// get a reference to the GraphPane
_temperaturePane = new GraphPane(new Rectangle(5, 5, 890, 350),
"Temperature controller",
"Time (s)",
"Temperature (C)");
masterPane.Add(_temperaturePane);
// Create data arrays for rolling points
_analog1List = new RollingPointPairList(3000);
_analog3List = new RollingPointPairList(3000);
_analog1List.Clear();
_analog3List.Clear();
// Create a smoothened red curve for the current temperature
LineItem myCurve1 = _temperaturePane.AddCurve("Current temperature", _analog1List, Color.Red, SymbolType.None);
myCurve1.Line.Width = 2;
myCurve1.Line.IsSmooth = true;
myCurve1.Line.SmoothTension = 0.2f;
// Create a smoothened blue curve for the goal temperature
LineItem myCurve3 = _temperaturePane.AddCurve("Goal temperature", _analog3List, Color.Blue, SymbolType.None);
myCurve3.Line.Width = 2;
myCurve3.Line.IsSmooth = true;
myCurve3.Line.SmoothTension = 0.2f;
// Tell ZedGraph to re-calculate the axes since the data have changed
chartControl.AxisChange();
_heaterPane = new GraphPane(new Rectangle(5, 360, 890, 250),
null,
null,
null);
masterPane.Add(_heaterPane);
_heaterList = new RollingPointPairList(3000);
_heaterPwmList = new RollingPointPairList(3000);
_heaterList.Clear();
_heaterPwmList.Clear();
// Create a red curve for the heater value
LineItem heaterCurve = _heaterPane.AddCurve(null, _heaterList, Color.YellowGreen, SymbolType.None);
heaterCurve.Line.Width = 2;
heaterCurve.Line.IsSmooth = false;
// Create a red curve for the current heater pwm value
LineItem heaterPwmCurve = _heaterPane.AddCurve(null, _heaterPwmList, Color.Blue, SymbolType.None);
heaterPwmCurve.Line.Width = 2;
heaterPwmCurve.Line.IsSmooth = false;
SetChartScale(0);
}
// Update the graph with the data points
public void UpdateGraph(double time, double currTemp, double goalTemp, double heaterValue, bool heaterPwmValue)
{
// Add data points to the circular lists
_analog1List.Add(time, currTemp);
_analog3List.Add(time, goalTemp);
_heaterList.Add(time, heaterValue);
_heaterPwmList.Add(time, heaterPwmValue?1.05:0.05);
// Because updating the chart is computationally expensive if
// there are many data points, we do this only every 10 ms, that is 100 Hz
if (!TimeUtils.HasExpired(ref _previousChartUpdate, 10)) return;
//Console.WriteLine(@"Update chart");
SetChartScale(time);
}
// Update the graph with the data points
public void SetConnected()
{
_connected = true;
UpdateUi();
}
// Update the graph with the data points
public void SetDisConnected()
{
_connected = false;
UpdateUi();
}
/// Updates the user interface.
private void UpdateUi()
{
buttonStartAcquisition.Enabled = _connected;
buttonStopAcquisition.Enabled = _connected;
chartControl.Enabled = _connected;
GoalTemperatureTrackBar.Enabled = _connected;
GoalTemperatureValue.Enabled = _connected;
}
/// Sets the chart scale.
/// The time scale to show.
private void SetChartScale(double time)
{
// set window width
const double windowWidth = 30.0;
// get and update x-scale to scroll with data with an certain window
var xScaleTemp = _temperaturePane.XAxis.Scale;
if (time < windowWidth)
{
xScaleTemp.Max = windowWidth;
xScaleTemp.Min = 0;
}
else
{
xScaleTemp.Max = time + xScaleTemp.MajorStep;
xScaleTemp.Min = xScaleTemp.Max - windowWidth;
}
var xScaleHeater = _heaterPane.XAxis.Scale;
xScaleHeater.Max = xScaleTemp.Max;
xScaleHeater.Min = xScaleTemp.Min;
// Make sure the axes are rescaled to accommodate actual data
chartControl.AxisChange();
// Force a redraw
chartControl.Invalidate();
}
///
/// Clean up any resources being used.
///
/// true if managed resources should be disposed; otherwise, false.
protected override void Dispose(bool disposing)
{
if (disposing)
{
_temperatureControl.Exit();
if (components != null)
components.Dispose();
}
base.Dispose(disposing);
}
/// Update goal temperature as triggered by scrollbar.
/// Source of the event.
/// Event information.
public void GoalTemperatureTrackBarScroll(object sender, EventArgs e)
{
_goalTemperature = ((double)GoalTemperatureTrackBar.Value/10.0);
GoalTemperatureValue.Text = _goalTemperature.ToString(CultureInfo.InvariantCulture);
_temperatureControl.GoalTemperature = _goalTemperature;
}
/// Stop Acquisition.
/// Source of the event.
/// Event information.
private void ButtonStopAcquisitionClick(object sender, EventArgs e)
{
_temperatureControl.StopAcquisition();
}
/// Start Acquisition.
/// Source of the event.
/// Event information.
private void ButtonStartAcquisitionClick(object sender, EventArgs e)
{
_temperatureControl.StartAcquisition();
}
/// Update status bar.
/// The message to show on the status bar.
public void SetStatus(string description)
{
toolStripStatusLabel1.Text = description;
}
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void loggingView1_SelectedIndexChanged(object sender, EventArgs e)
{
}
public void LogMessage(string message)
{
loggingView1.AddEntry(message);
}
}
}