Serial Port In C# - c#

I am working with a program the reads data from a file and plots it to a graph in real time. My stream is coming from a microcontroller output and I am building an interface to display the data. I am using stream reader in my routine, but I have a problem.
I have decided to use the data from the serial port directly. I get an error when I try to use the variable line that I have just read from the port. I do not know what I am doing wrong.
Thanks.
int tickStart = 0;
System.IO.Ports.SerialPort port;
public string portname;
public Parity parity;
public int BaudRate;
public StopBits stopbits;
public int databits;
int count;
String line;
public string PortName
{
get { return portname; }
set { portname = value; }
}
private void Form1_Load( object sender, EventArgs e )
{
//graphing stuff
count = 0;
portname = "COM1";
parity = Parity.None;
BaudRate = 9600;
stopbits = StopBits.Two;
databits = 8;
port = new System.IO.Ports.SerialPort(portname);
port.Parity = parity;
port.BaudRate = BaudRate;
port.StopBits = stopbits;
port.DataBits = databits;
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
port.Open();
count = 0;
}
void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
line = port.ReadLine();
count++;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void timer1_Tick( object sender, EventArgs e )
{
//graphing stuff
if (list == null)
return;
// Time is measured in seconds
double time = (Environment.TickCount - tickStart) / 1000.0;
double value = double.Parse(line);
list.Add(time, value);
//graphing stuff
}

in timer1_Tick, add an additional check for 'line == null', in addition to 'list == null'.
Assuming that your data comes in no more often than the firing rate of your timer, and, that the data received arrives all in one burst.

If I understand correctly, what happens is that the timer ticks before a value has been read from the port for the first time. This means that line == null still, so you get the error.
The best solution would be to not start the timer before at least one line is read, but checking for null would also do the trick.

Related

I have 2 different form applications. I'm trying to pull data from one to the other but I'm getting an error. Can you help me? [duplicate]

This question already has an answer here:
What is an "index out of range" exception, and how do I fix it? [duplicate]
(1 answer)
Closed 1 year ago.
I have one scale app. I want to pass the value to another form place but I am getting an error. I just graduated, I don't know much, unfortunately, can you help me?
My weighing app:
namespace Tartı
{
public partial class Tarti : Form
{
public SerialPort _serialPort = null;
public Tarti()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
_serialPort = new SerialPort("COM4", 9600, Parity.None, 8);
_serialPort.StopBits = StopBits.One;
_serialPort.ReadTimeout = 1000;
_serialPort.DataReceived += new SerialDataReceivedEventHandler(_serialPort_DataReceived);
_serialPort.Open();
}
public string weight = "";
private delegate void Closure();
private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int dataLength = _serialPort.BytesToRead;
byte[] data = new byte[dataLength];
int nbrDataRead = _serialPort.Read(data, 0, dataLength);
if (nbrDataRead == 0)
return;
string str = System.Text.Encoding.UTF8.GetString(data);
double number;
if (Double.TryParse(str, out number))
{
txtWeight.Text = string.Format("{0:0.000}", str);
}
else
{
var doubleArray = Regex.Split(str, #"[^0-9\.]+")
.Where(c => c != "." && c.Trim() != "");
string[] str1 = ((System.Collections.IEnumerable)doubleArray)
.Cast<object>()
.Select(x => x.ToString())
.ToArray();
if (str1 != null && str1.Length > 0)
{
txtWeight.Text = string.Format("{0:0.000}", str1[0]);
txtWeight.ForeColor = Color.Red;
weight = txtWeight.Text;
_serialPort.Close();
}
}
}
private void Tarti_Load(object sender, EventArgs e)
{
}
private void timer1_Tick(object sender, EventArgs e)
{
}
}
}
Other form application data needs to come to this application:
private void AgirlikAl_Click(object sender, EventArgs e)
{
Tarti v = new Tarti();
v.Hide();
string a = v.weight;
string[] split = a.Split('.');
PackingReal.Text = split[0].ToString();
PackingDecimal.Text = split[1].ToString();
}
It gives the following message as an error:
Additional information: Index was outside the bounds of the array. How can i fix this?
Check your "weight" varible value, it comes allways string.Empty, becouse you are creating always new instance of Tarti class(form) here:
Tarti v = new Tarti();
v.Hide();
string a = v.weight;
string[] split = a.Split('.'); - array elements count in this case - zero, for this you are getting "Index was outside the bounds of the array" error

