I am new in C# and currently working on the backend code to support PIN pad. Basically, my code
OpenDevice() -> RequestPIN()
-> key in PIN on PIN PAD -> GetResultPIN()
-> ConsolePrintOutPIN() -> Print keyed PIN on the Console
I don't know how to write thread for this, so that once the "Enter key" is hit on the device after PIN, the system would automatically rolls to function GetResultPIN(). So, with my elementary knowledge, I wrote the following codes using Console.ReadLine() to separate each procedure:
static void Main(string[] args)
{
// 1. Open PIN Pad device
OpenDevice();
Console.ReadLine();// to hold up from the previous procedure, it is *not* for input data purpose
// 2. Request PIN from PIN Pad device.
// On the PIN Pad device, it reads:
// "Key in the PIN: "
RequestPIN();
Console.ReadLine();// to hold up from the previous procedure, it is *not* for input data purpose
// 3. get PIN from the device
GetResultPIN();
// 4. Print out on the Console
ConsolePrintOutPIN();
Console.ReadLine();// to hold up from the previous procedure, it is *not* for input data purpose
}
Question: Can anyone give me any suggestions on how to use threading/event/delegate that can avoid using Console.ReadLine()?
As commended above, Console.ReadLine() is used just to stop the procedure (sorry about my naivety of using it this way....) Once I use Console.ReadLine(), between RequestPIN() and GetResult(), the system would at least wait for me to Key in the PIN from the PIN PAD (connected to the computer through USB, not from key board), and then I would hit any key on the keyboard to pass Console.ReadLine() and GetResultPIN() would be able to get my PIN number from PIN Pad.....the whole program works now, it is not customer ready, because it is very choppy, doesn't flow due to Console.ReadLine() I added.....
So ideally, all the method would flow together. Once the device is opened, RequestPIN() should show on the PIN Pad screen asking for PIN number, some one can key in and hit enter on PIN Pad and it naturally flow to GetResultPIN() and read the result, and then it prints the PIN on the console...`
or
if the person doesn't key in PIN, the device would wait for 30s and directly goes to GetResultPIN() and print out "0000" on the Console
I have looked up treading and delegate, but am not sure how to use them in this situation.... Thank you!
Reference: RequestPin() and GetResultPIN are listed down below:
mIPAD.requestPIN(waitTime, pinMsg, minLen, maxLen, tone, option, ",");
//This function wraps device command 0x04.
//It directs the device to prompt the user to enter a PIN
//by displaying one of five predetermined messages and playing
// a specified sound.
//The messages on the device’s screen look like the figures below.
//The event associated with this function is
//OnPINRequestCompleteEvent.
waitTime: Time the device should wait for the user to begin PIN entry
pinMsg: Message to display as a user prompt, such as "Enter PIN", "ReEnter PIN", "Verify PIN", etc
minLen and maxLen: minimum length and maximum length of PIN
tone: beeping tone option
Option: Verify PIN, not Verify PIN, ISO0 FOrmat, ISO3 Format
Output would be: an integer, 0: Success, Non-Zero: Error
public void GetResultPIN()
{
StringBuilder sb = new StringBuilder();
sb.Append(mIPAD.pin.KSN);
// Key Serial Number:
//a given number from the device, unique for each device
sb.Append("," + mIPAD.pin.EPB);
// EPB: encryption of PIN after Dubpt TripleDES,
// essentially, EPB is PIN
sb.Append("," + mIPAD.getStatusCode());
//status code: Zero is good/done
// None-Zero is Error
sb.Append("\r\n");
result = sb.ToString();
}
Basically, the GetResultPIN() returns a string of random code, for example:
9A00030000047A2000AB,AD781711481B08A2,0 when PIN is successful. If the pin-input part is skipped, it would return ,,0.
Really hard to know if this will work or not without hardware to play with...
This is the way I envisioned it working:
static void Main()
{
OpenDevice();
RequestPIN();
if (GetResultPIN())
{
// do something with the PIN:
var pin = mIPAD.pin.EPB;
// ...
}
else
{
Console.WriteLine("0000");
}
}
public static bool GetResultPIN()
{
TimeSpan timeout = TimeSpan.FromSeconds(30);
System.Diagnostics.Stopwatch SW = new System.Diagnostics.Stopwatch();
SW.Start();
while (mIPAD.getStatusCode() != 0 && SW.Elapsed < timeout)
{
System.Threading.Thread.Sleep(50); // small call to prevent CPU usage ramping to 100%
}
return (mIPAD.getStatusCode() == 0);
}
You can rewrite your api to:
make GetResultPIN() return a value
use this value as input for ConsolePrintOutPIN()
In GetResultPIN you need to make a Task To ReadYour Pin and wait for it.
See : https://msdn.microsoft.com/en-us/library/dd537610(v=vs.110).aspx
You can do something like this:
public string GetResultPIN()
{
StringBuilder sb = new StringBuilder();
sb.Append(mIPAD.pin.KSN);
// Key Serial Number:
//a given number from the device, unique for each device
sb.Append("," + mIPAD.pin.EPB);
// EPB: encryption of PIN after Dubpt TripleDES,
// essentially, EPB is PIN
sb.Append("," + mIPAD.getStatusCode());
//status code: Zero is good/done
// None-Zero is Error
sb.Append("\r\n");
Thread.Sleep(20*1000); // it is in milliseconds
return sb.ToString();
}
Thanks for posting... The solution is still not ideal....
I also did some more testing regarding the function RequestPIN(). I have the following four scenarios:
User finishes keying in PIN sooner than the waitTime goes out.
onPINRequestComplete :
OpStatus:0
KSN:9A00030000047A2000C8
EPB:39DED176D3EA40B9
..............................
User doesn't finish keying in PIN when the waitTime is going out.
onPINRequestComplete :
OpStatus:2
KSN:00000000000000000000
EPB:0000000000000000
..............................
User cancels the PIN pad option by pressing "Cancel X" key on the PIN Pad.
onPINRequestComplete :
OpStatus:1
KSN:00000000000000000000
EPB:0000000000000000
..............................
User doesn't key in PIN at all during the waitTime, and then waitTime goes out.
onPINRequestComplete :
OpStatus:2
KSN:00000000000000000000
EPB:0000000000000000
..............................
So, scenario 1 and 3 would require the thread to wake up right away, while 2 and 4 would require the thread to wake up when the waiTime goes out. So using Thread.sleep(20*1000) within GetResultPIN() would work perfectly for scenario 2 and 4. As for 1 and 3, the user has to wait for a long time....
On the other hand, I found some code about Event
Within Car.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WaitOnTasksToComplete
{
class Car
{
public event Action OnChange;
private double speed;
public double Speed
{
get { return speed; }
set { speed = value;
if (speed >= 60)
{
if (OnChange != null)
{
OnChange();
}
}
}
}
}
}
Within Program.cs:
using System;
namespace WaitOnTasksToComplete
{
class Program
{
static void Main(string[] args)
{
Car c = new Car();
c.OnChange += C_OnChange;
c.Speed = 5;
c.Speed = 55;
c.Speed = 65;
c.Speed = 75;
}
private static void C_OnChange()
{
Console.WriteLine("Event fired: Car goes higher than 60 MPH.");
}
}
}
So, basically once the Car.speed jumps above 60, the alarm would show. I am considering borrowing the condition into my situation: Initialize OpStatus = -999. When OpStatus=0 or 1, keep executing GetResultPIN() and PrintMessagePIN(). If OpStatus=2 or others, keep waiting...
That is just my thoughts.... still have no clue how to implement it.... Any related ideas or suggestions would be appreciated.....
Ah, I figured out. I am basically using threading here. The main flow is OpenDevice()->RequestPIN()->Thread(()=>CheckOpStatus(getResultPIN)) -> Thread.Start(). Within the Thread, a loop is set to check every half second what the OpStatus is. Per my previous post, OpStatusis the output parameter of PIN Pad, zero- success; non-zero: failure. That said, the loop would proceed until either bool condition_WithinWaitTime or bool condition_NoKeyEvent breaks. After breaking out, invoke the getResultPIN and so on....
Here is my source code, as PIN input is one of my functions, the rest of which have very similar behavior in terms programming (request->manual operation->feedback), so I also included a delegate variable to represents all functions (card swiping, PIN, signature bla bla).
static void Main(string[] args)
{
OpenDevice();
EventGetPIN();
}
static void EventGetPIN()
{
myDel getResult = new myDel(GetResultPIN);
Thread thread1 = new Thread(() => CheckOpStatus(getResult));
myDel requestDel = new myDel(RequestPIN); requestDel();
thread1.Start();
}
static void CheckOpStatus(Delegate getResult)
{
int count = 0;
int checkingPeriod = 500;
int totalWaitTime = waitTime * 1000 + offsetTime;
string OpStatus;
string ksnStart = mIPAD.getKSN();
string ksn = ksnStart;
bool condition_WithinWaitTime = true;
bool condition_NoKeyEvent = true;
while (condition_WithinWaitTime & condition_NoKeyEvent)
{
count++;
OpStatus = mIPAD.getStatusCode().ToString();
ksn = mIPAD.getKSN();
//Console.WriteLine(OpStatus);
condition_WithinWaitTime = (count * checkingPeriod) < totalWaitTime;
condition_NoKeyEvent = (ksn == ksnStart);
Thread.Sleep(checkingPeriod);
}
getResult.DynamicInvoke();
}
Related
I have a C# program that wants to interact with an external process written in C++. I believe this C++ process is using correct standard input. I just can't seem to get my C# code to not hang when trying to write to Process.StandardInput.
I've seen countless examples using Process.StandardInput.Close() when done writing. Every StackOverflow answer I found says to use this, and it does work. The problem is I can't close the StreamWriter because I'm not done interacting with the process. The process is a state machine that holds variables created using stdin, parses expressions, and returns an evaluation. I am expected to keep giving the process input after each output.
Does anyone have an example where Process.StandardInput.WriteLine is used more than once without closing or restarting the process?
This is how the C++ process is reading input. This example simply echos back the input and waits for another.
int main () {
std::string input;
while (getline(std::cin, input)) {
std::cout << input << std::endl;
}
}
My C# program tries to interact with this process using this wrapper class.
public class Expression {
System.Diagnostics.Process p;
public Expression () {
p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.FileName = "InputEcho.exe";
p.Start();
p.StandardInput.AutoFlush = true;
}
public void Run (in string input, out string output) {
p.StandardInput.WriteLine(input);
// p.StandardInput.Close();
output = p.StandardOutput.ReadToEnd();
}
}
This works when I uncomment p.StandardInput.Close() but then subsequent calls to Expression.Run() won't work because the writer is closed.
Main program
Expression expn = new();
string output;
Console.WriteLine("Expression start");
expn.Run("Hello", output);
Console.WriteLine(output);
expn.Run("Hi", output);
Console.WriteLine(output);
Expected output
Expression start
Hello
Hi
Actual output
Expression start
EDIT:
#Matthew Andrews provided a really good answer that works, but it's not quite what I'm after. I didn't think about using event delegates to receive output data, and I see why: It's hard to implement this into the wrapper that I want to use to build a process-relevant API. What I mean by this is that I want to write some method that communicates with the process, give it input, receive the output, and return this data to the caller before doing anything else. My Expression.Run method exemplifies this perfectly.
Here's an example of what the root caller would look like in a greater C# program.
bool GetConditionEval (string condition, SomeDataType data) {
// Makes another call to 'Run' that commands the C++ process to store a variable
// Input looks like this: "variableName = true" (aka key/value pairs)
Expression.SetVar(data.name, "true");
// Don't ask why I'm using an external process to set variables using string expressions.
// It's a company proprietary thing.
string output;
Expression.Run(in condition, out output);
if (output.ToLower() == "true") return true;
else if (output.ToLower() == "false") return false;
else throw new Exception("Output is something other than true or false.");
}
This is why I'd like for Run to immediately return the output it receives from the process.
If not, I guess I could find a way for a delegate method to store the output in a global container and the GetConditionEval can just reach into that. I worry about race conditions though.
Side note:
Since I do expect the API that is contained in this C++ process to eventaully take other forms, spinning this up as a standalone process and invoking the API via stdin is really a stopgap for now so I don't have to convert thousands of lines of C++ code into C#.
SOLUTION:
I figured out a solution using the asynchronous method Matthew suggested while having a linear process of sending input and working immediately off the output in the same sequence. I reconfigured my wrapper class to queue each output received from the event listener. This sets up a pattern where I can call one method to send input, and then call another method right after to pop output data off the queue if any. I compensated for the fact that output data might not be avaliable immediately by simply waiting if the queue is empty and then moving forward once something is there. This unfortuately makes it a blocking call if it does have to wait, but it's the best I have so far. I also implemented a failsafe so it doesn't wait indefinately.
public class Expression {
System.Diagnostics.Process p = new();
System.Collections.Generic.Queue<string> outputQ = new();
public Expression () {
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.FileName = "C2E2.exe";
p.OutputDataReceived += (s, e) => {
outputQ.Enqueue(e.Data);
};
p.Start();
p.BeginOutputReadLine();
}
/// Returns custom exception object if error is encountered.
public GRLib.Exception Run (in string input) {
if (p == null) return GRLib.Exception.New("Expression Evaluator not operational.");
try {
p.StandardInput.WriteLine(input);
}
catch (Exception e) {
return GRLib.Exception.New(e.Message);
}
return null;
}
/// Returns error code 1 if timeout occured.
/// Timeout is represented in milliseconds.
/// Blocking call.
public GRLib.Exception GetOutput (out string output, int timeout = 2000) {
/// Wait for something to show in the queue.
/// Waits indefinitely if timeout is 0.
/// If anyone knows a better way to implement this waiting loop,
/// please let me know!
int timeWaited = 0;
while (outputQ.Count == 0) {
System.Threading.Thread.Sleep(100);
if (timeout != 0 && (timeWaited += 100) > timeout) {
output = "ERR";
return GRLib.Exception.New(1, "Get timed out.");
}
}
output = outputQ.Dequeue();
return null;
}
...
}
Example usage
Expression expression = new();
var e = expression.Run("3 > 2");
if (e != null) // Handle error
string output;
e = expression.GetOutput(out output);
if (e != null) // Handle error
// 'output' should now be 'true' which can then be used in other parts of this program.
While the event listener in a standalone fashion works great, I need the output from the process to be returned in the same stack where the input is given because this is going to be part of a more complex call graph.
The problem you're observing is due to the synchronous nature of Process.StandardOutput.ReadToEnd(). Instead, you should listen for your output asynchronously by setting Process.BeginOutputReadLine() and utilizing the Process.OutputDataReceived event.
Here is a quick example to get you started:
var p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = #"ConsoleApplication1.exe";
p.OutputDataReceived += (s, e) =>
{
Console.WriteLine(e.Data);
};
p.Start();
p.BeginOutputReadLine();
while (true)
{
var readLine = Console.ReadLine();
p.StandardInput.WriteLine(readLine);
}
And here is the c++ I used for ConsoleApplication1.exe:
int main()
{
std::cout << "Hello World!\n";
std::string input;
while (std::getline(std::cin, input)) {
std::cout << input << std::endl;
}
}
Running my example will print Hello World! and then proceed to parrot whatever else you enter into the console.
I'm using the GDAX API Websocket Stream to try and create a copy of the full LEVEL3 orderbook.
I've got a very simple implementation using WebSocketSharp and Im basically doing something like this.
private readonly WebSocket _webSocket = new WebSocket("wss://ws-feed.gdax.com");
_webSocket.OnMessage += WebSocket_OnMessage;
_webSocket.Connect();
_webSocket.Send(JsonConvert.SerializeObject(new BeginSubscriptionMessage()));
private void WebSocket_OnMessage(object sender, MessageEventArgs e)
{
var message = JsonConvert.DeserializeObject<BaseMessage>(e.Data);
switch (message.Type)
{
case "match": //A trade occurred between two orders.
MatchMessage matchMessage = JsonConvert.DeserializeObject<MatchMessage>(e.Data);
_receivedMatchQueue.Enqueue(matchMessage);
break;
case "received": //A valid order has been received and is now active. This message is emitted for every single valid order as soon as the matching engine receives it whether it fills immediately or not.
ReceivedMessage receivedMessage = JsonConvert.DeserializeObject<ReceivedMessage>(e.Data);
_receivedMessageQueue.Enqueue(receivedMessage);
break;
case "open": //The order is now open on the order book. This message will only be sent for orders which are not fully filled immediately. remaining_size will indicate how much of the order is unfilled and going on the book.
OpenMessage openMessage = JsonConvert.DeserializeObject<OpenMessage>(e.Data);
_receivedOpenQueue.Enqueue(openMessage);
break;
case "done": //The order is no longer on the order book. Sent for all orders for which there was a received message. This message can result from an order being canceled or filled.
DoneMessage doneMessage = JsonConvert.DeserializeObject<DoneMessage>(e.Data);
_receivedDoneQueue.Enqueue(doneMessage);
break;
case "change": //Existing order has been changed
ChangeMessage changeMessage = JsonConvert.DeserializeObject<ChangeMessage>(e.Data);
_receivedChangeQueue.Enqueue(changeMessage);
break;
case "activate": //Stop order placed
//Console.WriteLine("Stop Order Placed");
//ActivateMessage activateMessage = JsonConvert.DeserializeObject<ActivateMessage>(e.Data);
break;
case "subscriptions":
break;
case "ticker":
TickerMessage tickerMessage = JsonConvert.DeserializeObject<TickerMessage>(e.Data);
_receivedTickerQueue.Enqueue(tickerMessage);
break;
case "l2update":
break;
}
}
The problem I am running into is that when I look at the sequence numbers as received through both the RECEIVED and OPEN messages I can see they are not sequential which (based on the following information) suggests that messages are being skipped.
Basically you end up with something like this
Open Message SequenceId: 5359746354
Open Message SequenceId: 5359746358
Open Message SequenceId: 5359746361
Open Message SequenceId: 5359746363
Open Message SequenceId: 5359746365
Open Message SequenceId: 5359746370
Open Message SequenceId: 5359746372
I have tried testing this on Azure, just to make sure that it wasn't a bandwidth limitation on my end and the results were largely similar.
So given this, how is it possible to build a complete 'real-time' orderbook using the 'full' websocket stream if messages are dropped? Can I just safely ignore them? Or do I just somehow clear orphaned values?
Any advice from anyone having done something similar would be extremely appreciated.
Most likely messages are not dropped, you just have wrong impression of what "sequence" those sequence numbers represent.
As stated in api documentation
Most feed messages contain a sequence number. Sequence numbers are
increasing integer values for each product with every new message
being exactly 1 sequence number than the one before it.
So every channel has separate sequence number for each product (like ETH-USD), not for each message type (like "open" or "receive"). Suppose you subscribed to "full" channel, for products ETH-USD and ETH-EUR. Then you should expect sequence like this:
receive `ETH-EUR` X
open `ETH-EUR` X + 1
receive `ETH-USD` Y
done `ETH-EUR` X + 2
open `ETH-USD` Y + 1
For full channel, message types are: received, open, done, match, change, activate (note that ticker message belongs to different channel, so has separate sequence). So to ensure no messages are not skipped you need to track all those message types and ensure that last sequence number you received is exactly 1 less than new sequence number, per product (in case you subscribed to multiple products).
Proof code:
class Program {
private static readonly WebSocket _webSocket = new WebSocket("wss://ws-feed.gdax.com");
private static long _lastSequence = 0;
private static readonly HashSet<string> _expectedTypes = new HashSet<string>(
new[] { "received", "open", "done", "match", "change", "activate" });
static void Main(string[] args) {
var subMsg = "{\"type\": \"subscribe\",\"product_ids\": [\"ETH-USD\"],\"channels\": [\"full\"]}";
_webSocket.OnMessage += WebSocket_OnMessage;
_webSocket.Connect();
_webSocket.Send(subMsg);
Console.ReadKey();
}
private static void WebSocket_OnMessage(object sender, MessageEventArgs e) {
var message = JsonConvert.DeserializeObject<BaseMessage>(e.Data);
if (_expectedTypes.Contains(message.Type)) {
lock (typeof(Program)) {
if (_lastSequence == 0)
_lastSequence = message.Sequence;
else {
if (message.Sequence > _lastSequence + 1) {
Debugger.Break(); // never hits, so nothing is dropped
}
_lastSequence = message.Sequence;
}
}
}
}
}
public class BaseMessage {
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("product_id")]
public string ProductId { get; set; }
[JsonProperty("sequence")]
public long Sequence { get; set; }
}
**Note: Cross-posted at LabVIEW forums: http://forums.ni.com/t5/LabVIEW/C-VISA-wait-on-RQS/td-p/3122939
I'm trying to write a simple C# (.NET 4.0) program to control a Keithley 2400 SMU over VISA GPIB and I'm having trouble with getting the program to wait for the Service Request that the Keithley sends at the end of the sweep.
The sweep is a simple linear voltage sweep, controlled internally by the Keithley unit. I've got the unit set up to send a ServiceRequest signal at the end of the sweep or when compliance is reached.
I'm able to send the commands to the SMU and read the data buffer, but only if I manually enter a timeout between the sweep start command and the read data command.
One issue I'm having is that I'm quite new to C# - I'm using this project (porting parts of my LV code) to learn it.
Here is what I have so far for my C# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using NationalInstruments.VisaNS;
private void OnServiceRequest(object sender, MessageBasedSessionEventArgs e)
{
Console.WriteLine("Service Request Received!");
}
// The following code is in a class method, but
public double[,] RunSweep()
{
// Create the session and message-based session
MessageBasedSession mbSession = null;
Session mySession = null;
string responseString = null;
// open the address
Console.WriteLine("Sending Commands to Instrument");
instrAddr = "GPIB0::25::INSTR";
mySession = ResourceManager.GetLocalManager().Open(instrAddr);
// Cast to message-based session
mbSession = (MessageBasedSession)mySession;
// Here's where things get iffy for me... Enabling the event and whatnot
mbSession.ServiceRequest += new MessageBasedSessionEventHandler(OnServiceRequest);
MessageBasedSessionEventType srq = MessageBasedSessionEventType.ServiceRequest;
mbSession.EnableEvent(srq, EventMechanism.Handler);
// Start the sweep (SMU was set up earlier)
Console.WriteLine("Starting Sweep");
mbSession.Write(":OUTP ON;:INIT");
int timeout = 10000; // milliseconds
// Thread.Sleep(10000); // using this line works fine, but it means the test always takes 10s even if compliance is hit early
// This raises error saying that the event is not enabled.
mbSession.WaitOnEvent(srq, timeout);
// Turn off the SMU.
Console.WriteLine("I hope the sweep is done, cause I'm tired of waiting");
mbSession.Write(":OUTP OFF;:TRAC:FEED:CONT NEV");
// Get the data
string data = mbSession.Query(":TRAC:DATA?");
// Close session
mbSession.Dispose();
// For now, create a dummy array, 3x3, to return. The array after is the starting value.
double[,] dummyArray = new double[3, 3] {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
return dummyArray;
}
All the above is supposed to mimic this LabVIEW code:
So, any ideas on where I'm going wrong?
Thanks,
Edit:
After a little more fiddling, I've found that the Service Request function OnServiceRequest is actually fired at the right time ("Service Request Received!" is printed to the console).
It turns out that I need to enable the event as a Queue rather than a handler. This line:
mbSession.EnableEvent(srq, EventMechanism.Handler);
Should actually be:
mbSession.EnableEvent(srq, EventMechanism.Queue);
Source: The documentation under "Remarks". It was a pain to find the docs on it... NI needs to make it easier :-(.
With this change, I also don't need to create the MessageBasedSessionEventHandler.
The final, working code looks like:
rm = ResourceManager.GetLocalManager().Open("GPIB0::25::INSTR");
MessageBasedSession mbSession = (MessageBasedSession)rm;
MessageBasedSessionEventType srq = MessageBasedSessionEventType.ServiceRequest;
mbSession.EnableEvent(srq, EventMechanism.Queue); // Note QUEUE, not HANDLER
int timeout = 10000;
// Start the sweep
mbSession.Write(":OUTP ON;:INIT");
// This waits for the Service Request
mbSession.WaitOnEvent(srq, timeout);
// After the Service Request, turn off the SMUs and get the data
mbSession.Write(":OUTP OFF;:TRAC:FEED:CONT NEV");
string data = mbSession.Query(":TRAC:DATA?");
mbSession.Dispose();
What you're doing looks correct to me so it's possible that there's an issue with the NI library.
The only thing I can think of to try is waiting for "all events" instead of just "ServiceRequest." like this:
mbSession.WaitOnEvent(MessageBasedSessionEventType.AllEnabledEvents, timeout);
Note: that it doesn't look like you can "enable" all events (so don't change that part).
I also looked for some examples of how other people are doing Keithley sweeps and I found this and this(Matlab ex). As I suspected in both they don't use events to determine when the sweep is finished, but rather a "while loop that keeps polling the Keithley" (the first link actually uses threads, but it's the same idea). This makes me think that maybe that's your best bet. So you could just do this:
int timeout = 10000;
int cycleWait = 1000;
for (int i = 0; i < timeout / cycleWait; i++)
{
try
{
string data = mbSession.Query(":TRAC:DATA?");
break;
}
catch
{
Thread.Sleep(cycleWait);
}
}
(You may also have to check if data is null, but there has to be some way of knowing when the sweep is finished).
I have a windows service that has some performance counters in it. I have another application that monitors what the service is doing, including the performance counters that way everything is found and available in one place. However I seem to be having an issue with one of the performance counters of type RateOfCountsPerSecond32. If I look at the counters on Perfmon everything seems fine, this particular counter gives a reasonable value, but in my monitoring application the counter always provides 0 as its NextValue.
Below is the code i'm using to retrieve the counters from the given category:
PerformanceCounterCategory pcc = new PerformanceCounterCategory(comboBox1.SelectedItem.ToString());
string stats = string.Empty;
foreach (var counter in pcc.GetCounters())
{
stats += string.Format("{0}:\t {1} : {2}\r\n\r\n", counter.CounterName, counter.NextValue(), counter.RawValue );
}
lblTps.Text = stats;
This only seems to be an issue with this particular type of Counter.
Can anyone else notice anything wrong with this? (other than that I should be using a StringBuilder)
From MSDN:
If the calculated value of a counter depends on two counter reads, the first read operation returns 0.0.
You have to call NextValue() twice after creating this type of counter because it needs to buffer one sample before computing its first value. Subsequent calls to NextValue() will work as expected.
Here's what I found to get a Rate counter to return a rate via code. Regardless of the Sleep time in button2_click, it displays a value of 4, which is about right for a 250ms delay in the "loop" code. The trick appears to be to compare the current and previous raw values over the time between the two samples.
private void button2_Click(object sender, EventArgs e)
{
Task.Run(() => loop());
using (PerformanceCounter pc = new PerformanceCounter("TestCounters", "RateTest", true))
{
CounterSample a = pc.NextSample();
while (true)
{
Application.DoEvents();
System.Threading.Thread.Sleep(5000);
CounterSample b = pc.NextSample();
Single deltaTime = Convert.ToSingle(b.CounterTimeStamp / b.CounterFrequency - a.CounterTimeStamp/a.CounterFrequency);
Single deltaRaw = Convert.ToSingle(b.RawValue - a.RawValue);
label1.Text = (deltaRaw / deltaTime).ToString();
b = a;
}
}
}
private void loop()
{
while (true)
{
using (PerformanceCounter pc = new PerformanceCounter("TestCounters", "RateTest", false))
{
pc.Increment();
}
System.Threading.Thread.Sleep(250);
}
}
In my XNA game, I've got the game window and the console which is running a threaded Console.ReadLine() so the game doesn't hang while waiting for scripting input. I'm trying to get it where when the game window closes, the Console closes automatically, as well as the input to actually work (with the ability to print things out whilst waiting on input).
I've gotten it to close automatically now by using code from this question: How to add a Timeout to Console.ReadLine()?
However, when I press enter to the input, an ObjectDisposedException is thrown. Also, I'm stuck with using a timeout when I'd rather the thing be instant. How would I go about fixing this?
public class ConsoleInput
{
public bool running = true;
public void Run()
{
String input;
while (running)
{
input = ReadLine(500);
//stuff
}
}
string ReadLine(int timeoutms)
{
ReadLineDelegate d = Console.ReadLine;
IAsyncResult result = d.BeginInvoke(null, null);
result.AsyncWaitHandle.WaitOne(timeoutms);//timeout e.g. 15000 for 15 secs
if (result.IsCompleted)
{
string resultstr = d.EndInvoke(result);
Console.WriteLine("Read: " + resultstr);
return resultstr;
}
result.AsyncWaitHandle.Dispose();
return "";
}
delegate string ReadLineDelegate();
}
Which is called by:
LuaInput = new ConsoleInput();
LuaInputThread = new Thread(new ThreadStart(LuaInput.Run));
LuaInputThread.Start();
Thanks!
Have you tried setting the thread's
IsBackground = true; ? This will force it closed and will not allow the thread to block.