I am writing a C# program to interface with an Arduino through a serial port and I have a function updateRPMs() that slows down the program so much it is unusable. It gets called every 1 second when it is used. The program runs a few PWM fans.
Here is the function:
private void updateRPMs()
{
TextBox[] RPMS = { Fan1RPM, Fan2RPM, Fan3RPM, Fan4RPM, Fan5RPM, Fan6RPM, Fan7RPM, Fan8RPM, Fan9RPM, Fan10RPM, Fan11RPM, Fan12RPM };
List<String> sepData = new List<String>();
if (CONNECTED)
{
String data = serialPort1.ReadLine();
// MessageBox.Show(data);
sepData = (data.Split(';').ToList());
if (sepData.Count == 12)
{
for (int i = 0; i < 12; i++)
{
RPMS[i].Text = sepData[i];
}
}
serialPort1.DiscardOutBuffer();
}
}
This is something the Arduino would send to the program:
a840.00;b885.00;c0;d0;e0;f0;g1635.00;h2070.00;i0;j0;k0;l0
I know I can push this to a different thread but I am trying to have it update as soon as the timer fires.
I was wondering if there is anything I could change or if there was anything stupid I did. I am new to C# and any help would be appreciated.
For reading from serial, I suggest you to avoid using a timer to read from the serial. You can use the DataReceived event, which is fired every time some data is received from the serial.
Of course you could receive a partial packet, so it's better to store the data in a buffer and then analyze it.
String readBuffer = "";
private static void DataReceivedHandler(
object sender,
SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
readBuffer += sp.ReadExisting();
int newLineIndex = -1;
while ((newLineIndex = readBuffer.IndexOf("\n")) >= 0)
{ // Analyze buffer
String currentLine = readBuffer.Substring(0,newLineIndex);
if (currentLine.length() > 0)
analyzeLine(currentLine);
readBuffer = readBuffer.Substring(newLineIndex+1);
}
}
public void analyzeLine(String data)
{
static TextBox[] RPMS = { Fan1RPM, Fan2RPM, Fan3RPM, Fan4RPM, Fan5RPM, Fan6RPM, Fan7RPM, Fan8RPM, Fan9RPM, Fan10RPM, Fan11RPM, Fan12RPM };
List<String> sepData = (data.Split(';').ToList());
if (sepData.Count == 12)
{
for (int i = 0; i < 12; i++)
{
RPMS[i].Text = sepData[i];
}
}
}
I assume you know how to attach to an event, since you already used the timer one ini your code ;)
Related
I need help with my program with which I want to read codes from several microcontrollers simultaneously and translate them into plain text. There is only one serial interface where all codes are collected. The translation of the codes works, but I have the problem that the codes are not read correctly. He makes pauses again and again where there are no gaps and where there are gaps (500 micro sec. ) He doesn't always recognize them correctly.
Here's part of the code:
public byte[] block = new byte[4096];
public int posBlock = 0;
public void Read(object sender, SerialDataReceivedEventArgs e)
{
console_.WriteLine("--------------------------------------------------");
console_.WriteLine("Void: Read(object sender, SerialDataReceivedEventArgs e)");
int offset = 0, count = serialPort.BytesToRead, i = 0;
byte[] rd = new byte[count];
serialPort.Read(rd, offset, count);
for (int buffer = 0; buffer < count; buffer++) { block[posBlock + buffer] = rd[buffer]; i = buffer; }
i++;
posBlock += i;
string rcpausgabe = null;
for (int i2 = 0; i2 < posBlock; i2++) { rcpausgabe += " " + (int)(block[i2]); }
//WriteProtocol(global_.variables.protocol_other, rcpausgabe, true);
console_.WriteLine("ReadCode: " + rcpausgabe);
if (IsDecode == false) { Zersetzten(); } else { console_.WriteLine("Add but not Zersetzen()"); }
IsDecode = false;
console_.WriteLine("--------------------------------------------------");
}
bool IsDecode = true;
public int ib = 0;
public string bs = null;
private void Zersetzten()
{
IsDecode = true;
console_.WriteLine("--------------------------------------------------");
console_.WriteLine("Void: Zersetzten()");
byte[] b = new byte[4096];
while (!(ib >= posBlock))
{
for (int i7 = 0; i7 < b[1] + 3; i7++)
{
string rcpausgabe1 = null;
b[i7] = block[ib];
ib++;;
if (i7+1 == (b[1] + 3))
{
Thread.Sleep(500);
console_.WriteLine("Decoding b");
for (int i2 = 0; i2 < b[1]+3; i2++) { rcpausgabe1 += " " + (int)(b[i2]); }
console_.WriteLine("Decoding Code: " + rcpausgabe1);
bs = rcpausgabe1;
Decoding(b);
}
}
}
IsDecode = false;
block = new byte[4096];
posBlock = 0;
ib = posBlock;
console_.WriteLine("--------------------------------------------------");
}
I have programmed my own console (console_) to help me with this, which allows me to track all processes in real time.
I also thank everyone for their answers in advance.
(I translated this text with Pons translator because my english is not so good)
I can't comment, so I have to use post to help you clarify your question.
I'll edit my answer if you could provide more detail.
Make your question clearer.
What result do you expect and what kind of phenomena do you observe.
Make minimal, reproducible example
Apparently Read(object sender, SerialDataReceivedEventArgs e) is not called inside of your post.
While your problem is reading is "paused", which piece of code is calling Read could be essential.
What is "pause" and what is "Gap".
He makes pauses again and again where there are no gaps and where there are gaps (500 micro sec.
I could only guess your program will "pause" when there is a gap, but having no idea about what "gap" and "pause" are.
What does for (int i7 = 0; i7 < b[1] + 3; i7++) and for (int i2 = 0; i2 < b[1]+3; i2++) want do achieve?
You're using b[1] for indexing and b[1] is changed while you're receiving data.
Edit: Adding How to create a Minimal, Reproducible Example.
Edit2: Point out a strange piece of code in for loop.
I am not sure what is wrong with you about the code you provided.
However, you could refer to [C#, need to receive data from microcontroller to receive data from microcontroller)
to know how to achieve the data from the microcontroller.
Currently I am trying to create a console game. The basic concept is that the user gets a number of randomized letters and has a limited amount of time to make as many words with these letters as possible. An example could be, that the user gets [a,a,c,t,t,e,g,s,o,i] where valid words would be "get", "got", "test", etc. The user input is checked on whether it is present in a word list and whether it consists of letters that are allowed to be used. Unfortunately I have some trouble trying to implement and display the timer for this game.
Please note: My C# knowledge is very limited, as I am just a beginner.
The problem
At the moment I have a background thread that contains a loop with the ReadLine() function. The 'normal' code pauses with the Sleep() function and continues when the time is up. It is heavily inspired by the solution given here. What I am hoping to achieve is to display a timer in the console, that tells the user how many seconds he has left to fill in words. However, I have not figured out how to achieve this.
I have trouble thinking up a solution, because of the following. The reason the timer words is because after the 'normal' code is paused, the Thread containing the loop asking for userinput, is active without interruptions. This means that there are no interruptions that could allow a timer to printed. I have no idea on how to periodically 'pause' the readline function while maintaining its functionality.
So my question to you is, how could I achieve this?
The code
This is a piece of isolated code containing just this functionality. So the words are not tested on whether they meet the requirements.
using System;
using System.Collections.Generic;
using System.Threading;
namespace UnderstandingThreading
{
class Reader
{
private static Thread inputThread;
private static List<string> userInput = new List<string>();
private static bool closeLoop = new bool();
static Reader()
{
inputThread = new Thread(reader);
closeLoop = false;
inputThread.IsBackground = true;
inputThread.Start();
}
private static void reader()
{
while (!closeLoop)
{
userInput.Add(Console.ReadLine());
}
}
public static List<string> ReadLine(int timeOutMilliseconds)
{
Thread.Sleep(timeOutMilliseconds);
closeLoop = true;
return userInput;
}
}
class MainClass
{
public static void Main(string[] args)
{
List<string> allEntries = new List<string>();
Console.WriteLine("Please enter random things for the next 5 seconds");
allEntries = Reader.ReadLine(5000);
for (int i = 0; i < allEntries.Count; i++)
{
Console.WriteLine(allEntries[i]);
}
}
}
}
Thank you,
Sebastiaan
Actually I found a way better way to do and much more easier to implement and to understand. Simply using the class System.Timers.Timer !
class MainClass
{
private static int delay { get; set; }
private static int time_left { get; set; }
public static void Main(string[] args)
{
delay = 8;
time_left = delay;
List<string> allEntries = new List<string>();
Console.WriteLine("Please enter random things for the next 5 seconds");
Console.SetCursorPosition(0, 2);
System.Timers.Timer Timer = new System.Timers.Timer(1000);
Timer.Elapsed += WriteTimeLeft;
Timer.AutoReset = true;
Timer.Enabled = true;
Timer.Start();
allEntries = Reader.ReadLine(10000);
Timer.Stop();
for (int i = 0; i < allEntries.Count; i++)
{
Console.WriteLine(allEntries[i]);
}
Console.Read();
}
public static void WriteTimeLeft(Object source, ElapsedEventArgs e)
{
int currentLineCursorTop = Console.CursorTop;
int currentLineCursorLeft = Console.CursorLeft;
Console.CursorVisible = false;
Console.SetCursorPosition(0, 1);
Console.Write(new string(' ', Console.WindowWidth));
Console.SetCursorPosition(0, 1);
Console.Write(time_left);
Console.SetCursorPosition(currentLineCursorLeft, currentLineCursorTop);
Console.CursorVisible = true;
time_left -= 1;
}
Basically, we set a timer which has an interval of 1000ms and we set it as AutoReset, therefore it will fire an event each seconds when it is activated. We just add to the list of the methods launch by the event our custom method WriteTimeLeft(Object source, ElapsedEventArgs e) and we're good to go ! :)
I found a solution to your problem using Task.Delay().
Basically I create as much task as there are seconds and I make each one wait 1 second more than the one before. When a task is completed it calls the function WriteTimeLeft() which take care of displaying correctly the time and letting the user type his answer (I erase the line where I display the time and replace it by the new time and then move back the cursor where it was). To this purpose I added the constant "delay" and the variable "time_left". As this action is really quick the user can type without interuption :)
I believe the code is undertandable but if you have any question do not hesitate to ask :)
This isn't perfect (i'm not a professional of C#) but it'll do what you asked for ;)
class MainClass
{
private static int delay { get; set; }
private static int time_left { get; set; }
public static void Main(string[] args)
{
delay = 10;
time_left = delay;
List<string> allEntries = new List<string>();
Console.WriteLine("Please enter random things for the next 10 seconds");
Console.SetCursorPosition(0, 2);
Timer();
allEntries = Reader.ReadLine(11000);
for (int i = 0; i < allEntries.Count; i++)
{
Console.WriteLine(allEntries[i]);
}
Console.Read();
}
public static void Timer()
{
for (int i = 11; i > 0; i--)
{
var t = Task.Delay(i*1000).ContinueWith(_ => WriteTimeLeft());
}
}
public static void WriteTimeLeft()
{
int currentLineCursorTop = Console.CursorTop;
int currentLineCursorLeft = Console.CursorLeft;
Console.CursorVisible = false;
Console.SetCursorPosition(0, 1);
Console.Write(new string(' ', Console.WindowWidth));
Console.SetCursorPosition(0, 1);
Console.Write(time_left);
Console.SetCursorPosition(currentLineCursorLeft, currentLineCursorTop);
Console.CursorVisible = true;
time_left -= 1;
}
}
I want to play a video (mostly .mov with Motion JPEG) in frame by frame mode with changing framerate. I have a function who gives me a framenumber and then I have to jump there. It will be mostly in one direction but can skip a few frames from time to time; also the velocity is not constant.
So I have a timer asking every 40ms about a new framenumber and setting the new position.
My first approach now is with DirectShow.Net (Interop.QuartzTypeLib). Therefore I render and open the video and set it to pause to draw the picture in the graph
FilgraphManagerClass media = new FilgraphManagerClass();
media.RenderFile(FileName);
media.pause();
Now I will just set a new position
media.CurrentPosition = framenumber * media.AvgTimePerFrame;
Since the video is in pause mode it will then draw every requested new position (frame). Works perfectly fine but really slow... the video keeps stuttering and lagging and its not the video source; there are enough frames recorded to play a fluent video.
With some performance tests I found out that the LAV-Codec is the bottleneck here. This is not included directly in my project since its a DirectShow-Player it will be cast through my codec pack I installed on my PC.
Ideas:
Using the LAV-Codec by myself directly in C#. I searched but everyone is using DirectShow it seems, building their own filters and not using existing ones directly in the project.
Instead of seeking or setting the time, can I get single frames just by the framenumber and draw them simply?
Is there a complete other way to archive what I want to do?
Background:
This project has to be a train simulator. We recorded real time videos of trains driving from inside the cockpit and know which frame is what position. Now my C# programm calculates the position of the train in dependence of time and acceleration, gives back the appropriate framenumber and draw this frame.
Additional Information:
There is another project (not written by me) in C/C++ who uses DirectShow and the avcodec-LAV directly with a similar way I do and it works fine! Thats because I had the idea to use a codec / filter like the avrcodec-lav by myself. But I can't find an interop or interface to work with C#.
Thanks everyone for reading this and trying to help! :)
Obtaining specific frame by seeking filter graph (the entire pipeline) is pretty slow since every seek operation involves the following on its backyard: flushing everything, possibly re-creating worker threads, seeking to first key frame/splice point/clean point/I-Frame before the requested time, start of decoding starting from found position skipping frames until originally requested time is reached.
Overall, the method works well when you scrub paused video, or retrieve specific still frames. When however you try to play this as smooth video, it eventually causes significant part of the effort to be wasted and spent on seeking within video stream.
Solutions here are:
re-encode video to remove or reduce temporal compression (e.g. Motion JPEG AVI/MOV/MP4 files)
whenever possible prefer to skip frames and/or re-timestamp them according to your algorithm instead of seeking
have a cached of decoded video frames and pick from there, populate them as necessary in worker thread
The latter two are unfortunately hard to achieve without advanced filter development (where continuous decoding without interruption by seeking operations is the key to achieving decent performance). With basic DirectShow.Net you only have basic control over streaming and hence the first item from the list above.
Wanted to post a comment instead of an answer, but don't have the reputation. I think your heading in the wrong direction with Direct Show. I've been messing with motion-jpeg for a few years now between C# & Android, and have gotten great performance with built-in .NET code (for converting byte-array to Jpeg frame) and a bit of multi-threading. I can easily achieve over 30fps from multiple devices with each device running in it's own thread.
Below is an older version of my motion-jpeg parser from my C# app 'OmniView'. To use, just send the network stream to the constructor, and receive the OnImageReceived event. Then you can easily save the frames to the hard-drive for later use (perhaps with the filename set to the timestamp for easy lookup). For better performance though, you will want to save all of the images to one file.
using OmniView.Framework.Helpers;
using System;
using System.IO;
using System.Text;
using System.Windows.Media.Imaging;
namespace OmniView.Framework.Devices.MJpeg
{
public class MJpegStream : IDisposable
{
private const int BUFFER_SIZE = 4096;
private const string tag_length = "Content-Length:";
private const string stamp_format = "yyyyMMddHHmmssfff";
public delegate void ImageReceivedEvent(BitmapImage img);
public delegate void FrameCountEvent(long frames, long failed);
public event ImageReceivedEvent OnImageReceived;
public event FrameCountEvent OnFrameCount;
private bool isHead, isSetup;
private byte[] buffer, newline, newline_src;
private int imgBufferStart;
private Stream data_stream;
private MemoryStream imgStreamA, imgStreamB;
private int headStart, headStop;
private long imgSize, imgSizeTgt;
private bool useStreamB;
public volatile bool EnableRecording, EnableSnapshot;
public string RecordPath, SnapshotFilename;
private string boundary_tag;
private bool tagReadStarted;
private bool enableBoundary;
public volatile bool OututFrameCount;
private long FrameCount, FailedCount;
public MJpegStream() {
isSetup = false;
imgStreamA = new MemoryStream();
imgStreamB = new MemoryStream();
buffer = new byte[BUFFER_SIZE];
newline_src = new byte[] {13, 10};
}
public void Init(Stream stream) {
this.data_stream = stream;
FrameCount = FailedCount = 0;
startHeader(0);
}
public void Dispose() {
if (data_stream != null) data_stream.Dispose();
if (imgStreamA != null) imgStreamA.Dispose();
if (imgStreamB != null) imgStreamB.Dispose();
}
//=============================
public void Process() {
if (isHead) processHeader();
else {
if (enableBoundary) processImageBoundary();
else processImage();
}
}
public void Snapshot(string filename) {
SnapshotFilename = filename;
EnableSnapshot = true;
}
//-----------------------------
// Header
private void startHeader(int remaining_bytes) {
isHead = true;
headStart = 0;
headStop = remaining_bytes;
imgSizeTgt = 0;
tagReadStarted = false;
}
private void processHeader() {
int t = BUFFER_SIZE - headStop;
headStop += data_stream.Read(buffer, headStop, t);
int nl;
//
if (!isSetup) {
byte[] new_newline;
if ((nl = findNewline(headStart, headStop, out new_newline)) >= 0) {
string tag = Encoding.UTF8.GetString(buffer, headStart, nl - headStart);
if (tag.StartsWith("--")) boundary_tag = tag;
headStart = nl+new_newline.Length;
newline = new_newline;
isSetup = true;
return;
}
} else {
while ((nl = findData(newline, headStart, headStop)) >= 0) {
string tag = Encoding.UTF8.GetString(buffer, headStart, nl - headStart);
if (!tagReadStarted && tag.Length > 0) tagReadStarted = true;
headStart = nl+newline.Length;
//
if (!processHeaderData(tag, nl)) return;
}
}
//
if (headStop >= BUFFER_SIZE) {
string data = Encoding.UTF8.GetString(buffer, headStart, headStop - headStart);
throw new Exception("Invalid Header!");
}
}
private bool processHeaderData(string tag, int index) {
if (tag.StartsWith(tag_length)) {
string val = tag.Substring(tag_length.Length);
imgSizeTgt = long.Parse(val);
}
//
if (tag.Length == 0 && tagReadStarted) {
if (imgSizeTgt > 0) {
finishHeader(false);
return false;
}
if (boundary_tag != null) {
finishHeader(true);
return false;
}
}
//
return true;
}
private void finishHeader(bool enable_boundary) {
int s = shiftBytes(headStart, headStop);
enableBoundary = enable_boundary;
startImage(s);
}
//-----------------------------
// Image
private void startImage(int remaining_bytes) {
isHead = false;
imgBufferStart = remaining_bytes;
Stream imgStream = getStream();
imgStream.Seek(0, SeekOrigin.Begin);
imgStream.SetLength(imgSizeTgt);
imgSize = 0;
}
private void processImage() {
long img_r = (imgSizeTgt - imgSize - imgBufferStart);
int bfr_r = Math.Max(BUFFER_SIZE - imgBufferStart, 0);
int t = (int)Math.Min(img_r, bfr_r);
int s = data_stream.Read(buffer, imgBufferStart, t);
int x = imgBufferStart + s;
appendImageData(0, x);
imgBufferStart = 0;
//
if (imgSize >= imgSizeTgt) processImageData(0);
}
private void processImageBoundary() {
int t = Math.Max(BUFFER_SIZE - imgBufferStart, 0);
int s = data_stream.Read(buffer, imgBufferStart, t);
//
int nl, start = 0;
int end = imgBufferStart + s;
while ((nl = findData(newline, start, end)) >= 0) {
int tag_length = boundary_tag.Length;
if (nl+newline.Length+tag_length > BUFFER_SIZE) {
appendImageData(start, nl+newline.Length - start);
start = nl+newline.Length;
continue;
}
//
string v = Encoding.UTF8.GetString(buffer, nl+newline.Length, tag_length);
if (v == boundary_tag) {
appendImageData(start, nl - start);
int xstart = nl+newline.Length + tag_length;
int xsize = shiftBytes(xstart, end);
processImageData(xsize);
return;
} else {
appendImageData(start, nl+newline.Length - start);
}
start = nl+newline.Length;
}
//
if (start < end) {
int end_x = end - newline.Length;
if (start < end_x) {
appendImageData(start, end_x - start);
}
//
shiftBytes(end - newline.Length, end);
imgBufferStart = newline.Length;
}
}
private void processImageData(int remaining_bytes) {
if (EnableSnapshot) {
EnableSnapshot = false;
saveSnapshot();
}
//
try {
BitmapImage img = createImage();
if (EnableRecording) recordFrame();
if (OnImageReceived != null) OnImageReceived.Invoke(img);
FrameCount++;
}
catch (Exception) {
// output frame error ?!
FailedCount++;
}
//
if (OututFrameCount && OnFrameCount != null) OnFrameCount.Invoke(FrameCount, FailedCount);
//
useStreamB = !useStreamB;
startHeader(remaining_bytes);
}
private void appendImageData(int index, int length) {
Stream imgStream = getStream();
imgStream.Write(buffer, index, length);
imgSize += (length - index);
}
//-----------------------------
private void recordFrame() {
string stamp = DateTime.Now.ToString(stamp_format);
string filename = RecordPath+"\\"+stamp+".jpg";
//
ImageHelper.Save(getStream(), filename);
}
private void saveSnapshot() {
Stream imgStream = getStream();
//
imgStream.Position = 0;
Stream file = File.Open(SnapshotFilename, FileMode.Create, FileAccess.Write);
try {imgStream.CopyTo(file);}
finally {file.Close();}
}
private BitmapImage createImage() {
Stream imgStream = getStream();
imgStream.Position = 0;
return ImageHelper.LoadStream(imgStream);
}
//-----------------------------
private Stream getStream() {return useStreamB ? imgStreamB : imgStreamA;}
private int findNewline(int start, int stop, out byte[] data) {
for (int i = start; i < stop; i++) {
if (i < stop-1 && buffer[i] == newline_src[0] && buffer[i+1] == newline_src[1]) {
data = newline_src;
return i;
} else if (buffer[i] == newline_src[1]) {
data = new byte[] {newline_src[1]};
return i;
}
}
data = null;
return -1;
}
private int findData(byte[] data, int start, int stop) {
int data_size = data.Length;
for (int i = start; i < stop-data_size; i++) {
if (findInnerData(data, i)) return i;
}
return -1;
}
private bool findInnerData(byte[] data, int buffer_index) {
int count = data.Length;
for (int i = 0; i < count; i++) {
if (data[i] != buffer[buffer_index+i]) return false;
}
return true;
}
private int shiftBytes(int start, int end) {
int c = end - start;
for (int i = 0; i < c; i++) {
buffer[i] = buffer[end-c+i];
}
return c;
}
}
}
I am looking to create an external application that monitors the 'FPS' of a DirectX application (like FRAPS without the recording). I have read several Microsoft articles on performance measuring tools - but I am looking to get the feedback (and experience) of the community.
My question: what is the best method for obtaining the FPS of a DirectX application?
Windows has some Event Tracing for Windows providers related to DirectX profiling. The most intresting ones are Microsoft-Windows-D3D9 and Microsoft-Windows-DXGI, which allow tracing of the frame presentation events. The simplest way to calculate FPS is to count the number of PresentStart events withing a time interval and divide that by the length of the interval.
To work with ETW in C#, install Microsoft.Diagnostics.Tracing.TraceEvent package.
The following code sample displays FPS of running processes:
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Threading;
using Microsoft.Diagnostics.Tracing.Session;
namespace ConsoleApp1
{
//helper class to store frame timestamps
public class TimestampCollection
{
const int MAXNUM = 1000;
public string Name { get; set; }
List<long> timestamps = new List<long>(MAXNUM + 1);
object sync = new object();
//add value to the collection
public void Add(long timestamp)
{
lock (sync)
{
timestamps.Add(timestamp);
if (timestamps.Count > MAXNUM) timestamps.RemoveAt(0);
}
}
//get the number of timestamps withing interval
public int QueryCount(long from, long to)
{
int c = 0;
lock (sync)
{
foreach (var ts in timestamps)
{
if (ts >= from && ts <= to) c++;
}
}
return c;
}
}
class Program
{
//event codes (https://github.com/GameTechDev/PresentMon/blob/40ee99f437bc1061a27a2fc16a8993ee8ce4ebb5/PresentData/PresentMonTraceConsumer.cpp)
public const int EventID_D3D9PresentStart = 1;
public const int EventID_DxgiPresentStart = 42;
//ETW provider codes
public static readonly Guid DXGI_provider = Guid.Parse("{CA11C036-0102-4A2D-A6AD-F03CFED5D3C9}");
public static readonly Guid D3D9_provider = Guid.Parse("{783ACA0A-790E-4D7F-8451-AA850511C6B9}");
static TraceEventSession m_EtwSession;
static Dictionary<int, TimestampCollection> frames = new Dictionary<int, TimestampCollection>();
static Stopwatch watch = null;
static object sync = new object();
static void EtwThreadProc()
{
//start tracing
m_EtwSession.Source.Process();
}
static void OutputThreadProc()
{
//console output loop
while (true)
{
long t1, t2;
long dt = 2000;
Console.Clear();
Console.WriteLine(DateTime.Now.ToString() + "." + DateTime.Now.Millisecond.ToString());
Console.WriteLine();
lock (sync)
{
t2 = watch.ElapsedMilliseconds;
t1 = t2 - dt;
foreach (var x in frames.Values)
{
Console.Write(x.Name + ": ");
//get the number of frames
int count = x.QueryCount(t1, t2);
//calculate FPS
Console.WriteLine("{0} FPS", (double)count / dt * 1000.0);
}
}
Console.WriteLine();
Console.WriteLine("Press any key to stop tracing...");
Thread.Sleep(1000);
}
}
public static void Main(string[] argv)
{
//create ETW session and register providers
m_EtwSession = new TraceEventSession("mysess");
m_EtwSession.StopOnDispose = true;
m_EtwSession.EnableProvider("Microsoft-Windows-D3D9");
m_EtwSession.EnableProvider("Microsoft-Windows-DXGI");
//handle event
m_EtwSession.Source.AllEvents += data =>
{
//filter out frame presentation events
if (((int)data.ID == EventID_D3D9PresentStart && data.ProviderGuid == D3D9_provider) ||
((int)data.ID == EventID_DxgiPresentStart && data.ProviderGuid == DXGI_provider))
{
int pid = data.ProcessID;
long t;
lock (sync)
{
t = watch.ElapsedMilliseconds;
//if process is not yet in Dictionary, add it
if (!frames.ContainsKey(pid))
{
frames[pid] = new TimestampCollection();
string name = "";
var proc = Process.GetProcessById(pid);
if (proc != null)
{
using (proc)
{
name = proc.ProcessName;
}
}
else name = pid.ToString();
frames[pid].Name = name;
}
//store frame timestamp in collection
frames[pid].Add(t);
}
}
};
watch = new Stopwatch();
watch.Start();
Thread thETW = new Thread(EtwThreadProc);
thETW.IsBackground = true;
thETW.Start();
Thread thOutput = new Thread(OutputThreadProc);
thOutput.IsBackground = true;
thOutput.Start();
Console.ReadKey();
m_EtwSession.Dispose();
}
}
}
Based on the source code of PresentMon project.
Fraps inserts a DLL into every running application and hooks specific DX calls to figure out the framerate and capture video, pretty sure that you'll have to do something similar. After a bit of poking around I found a Github project that does some basic DX hooking for doing captures and overlays, so that might be a good spot to start out with. Though I've not used it personally so I can't totally vouch for the quality.
http://spazzarama.com/2011/03/14/c-screen-capture-and-overlays-for-direct3d-9-10-and-11-using-api-hooks/
Building on https://stackoverflow.com/a/54625953/12047161:
I had more success not using the stopwatch as the event triggers seems to be asynchronous with the actual frames. I kept getting batches of 20-50 frames all at once, making the estimated FPS fluctuate between 50 and 250% of the actual value.
Instead i used TimeStampRelativeMSec
//handle event
m_EtwSession.Source.AllEvents += data =>
{
//filter out frame presentation events
if((int) data.ID == EventID_DxgiPresentStart && data.ProviderGuid == DXGI_provider)
{
int pid = data.ProcessID;
long t;
t = watch.ElapsedMilliseconds;
//if process is not yet in Dictionary, add it
if (!frames.ContainsKey(pid))
{
frames[pid] = new TimestampCollection();
string name = "";
var proc = Process.GetProcessById(pid);
if (proc != null)
{
using (proc)
{
name = proc.ProcessName;
}
}
else name = pid.ToString();
frames[pid].Name = name;
}
frames[pid].Add((long)data.TimeStampRelativeMSec);
}
};
property from the TraceEvent class, and calculate FPS by rounding the average time between an arbitrary number of past entries:
public double GetFrameTime(int count)
{
double returnValue = 0;
int listCount = timestamps.Count;
if(listCount > count)
{
for(int i = 1; i <= count; i++)
{
returnValue += timestamps[listCount - i] - timestamps[listCount - (i + 1)];
}
returnValue /= count;
}
return returnValue;
}
This method gave me far more accurate (Compared to, as available, in-game counters) of several different games i've tried.
I have a Keyence camera which communicates through RS-232. It is configured to output three integer values when triggered. I'm having trouble reading the integer values. I try to use a char array buffer but it only reads the first + sign in the output. I tested it using putty and output is something like this
+346.0,+261.0,098
I want to know if there is anything I need to use to read integer values like these?
static void Main(string[] args)
{
char[] buffer1 = new char[200] ;
SerialPort port = new SerialPort("COM4", 9600, Parity.None, 8, StopBits.One);
port.Open();
if (port.IsOpen) { Console.WriteLine("port is now open"); } else { Console.WriteLine("port not opened correctly"); }
port.Write("T"); //triggers the camera
port.Read(buffer1, 0, 200);
for (int i = 0; i < 200; i++)
{
Console.WriteLine(buffer1[i]);
}
Console.ReadLine();
}
I've had issues before with reading from the serial port and not reading in everything expected.
Turns out I was reading in the response from the device and it wasn't done yet writing. I figured the serial port object would continue trying to fill the buffer until the read timeout was hit, and that was not what was happening.
In my scenario I knew how many characters I was going to be reading from the serial port. So if you know that you could implement a repeat on the read until your character buffer is full. I don't know if the same would apply if you are reading from SerialPort.BaseStream.
SerialPort serialPort;
char[] buffer = new char[expectedLength];
int totalBytesRead = 0;
//continue to read until all of the expected characters have been read
while (totalBytesRead < expectedLength)
{
totalBytesRead += serialPort.Read(buffer, totalBytesRead, expectedLength - totalBytesRead);
}
This is the code I use (simplified):
public class Scanner : SerialPort
{
private string _word;
private int _globalCounter;
private readonly char[] _rxArray = new char[2047];
public Scanner()
{
DataReceived += MyDataReceivedEventHandler;
}
public event EventHandler<CodeScannedEventArgs> CodeScanned;
private void MyDataReceivedEventHandler(object sender, SerialDataReceivedEventArgs e)
{
do
{
var rxByte = (byte)ReadByte();
// end of word
if (rxByte == 10)
{
// first byte (02) and last two bytes (13 and 10) are ignored
_word = new string(_rxArray, 1, _globalCounter - 2);
DisplayData(_word);
_globalCounter = 0;
}
else
{
_rxArray[_globalCounter] = (char)rxByte;
_globalCounter++;
}
} while (BytesToRead > 0);
}
private void DisplayData(string receivedText)
{
OnCodeScanned(new CodeScannedEventArgs(receivedText));
}
protected void OnCodeScanned(CodeScannedEventArgs e)
{
EventHandler<CodeScannedEventArgs> handler = CodeScanned;
if (handler != null)
{
handler(this, e);
}
}
}
The scanner I use adds byte 02 as a prefix and bytes 13 and 10 as postfix to everything it scans, so it is pretty easy for me to break it up into words. You'll obviously need to change the implementation slightly so it works for you.
Edit - CodeScannedEventArgs class:
public class CodeScannedEventArgs : EventArgs
{
public CodeScannedEventArgs(string scannedCode)
{
ScannedCode = scannedCode;
}
public string ScannedCode { get; set; }
}
I used the port.ReadTo("\r") and it works, as the output ends with a carriage return.
But I want to know what is the advantage of using a data received event?