Trying to set variable in the UI-Thread

I use this code to read from a weighting scale, I successfully read weight value from it but when trying to set the variable hex = "" for the next weight value I can't get it in the textbox, it appears very quickly and then disappears again, if I trace the program with the hex = "" enabled the results are as expected, but if run the program without trace it, then the blinking with the values and the textbox gets empty :( any ideas
string hex = "";
private delegate void Closure();
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
{
if (InvokeRequired)
{
BeginInvoke(new Closure(() => { SerialPortOnDataReceived(sender, serialDataReceivedEventArgs); }));
}
else
{
if (_serialPort.BytesToRead > 0)
{
//hex = ""; <- Without this different weight values appears one after another. If applied then happens what explained above.
while (_serialPort.BytesToRead > 0) //<-- repeats until the In-Buffer is empty
{
hex += string.Format("{0:X2} ", _serialPort.ReadByte());
}
byte[] data = FromHex(hex.Trim());
textBox1.Text = Encoding.ASCII.GetString(data).Trim();
}
}
}
public byte[] FromHex(string aHex)
{
aHex = aHex.Replace(" ", "");
byte[] raw = new byte[aHex.Length / 2];
for (int i = 0; i < raw.Length; i++)
{
raw[i] = Convert.ToByte(aHex.Substring(i * 2, 2), 16);
}
return raw;
}
This is the code to start listening:
private void button1_Click(object sender, EventArgs e)
{
//<-- This block ensures that no exceptions happen
if (_serialPort != null && _serialPort.IsOpen)
_serialPort.Close();
if (_serialPort != null)
_serialPort.Dispose();
//<-- End of Block
/*--- OHAUS Ranger Count Config ---*/
//http://us.ohaus.com/us/en/home/support/faq.aspx
_serialPort = new SerialPort(comboBox1.Text);
_serialPort.BaudRate = 2400;
_serialPort.Parity = Parity.None;
_serialPort.DataBits = 7;
_serialPort.StopBits = StopBits.Two;
_serialPort.Handshake = Handshake.None;
/*--- End OHAUS Ranger Count Config ---*/
label1.Text = "Listening on " + _serialPort.PortName + "...";
_serialPort.DataReceived += SerialPortOnDataReceived; //<- Here I add the event
_serialPort.Open(); //<-- make the comport listen
}
Inside the method that is called when you press the print key, you can add the serial port event handler:
_serialPort.OnDataReceived+=SerialPortOnDataReceived;
Then, at the end of your SerialPortOnDataReceived method (after the successful read), remove the event handler from the serial port object. This will make it stop listening for new data on the serial port until you press print again.
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
{
if (InvokeRequired)
{
BeginInvoke(new Closure(() => { SerialPortOnDataReceived(sender, serialDataReceivedEventArgs); }));
}
else
{
if (_serialPort.BytesToRead > 0)
{
//hex = ""; <- Without this different weight values appears one after another. If applied then happens what explained above.
while (_serialPort.BytesToRead > 0) //<-- repeats until the In-Buffer is empty
{
hex += string.Format("{0:X2} ", _serialPort.ReadByte());
}
byte[] data = FromHex(hex.Trim());
textBox1.Text = Encoding.ASCII.GetString(data).Trim();
_serialPort.OnDataReceived-=SerialPortOnDataReceived; // <---add this
}
}
}
This is how I update the UI thread.
delegate void SerialPortOnDataReceivedDelegate(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs);
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
{
if (InvokeRequired)
BeginInvoke(new SerialPortOnDataReceivedDelegate(SerialPortOnDataReceived), new object[] { sender, serialDataReceivedEventArgs });
else
{
if (_serialPort.BytesToRead > 0)
{
//hex = ""; <- Without this different weight values appears one after another. If applied then happens what explained above.
while (_serialPort.BytesToRead > 0) //<-- repeats until the In-Buffer is empty
{
hex += string.Format("{0:X2} ", _serialPort.ReadByte());
}
byte[] data = FromHex(hex.Trim());
textBox1.Text = Encoding.ASCII.GetString(data).Trim();
}
}
}
public byte[] FromHex(string aHex)
{
aHex = aHex.Replace(" ", "");
byte[] raw = new byte[aHex.Length / 2];
for (int i = 0; i < raw.Length; i++)
{
raw[i] = Convert.ToByte(aHex.Substring(i * 2, 2), 16);
}
return raw;
}
This is what worked for me, I added some delay before hex = "", however I believe this is not a good practice though:
string hex = "";
private delegate void Closure();
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
{
if (InvokeRequired)
{
BeginInvoke(new Closure(() => { SerialPortOnDataReceived(sender, serialDataReceivedEventArgs); }));
}
else
{
if (_serialPort.BytesToRead > 0)
{
Thread.Sleep(200); //<-- Add some delay
hex = "";
while (_serialPort.BytesToRead > 0) //<-- repeats until the In-Buffer is empty
{
hex += string.Format("{0:X2} ", _serialPort.ReadByte());
}
byte[] data = FromHex(hex.Trim());
textBox1.Text = Encoding.ASCII.GetString(data).Trim();
}
}
}

C# read Data from 2 RS232(COM-Ports) independent

Is there any possibility to read Data from 2 RS232 Ports parallel?
It seems, that when i have 2 DataReceived-Events there are blocking each other.
I have also tried to set the SerialPort.ReceivedBytesThreshold to a value of 50/100
class DataCollector
{
private SerialPort _serialPort;
List<String> Data;
private bool _finished = false;
private bool _handshake = true;
public DataCollector(SerialPort serialPort, bool handshake=true)
{
Data = new List<String>();
_serialPort = serialPort;
_serialPort.DataReceived += SerialPortDataReceived;
_handshake = handshake;
if (_serialPort.IsOpen)
{
_serialPort.DiscardInBuffer();
}
}
~DataCollector()
{
if (_serialPort.IsOpen)
{
_serialPort.DiscardInBuffer();
}
Data.Clear();
}
private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (_handshake == false)
{
String str =_serialPort.ReadLine();
str.Insert(str.Length, "\n");
Data.Add(str);
if (Data.Count == 48)
{
_finished = true;
}
}
else
{
Char readedByte = (char)_serialPort.ReadByte();
if ((readedByte != (char)5) && Data.Count == 0)
{
return;
}
if (readedByte.CompareTo((char)2) == 0)
{
readLine();
sendAck();
}
else if (readedByte.CompareTo((char)5) == 0)
{
Data.Add(((char)5).ToString());
sendAck();
}
else if (readedByte == (char)4)
{
_finished = true;
}
}
private void sendAck()
{
if (_serialPort.IsOpen )
{
Byte[] bytes = {6};
_serialPort.Write(bytes,0,1);
}
}
private void readLine(){
String str = _serialPort.ReadLine();
Data.Add(str);
}
}
There are 2 defined in the Main:
_inputCollector = new DataCollector(_RS232Input);
_inputSecondCollector = new DataCollector(_RS232SecondInput, false);
Comment
I would seriously reconsider that implementation of only having a single thread - you should realistically have two separate threads each dealing with its own serial port (as currently, the program will 'freeze' if a large message was passed in - meaning the second port will be 'unusable' until this msg has finished).
Answer
Your system is currently running on a single thread. But implementing a muti-threading system - one which will listen to the first port, and another to listen to the second port. That way, they can both work at the same time.
Currently, (on this single thread) if data is received on one port, (and the other receives also) the thread will 'freeze' until the first message has been received/dealt with - and THEN will read the second port (that is, if it has not already timed out). So by using two threads, both ports can be written/read simultaneously (or, seem to be anyway).

Multithread with TCPclient

I do have a problem with a multithreaded TCPClient application, every Client object has a Thread that recievies and sends messages and a thread that handle the Tasks that should be handled (depending on the messages)... (for example creates and answer that the msg threads sends). But something is going wrong... the application almost allways uses 100% cpu (if any thread have a task, and thats most of the time). I also have a feeling that some threads get prioritised less then others (can see in some loggs that an operation takes longer in thread 1 then in thread 2 for exampel... Is there any nice way to handel this problem?
I would love some help or some hints!
Anything unclear just ask :)
Thanks! /Nick
//Waiting for TCP-connections and creating them as they arrive. Starts a Thread that handles the messages recieved and sent with this thread.
private void ListenForClients()
{
try
{
this.tcpListener.Start();
while (true)
{
TcpClient client = this.tcpListener.AcceptTcpClient();
Connection c = new Connection(this.parent);
connectionCollection.Add(c);
Thread clientThread = new Thread(new ParameterizedThreadStart(c.HandleClientComm));
threadCollection.Add(clientThread);
clientThread.Start(client);
}
}
catch (Exception e)
{
}
}
//Connection constructor, creates a ToDo-thread, this handles the messages (DB, Filewriting etc.) recieived and creats new ones to be sent.
public Connection()
{
this.todo = new ArrayList();
todoT = new Thread(handleToDo);
todoT.Start();
}
//Messagehandeling-thread
public void HandleClientComm(object client)
{
try
{
TcpClient server = (TcpClient)client;
NetworkStream ns = server.GetStream();
byte[] data = new byte[1024];
string input, stringData;
online = true;
DateTime lastTime = DateTime.Now;
while (true && this.online)
{
try
{
if (lastTime.AddMinutes(2) < DateTime.Now)
break;
data = new byte[1024];
if (ns.DataAvailable && ns.CanRead)
{
int recv = ns.Read(data, 0, data.Length);
if (recv > 0)
{
lastTime = DateTime.Now;
if ((byte)data[recv - 1] == (byte)255)
{
int cnt = -1;
for (int i = 0; i < recv; i++)
{
if (data[i] == (byte)254)
{
cnt = i;
break;
}
}
int nr = recv - cnt - 2;
byte[] tmp = new byte[nr];
for (int i = 0; i < nr; i++)
{
tmp[i] = data[cnt + i + 1];
}
string crc = Encoding.UTF8.GetString(tmp);
stringData = Encoding.UTF8.GetString(data, 0, cnt);
MsgStruct msgs = new MsgStruct(stringData);
msgs.setCrc(crc);
addTodo(msgs);
if (msgs.getMsg()[0] == 'T' && this.type == 1)
this.parent.cStructHandler.sendAck(msgs, this.ID);
Console.WriteLine(todo.Count);
}
}
}
if (parent.cStructHandler.gotMsg(this.ID))
{
MsgStruct tmpCs = parent.cStructHandler.getNextMsg(this.ID);
if (tmpCs.getMsg().Length != 0 && ns.CanWrite)
{
byte[] ba = Encoding.UTF8.GetBytes(tmpCs.getMsg());
if (tmpCs.getCrc() == "")
{
ulong tmp = CRC.calc_crc(ba, ba.Length);
tmpCs.setCrc(tmp.ToString("X"));
}
if (tmpCs.canSendByTimeout())
{
string crcStr = "?" + tmpCs.getCrc() + "?";
byte[] bb = Encoding.UTF8.GetBytes(crcStr);
crcStr = Encoding.UTF8.GetString(bb);
byte[] fullMsg = new byte[ba.Length + bb.Length];
bb[0] = 254;
bb[bb.Length - 1] = 255;
ba.CopyTo(fullMsg, 0);
bb.CopyTo(fullMsg, ba.Length);
string s = System.Text.UTF8Encoding.ASCII.GetString(fullMsg);
ns.Write(fullMsg, 0, fullMsg.Length);
if (!tmpCs.isAckNeeded())
parent.cStructHandler.removeNextMsg(this.ID);
}
}
}
}
catch (Exception e)
{
break;
}
}
ns.Close();
server.Close();
dead = true;
}
catch (Exception e)
{
dead = true;
}
}
//Todo-thread
public void handleToDo()
{
try
{
int cnt = 0;
while (true)
{
if (todo.Count > 0)
{
//SWITCH CASE FOR DIFFERENT MESSAGE TYPES, DOING TASKS DEPENDING ON WHAT ONES...
}
else
{
if (dead)
{
todoT.Abort();
todoT = null;
break;
}
}
}
}
}
Stop checking if data is available etc. and just let the read() block. That's how it's supposed to work!
If you want to write stuff to the socket, do it from another thread, (direct from parent thingy?), or change your design to use async reads/writes.
Looping around, polling stuff, sleep() etc. is just a waste of CPU and/or adding avoidable latency to your app.

WinForm With Multiple Timers

I am writing a WinForm application to use SNMP calls either every 30 seconds or 1 minute.
I have a timer working for calling my SNMP commands, but I want to add a texbox counter that display the total time elapsed during the operation.
There are many problems I am having so here is a list:
I want my SNMP timer 'timer' to execute once before waiting the allotted time so I have it going off at 3 seconds and then changing the interval in my handler. But this sometimes makes the timer go off multiple times which is not what I want.
Every time 'timer' goes off and my SNMP calls execute my counter timer 'appTimer' becomes out of sync. I tried a work around where I check if it is in the other handler and then just jump the timer to its appropriate time. Which works but I feel this is making it too complicated.
My last issue, that I know of, happens when I stop my application using my stop button which does not completely exit the app. When I go to start another run the time between both timers is becomes even greater and for some reason my counting timer 'appTimer' starts counting twice as fast.
I hope this description isn't too confusing but here is my code anyway:
using System;
using System.Net;
using SnmpSharpNet;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public static bool stop = false;
static bool min = true, eye = false, firstTick = false;
static string ipAdd = "", fileSaveLocation = "";
static System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
static System.Windows.Forms.Timer appTimer = new System.Windows.Forms.Timer();
static int alarmCounter = 1, hours = 0, minutes = 0, seconds = 0, tenthseconds = 0, count = 0;
static bool inSNMP = false;
static TextBox textbox, timeTextbox;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
textbox = outputBox;
timeTextbox = timeBox;
ipAdd = "192.168.98.107";
fileSaveLocation = "c:/Users/bshellnut/Desktop/Eye.txt";
min = true;
inSNMP = false;
}
private void IPtext_TextChanged(object sender, EventArgs e)
{
ipAdd = IPtext.Text;
}
private void stopButton_Click(object sender, EventArgs e)
{
stop = true;
timer.Stop();
appTimer.Stop();
count = 0;
hours = minutes = seconds = tenthseconds = 0;
inSNMP = false;
}
// This is the method to run when the timer is raised.
private static void TimerEventProcessor(Object myObject,
EventArgs myEventArgs)
{
inSNMP = true;
timer.Stop();
if (firstTick == true)
{
// Sets the timer interval to 60 seconds or 1 second.
if (min == true)
{
timer.Interval = 1000 * 60;
}
else
{
timer.Interval = 1000 * 30;
}
}
// Displays a message box asking whether to continue running the timer.
if (stop == false)
{
textbox.Clear();
// Restarts the timer and increments the counter.
alarmCounter += 1;
timer.Enabled = true;
System.IO.StreamWriter file;
//if (eye == true)
//{
file = new System.IO.StreamWriter(fileSaveLocation, true);
/*}
else
{
file = new System.IO.StreamWriter(fileSaveLocation, true);
}*/
// SNMP community name
OctetString community = new OctetString("public");
// Define agent parameters class
AgentParameters param = new AgentParameters(community);
// Set SNMP version to 2 (GET-BULK only works with SNMP ver 2 and 3)
param.Version = SnmpVersion.Ver2;
// Construct the agent address object
// IpAddress class is easy to use here because
// it will try to resolve constructor parameter if it doesn't
// parse to an IP address
IpAddress agent = new IpAddress(ipAdd);
// Construct target
UdpTarget target = new UdpTarget((IPAddress)agent, 161, 2000, 1);
// Define Oid that is the root of the MIB
// tree you wish to retrieve
Oid rootOid;
if (eye == true)
{
rootOid = new Oid("1.3.6.1.4.1.128.5.2.10.14"); // ifDescr
}
else
{
rootOid = new Oid("1.3.6.1.4.1.128.5.2.10.15");
}
// This Oid represents last Oid returned by
// the SNMP agent
Oid lastOid = (Oid)rootOid.Clone();
// Pdu class used for all requests
Pdu pdu = new Pdu(PduType.GetBulk);
// In this example, set NonRepeaters value to 0
pdu.NonRepeaters = 0;
// MaxRepetitions tells the agent how many Oid/Value pairs to return
// in the response.
pdu.MaxRepetitions = 5;
// Loop through results
while (lastOid != null)
{
// When Pdu class is first constructed, RequestId is set to 0
// and during encoding id will be set to the random value
// for subsequent requests, id will be set to a value that
// needs to be incremented to have unique request ids for each
// packet
if (pdu.RequestId != 0)
{
pdu.RequestId += 1;
}
// Clear Oids from the Pdu class.
pdu.VbList.Clear();
// Initialize request PDU with the last retrieved Oid
pdu.VbList.Add(lastOid);
// Make SNMP request
SnmpV2Packet result;
try
{
result = (SnmpV2Packet)target.Request(pdu, param);
}
catch (SnmpSharpNet.SnmpException)
{
timer.Stop();
textbox.Text = "Could not connect to the IP Provided.";
break;
}
// You should catch exceptions in the Request if using in real application.
// If result is null then agent didn't reply or we couldn't parse the reply.
if (result != null)
{
// ErrorStatus other then 0 is an error returned by
// the Agent - see SnmpConstants for error definitions
if (result.Pdu.ErrorStatus != 0)
{
// agent reported an error with the request
textbox.Text = "Error in SNMP reply. " + "Error " + result.Pdu.ErrorStatus + " index " + result.Pdu.ErrorIndex;
lastOid = null;
break;
}
else
{
// Walk through returned variable bindings
foreach (Vb v in result.Pdu.VbList)
{
// Check that retrieved Oid is "child" of the root OID
if (rootOid.IsRootOf(v.Oid))
{
count++;
textbox.Text += "#" + count + " " + v.Oid.ToString() + " " + SnmpConstants.GetTypeName(v.Value.Type) +
" " + v.Value.ToString() + Environment.NewLine;
file.WriteLine("#" + count + ", " + v.Oid.ToString() + ", " + SnmpConstants.GetTypeName(v.Value.Type) +
", " + v.Value.ToString(), true);
if (v.Value.Type == SnmpConstants.SMI_ENDOFMIBVIEW)
lastOid = null;
else
lastOid = v.Oid;
}
else
{
// we have reached the end of the requested
// MIB tree. Set lastOid to null and exit loop
lastOid = null;
}
}
}
}
else
{
//Console.WriteLine("No response received from SNMP agent.");
textbox.Text = "No response received from SNMP agent.";
//outputBox.Text = "No response received from SNMP agent.";
}
}
target.Close();
file.Close();
}
else
{
// Stops the timer.
//exitFlag = true;
count = 0;
}
}
private static void ApplicationTimerEventProcessor(Object myObject,
EventArgs myEventArgs)
{
tenthseconds += 1;
if (tenthseconds == 10)
{
seconds += 1;
tenthseconds = 0;
}
if (inSNMP && !firstTick)
{
if (min)
{
seconds = 60;
}
else
{
textbox.Text += "IN 30 SECONDS!!!";
if (seconds < 30)
{
seconds = 30;
}
else
{
seconds = 60;
}
}
}
if(seconds == 60)
{
seconds = 0;
minutes += 1;
}
if(minutes == 60)
{
minutes = 0;
hours += 1;
}
timeTextbox.Text = (hours < 10 ? "00" + hours.ToString() : hours.ToString()) + ":" +
(minutes < 10 ? "0" + minutes.ToString() : minutes.ToString()) + ":" +
(seconds < 10 ? "0" + seconds.ToString() : seconds.ToString()) + "." +
(tenthseconds < 10 ? "0" + tenthseconds.ToString() : tenthseconds.ToString());
inSNMP = false;
firstTick = false;
}
private void eyeButton_Click(object sender, EventArgs e)
{
outputBox.Text = "Connecting...";
eye = true;
stop = false;
count = 0;
hours = minutes = seconds = tenthseconds = 0;
timer.Tick += new EventHandler(TimerEventProcessor);
timer.Interval = 3000;
firstTick = true;
appTimer.Tick += new EventHandler(ApplicationTimerEventProcessor);
appTimer.Interval = 100;
appTimer.Start();
timer.Start();
}
private void jitterButton_Click(object sender, EventArgs e)
{
outputBox.Text = "Connecting...";
eye = false;
stop = false;
count = 0;
hours = minutes = seconds = tenthseconds = 0;
timer.Tick += new EventHandler(TimerEventProcessor);
timer.Interval = 3000;
firstTick = true;
appTimer.Tick += new EventHandler(ApplicationTimerEventProcessor);
appTimer.Interval = 100;
appTimer.Start();
timer.Start();
}
private void Seconds_CheckedChanged(object sender, EventArgs e)
{
min = false;
}
private void Minutes_CheckedChanged(object sender, EventArgs e)
{
min = true;
}
private void exitButton_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void savetextBox_TextChanged(object sender, EventArgs e)
{
fileSaveLocation = savetextBox.Text;
}
}
}
This is very easy to do with a single timer. The timer has a 1/10th second resolution (or so) and can be used directly to update the elapsed time. You can then use relative elapsed time within that timer to fire off your SNMP transaction, and you can reschedule the next one dynamically.
Here's a simple example
using System;
using System.Drawing;
using System.Windows.Forms;
class Form1 : Form
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
DateTime lastSnmpTime;
TimeSpan snmpTime = TimeSpan.FromSeconds(30);
DateTime startTime;
TextBox elapsedTimeTextBox;
Timer timer;
public Form1()
{
timer = new Timer { Enabled = false, Interval = 10 };
timer.Tick += new EventHandler(timer_Tick);
elapsedTimeTextBox = new TextBox { Location = new Point(10, 10), ReadOnly = true };
Controls.Add(elapsedTimeTextBox);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
startTime = DateTime.Now;
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
// Update elapsed time
elapsedTimeTextBox.Text = (DateTime.Now - startTime).ToString("g");
// Send SNMP
if (DateTime.Now - lastSnmpTime >= snmpTime)
{
lastSnmpTime = DateTime.Now;
// Do SNMP
// Adjust snmpTime as needed
}
}
}
Updated Q&A
With this code the timer fires once at the beginning where after I
press the stop button and call timer.Stop() and then press my start
button the timer doesn't fire until roughly 12 seconds later. Will
resetting the DateTimes fix this?
When the user presses the Start button, set lastSnmpTime = DateTime.MinValue. This causes the TimeSpan of (DateTime.Now - lastSnmpTime) to be over 2,000 years, so it will be greater than snmpTime and will fire immediately.
Also my output time in the text box looks like this: 0:00:02.620262.
Why is that? Is there a way to make it display only 0:00:02.62?
When you subtract two DateTime values, the result is a TimeSpan value. I used a standard TimeSpan formatting string of "g". You can use a custom TimeSpan formatting string of #"d\:hh\:mm\:ss\.ff" to get days:hours:minutes:seconds.fraction (2 decimal places).
Also will the timer go on and print out to the text box when it is run
for over 9 hours? Because I plan to have this running for 24 hrs+
If you use the custom format with 'd' to show the number of days, it will run for TimeSpan.MaxValue which is slightly more than 10,675,199 days, which is more than 29,000 years.

Categories

Resources