Windows 10-64.
I coded a small VB application last fall, to drive a "PR-705" serial device from the RS-232 port.
It worked flawlessly. Now, whenever I fire that code, the PR-705 is not responding so nicely?
I originally used a FTDI-based USB to RS232 adapter (Thunderlinx 1000) which worked perfect. I figured, the problem might have to do with the "driver"? So I added a PCI-Express serial port card from StarTech to my PC. The result: no improvement - same erratic behavior? Out of curiosity, this morning, I fired my trusty Windows HyperTerminal and it worked flawlessly (out of the PCI-e port)! So I know the trouble does not come from the device itself (sigh!) but somewhere in the chain of communications.
The problem I run into is as follows (hopefully, you can detect a "pattern"):
a) Open the serial port
b) Send a command to the port, in an ASCII string (e.g. "M1")
<- Device responds by sending data back
In order to obtain ALL data from device, however, I have to send additional commands:
c) "D2"
d) "D3"
e) "D4"
f) "D5"
When I run these commands from HyperTerminal, I get stellar behavior.
In my application, however, the additional commands ("D2", "D3", "D4" and "D5") are not getting THROUGH to the device, somehow? When I send "D2", for example, I get "XYZ" data back, which is OK.
But when I follow-up with "D3", I still get the same "XYZ" data back?
It is as though the new command ("D3") never reached the device?
My (ugly) workaround is to resend the same command over and THEN I get the new data (most of the time).
Here is some of my code:
Dim myPort As New IO.Ports.SerialPort("COM2") With {
.BaudRate = 9600,
.DataBits = 8,
.StopBits = IO.Ports.StopBits.One,
.Parity = IO.Ports.Parity.None,
.Handshake = IO.Ports.Handshake.RequestToSend,
.RtsEnable = True,
.DtrEnable = True,
.ReadTimeout = 1000000,
.WriteTimeout = 10000
}
myPort.Open()
myPort.WriteLine("M1")
myPort.WriteLine("D2")
Incoming = myPort.ReadLine()
myPort.WriteLine("D2")
Incoming = myPort.ReadLine()
myPort.WriteLine("D3")
Incoming = myPort.ReadLine()
myPort.WriteLine("D4")
Incoming = myPort.ReadLine()
myPort.WriteLine("D5")
Incoming = myPort.ReadLine()
I know the TimeOut value is "extreme" but the device can take up to 15 minutes to reply, depending on the circumstances. I can't close the port before the device responds back otherwise I'll get an error, something to do with CTS, and then device automatically reboots -- not ideal. I'm not a RS-232 expert but I do the best I can with the little knowledge I have.
Found a partial answer to my serial port problem but this solution is not without its own problems. I found some c# code I adapted where the serial port "Received" is separated into its own "event". This works very well. As you'll see in the code below, it does the job. But now I'm facing the question of how to go about "successively" polling the port to get all the data returned by the instrument?
Here's the c# code first:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
namespace WindowsApplication14
{
public partial class Form1 : Form
{
string Operation, MesureM1, MesureD2, MesureD3, MesureD4;
SerialPort _serialPort;
// delegate is used to write to a UI control from a non-UI thread
private delegate void SetTextDeleg(string text);
public Form1()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
try
{
if (!_serialPort.IsOpen)
_serialPort.Open();
_serialPort.Write("PR705\r\n");
}
catch (Exception ex)
{
MessageBox.Show("Error opening serial port :: " + ex.Message, "Error!");
}
}
private void Form1_Load(object sender, EventArgs e)
{
_serialPort = new SerialPort("COM2", 9600, Parity.None, 8, StopBits.One);
_serialPort.Handshake = Handshake.RequestToSend;
_serialPort.RtsEnable = true;
_serialPort.DtrEnable = true;
_serialPort.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
_serialPort.ReadTimeout = 500;
_serialPort.WriteTimeout = 500;
_serialPort.Open();
_serialPort.Write("PR705\r\n");
}
private void btnM1_Click(object sender, EventArgs e)
{
Operation = "M1";
_serialPort.Write("M1\r\n"); // 0000,111,3.896e+002,0.3371,0.3563
Thread.Sleep(500);
}
private void btnD2_Click(object sender, EventArgs e)
{
Operation = "D2";
_serialPort.Write("D2\r\n");
Thread.Sleep(500);
}
private void btnD3_Click(object sender, EventArgs e)
{
Operation = "D3";
_serialPort.Write("D3\r\n");
Thread.Sleep(500);
}
private void btnD4_Click(object sender, EventArgs e)
{
Operation = "D4";
_serialPort.Write("D4\r\n");
Thread.Sleep(500);
}
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(500);
string data = _serialPort.ReadLine();
this.BeginInvoke(new SetTextDeleg(si_DataReceived), new object[] { data });
}
private void si_DataReceived(string data)
{
String Result = data.Trim();
textBox1.Text = Result;
switch (Operation)
{
case "M1":
MesureM1= Result; // MesureBase = "0000,111,3.884e+002,0.3377,0.3570"
break;
case "D2":
MesureD2 = Result; // MesureD2 = "0000,111,3.674e+002,3.884e+002,3.322e+002"
break;
case "D3":
MesureD3 = Result; // MesureD3 = "0000,111,3.884e+002,0.2044,0.4862"
break;
case "D4":
MesureD4 = Result; //
break;
default:
break;
}
}
}
}
In my main form, I have four buttons and a textbox.
Button M1 is used to take a measurement (send "M1" command to the instrument).
Buttons D2, D3 and D4 are used to retrieve data from the instrument.
In my old VB application, I used code like this, to successively retrieve data from the instrument:
myPort.WriteLine("M1")
myPort.WriteLine("D2")
Incoming = myPort.ReadLine()
myPort.WriteLine("D3")
Incoming = myPort.ReadLine()
myPort.WriteLine("D4")
Incoming = myPort.ReadLine()
That was but I don't know how to accomplish the same thing using the 'separate' approach in c#? I tried lumping the read operations in the same "event" sub as the M1 button, like this :
private void btnM1_Click(object sender, EventArgs e)
{
Operation = "M1";
_serialPort.Write("M1\r\n"); // 0000,111,3.896e+002,0.3371,0.3563
Thread.Sleep(500);
Operation = "D2";
_serialPort.Write("D2\r\n");
Thread.Sleep(500);
Operation = "D3";
_serialPort.Write("D3\r\n");
Thread.Sleep(500);
Operation = "D4";
_serialPort.Write("D4\r\n");
Thread.Sleep(500);
}
But it does not work, I only get the "last" serial port "Read", the D4. The code never goes through D2 and D3.
How would you suggest I go about this? I have not shown you D5 yet… The D5 operation is the most involved as I have to do "two reads", one for one piece of data and then 201 successive reads, to retrieve wavelength data, like this :
myPort.WriteLine("D5")
Incoming = myPort.ReadLine()
Temp = Split(Incoming, ",")
PeakWL = Convert.ToDouble(Temp(2))
For i = 1 To 201
Incoming = myPort.ReadLine()
Temp = Split(Incoming, ",")
nmValue(i) = CDbl(Temp(0))
SpectralValue(i) = CDbl(Temp(1))
Next
I'm going to try to solve my problem myself but I would appreciate suggestions.
Related
I'm having an issue with duplicated content from redirected output.
In my forms I have two buttons: Run and Clear.
public partial class BatchRun : Form
{
Process process = new Process();
public BatchRun()
{
InitializeComponent();
}
private void RunBTN_Click(object sender, EventArgs e)
{
//initiate the process
this.process.StartInfo.FileName = sMasterBATname;
this.process.StartInfo.UseShellExecute = false;
this.process.StartInfo.CreateNoWindow = true;
this.process.StartInfo.RedirectStandardOutput = true;
this.process.OutputDataReceived += new DataReceivedEventHandler(StandardOutputHandler);
this.process.StartInfo.RedirectStandardInput = true;
this.process.Start();
this.process.BeginOutputReadLine();
}
public void StandardOutputHandler(object sender, DataReceivedEventArgs outLine)
{
BeginInvoke(new MethodInvoker(() =>
{
Label TestLBL = new Label();
TestLBL.Text = text.TrimStart();
TestLBL.AutoSize = true;
TestLBL.Location = new Point(10, CMDpanel.AutoScrollPosition.Y + CMDpanel.Controls.Count * 20);
CMDpanel.Controls.Add(TestLBL);
CMDpanel.AutoScrollPosition = new Point(10, CMDpanel.Controls.Count * 20);
}));
}
private void ClearBTN_Click(object sender, EventArgs e)
{
CMDpanel.Controls.Clear();
this.process.CancelOutputRead();
this.process.Close();
this.process.Refresh();
}
}
This works great if I want to run process only once i.e. close the forms once process has completed.
However, I need to allow user to rerun the same process or run a new one hence I have added a clear button the clear various controls etc.
The problem I'm having is that after clicking clear button, I want to click run button again without closing which should then run the sMAsterBAT file(CMD).
StandardOutputHandler seems to be including content of the previous run as well as the new one resulting in duplicated labels in my CMDpanel.
Is this stored in some kind of buffer? If so, How do i clear it to allow me a rerun?
Could someone explain why this is happening and how to resolve it please.
Spoke to someone at work who fixed it for me. So easy lol
private void ClearBTN_Click(object sender, EventArgs e)
{
CMDpanel.Controls.Clear();
this.process.CancelOutputRead();
this.process.Close();
this.process.Refresh();
this.process = new Process(); // this line resolved my issue!!
}
}
I am new to UCMA and I am learning as I go through examples. I am trying to build 2 Lync clients A and B with the scenario as follows,
A calls B
B answers
A plays audio
B records it using Recorder.
I am stuck at trying to record the call at B. For B its an incoming call. I need to attach the audiovideoflow to the recorder, but I am not sure on how to do it. I will appreciate any help.
Apologies on the unformatted code, I am not sure how to format it properly, I tried.
Thanks.
Kris
Client B Code:
Accepts an incoming call
Records the media received in the incoming call. ***This is the part I have trouble
using System;
using System.Threading;
using Microsoft.Rtc.Collaboration;
using Microsoft.Rtc.Collaboration.AudioVideo;
using Microsoft.Rtc.Signaling;
using Microsoft.Rtc.Collaboration.Lync;
namespace Microsoft.Rtc.Collaboration.LyncUAS
{
public class LyncUAS
{
#region Locals
private LyncUASConfigurationHelper _helper;
private UserEndpoint _userEndpoint;
private AudioVideoCall _audioVideoCall;
private AudioVideoFlow _audioVideoFlow;
private Conversation _incomingConversation;
//Wait handles are only present to keep things synchronous and easy to read.
private AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
private EventHandler<AudioVideoFlowConfigurationRequestedEventArgs> _audioVideoFlowConfigurationRequestedEventHandler;
private EventHandler<MediaFlowStateChangedEventArgs> _audioVideoFlowStateChangedEventHandler;
private AutoResetEvent _waitForAudioVideoCallEstablishCompleted = new AutoResetEvent(false);
private AutoResetEvent _waitForAudioVideoFlowStateChangedToActiveCompleted = new AutoResetEvent(false);
private AutoResetEvent _waitForPrepareSourceCompleted = new AutoResetEvent(false);
#endregion
#region Methods
/// <summary>
/// Instantiate and run the DeclineIncomingCall quickstart.
/// </summary>
/// <param name="args">unused</param>
public static void Main(string[] args)
{
LyncUAS lyncUAS = new LyncUAS();
lyncUAS.Run();
}
private void Run()
{
string filename = "received.wma";
_helper = new LyncUASConfigurationHelper();
// Create a user endpoint, using the network credential object
// defined above.
_userEndpoint = _helper.CreateEstablishedUserEndpoint("Lync UAS" /*endpointFriendlyName*/);
_userEndpoint.RegisterForIncomingCall<AudioVideoCall>(On_AudioVideoCall_Received);
Console.WriteLine("Waiting for incoming call...");
_autoResetEvent.WaitOne();
Console.WriteLine("came after call is connected");
//start recording for audio.
Recorder recorder = new Recorder();
recorder.StateChanged += new EventHandler<RecorderStateChangedEventArgs>(recorder_StateChanged);
recorder.VoiceActivityChanged += new EventHandler<VoiceActivityChangedEventArgs>(recorder_VoiceActivityChanged);
//**********This is the issue, currently _audioVideoFlow is null, it is not attached to the flow
//So this will fail, how to attach _audioVideoFlow to an incoming call ?? HELP !!!
// recorder.AttachFlow(_audioVideoFlow); ------------> HELP!
WmaFileSink sink = new WmaFileSink(filename);
recorder.SetSink(sink);
recorder.Start();
Console.WriteLine("Started Recording ...");
_autoResetEvent.WaitOne();
recorder.Stop();
Console.WriteLine("Stopped Recording ...");
recorder.DetachFlow();
Console.WriteLine("Exiting");
Thread.Sleep(2000);
}
private void audioVideoFlow_StateChanged(object sender, MediaFlowStateChangedEventArgs e)
{
Console.WriteLine("Flow state changed from " + e.PreviousState + " to " + e.State);
//When flow is active, media operations can begin
if (e.State == MediaFlowState.Active)
{
// Flow-related media operations normally begin here.
_waitForAudioVideoFlowStateChangedToActiveCompleted.Set();
}
// call sample event handler
if (_audioVideoFlowStateChangedEventHandler != null)
{
_audioVideoFlowStateChangedEventHandler(sender, e);
}
}
void recorder_VoiceActivityChanged(object sender, VoiceActivityChangedEventArgs e)
{
Console.WriteLine("Recorder detected " + (e.IsVoice ? "voice" : "silence") + " at " + e.TimeStamp);
}
void recorder_StateChanged(object sender, RecorderStateChangedEventArgs e)
{
Console.WriteLine("Recorder state changed from " + e.PreviousState + " to " + e.State);
}
void On_AudioVideoCall_Received(object sender, CallReceivedEventArgs<AudioVideoCall> e)
{
//Type checking was done by the platform; no risk of this being any
// type other than the type expected.
_audioVideoCall = e.Call;
// Call: StateChanged: Only hooked up for logging, to show the call
// state transitions.
_audioVideoCall.StateChanged += new
EventHandler<CallStateChangedEventArgs>(_audioVideoCall_StateChanged);
_incomingConversation = new Conversation(_userEndpoint);
Console.WriteLine("Call Received! From: " + e.RemoteParticipant.Uri + " Toast is: " +e.ToastMessage.Message);
_audioVideoCall.BeginAccept(
ar =>
{
try {
_audioVideoCall.EndAccept(ar);
Console.WriteLine("Call must be connected at this point. "+_audioVideoCall.State);
_autoResetEvent.Set();
} catch (RealTimeException ex) { Console.WriteLine(ex); }
}, null);
}
//Just to record the state transitions in the console.
void _audioVideoCall_StateChanged(object sender, CallStateChangedEventArgs e)
{
Console.WriteLine("Call has changed state. The previous call state was: " + e.PreviousState +
" and the current state is: " + e.State);
if (e.State == CallState.Terminated)
{
Console.WriteLine("Shutting down");
_autoResetEvent.Set();
_helper.ShutdownPlatform();
}
}
#endregion
}
}
I think I have figured out what's not quite right here.
Your Code
// Create a user endpoint, using the network credential object
// defined above.
_userEndpoint = _helper.CreateEstablishedUserEndpoint("Lync UAS" /*endpointFriendlyName*/);
_userEndpoint.RegisterForIncomingCall<AudioVideoCall>(On_AudioVideoCall_Received);
Console.WriteLine("Waiting for incoming call...");
_autoResetEvent.WaitOne();
Console.WriteLine("came after call is connected");
//start recording for audio.
Recorder recorder = new Recorder();
recorder.StateChanged += new EventHandler<RecorderStateChangedEventArgs>(recorder_StateChanged);
recorder.VoiceActivityChanged += new EventHandler<VoiceActivityChangedEventArgs>(recorder_VoiceActivityChanged);
//**********This is the issue, currently _audioVideoFlow is null, it is not attached to the flow //So this will fail, how to attach _audioVideoFlow to an incoming call ?? HELP !!!
// recorder.AttachFlow(_audioVideoFlow); ------------> HELP!
Looking good so far. I'm assuming you're establishing and such in your CreateEstablishedUserEndpoint method, but I'm not seeing where you're getting the value for _audioVideoFlow.
I'm guessing you might be doing it elsewhere, but on the off chance that's actually where you're running into problems, here's that bit:
Simplest pattern to get AVFlow
public static void RegisterForIncomingCall(LocalEndpoint localEndpoint)
{
localEndpoint.RegisterForIncomingCall
<AudioVideoCall>(IncomingCallDelegate);
}
private static void IncomingCallDelegate(object sender, CallReceivedEventArgs<AudioVideoCall> e)
{
e.Call.AudioVideoFlowConfigurationRequested += IncomingCallOnAudioVideoFlowConfigurationRequested;
}
private static void IncomingCallOnAudioVideoFlowConfigurationRequested(object sender, AudioVideoFlowConfigurationRequestedEventArgs e)
{
AudioVideoFlow audioVideoFlow = e.Flow; // <--- There's your flow, gentleman.
}
Now, instead of registering for your incoming call, just call RegisterForIncomingCall(_userEndpoint);.
Your AVFlow will be hanging off e.Flow above, you could then pass that into your recorder: recorder.AttachFlow(e.Flow) or simply assign the flow to a field in your class and autoResetEvent.WaitOne(); and set that up where you're setting that up now.
Obviously this is a pretty naive implementation. A lot can go wrong in those few lines of code (exception handling/static event handler memory leak comes immediately to mind); don't forget to wire up events related to status changes on the conversation/call and endpoints, as well as any of the recovery related items.
I have a code to access multiple wcf server from one client with multiple instances. if any connection lost between this, having faulted/closed event trigger function to hande this.
((ICommunicationObject)notificationProviderClient).Faulted += new EventHandler(myHost_Faulted);
((ICommunicationObject)notificationProviderClient).Closed += new EventHandler(myHost_Closed);
void myHost_Faulted(object sender, EventArgs e)
{
}
void myHost_Closed(object sender, EventArgs e)
{
}
The above function get called, if any connection get fault/closed.
In this scenarion how to find which wcf server connection lost with the clent? is there any possible to find this or we have to go for another method to handle this?
to find remote address of server during connection lost, use this on client side
this.notificationProviderClient.InnerDuplexChannel.Faulted += new EventHandler(myHost_Faulted);
void myHost_Faulted(object sender, EventArgs e) {
IContextChannel channel = sender as IContextChannel;
if (channel != null)
{
var remoteAddrs = a1.RemoteAddress;
}
}
My project is about Remoting and i want to add a webcam component to it. Here it goes: I have 3 project in my solution... Client, Server, Remote.dll. In Remote.dll is a common class which has methods works in server machine. When i call these methods from Client it executes in server side. So now my question is i put the code of Webcam in remote.dll and it has an event called "video_NewFrame" which it works everytime when webcam catch an image. But i cant reach to the images from my Client side because when code drops to this event it executes infinitely
and my timer in Client side doesnt work as well. I tried to assing image to my global variable but whenever code goes to client and comes to Remote.dll again my variable is null...
How can i reach simultaneously captured images from my client? here is my code:
(i use AForge framework for webcam)
private bool DeviceExist = true;
private FilterInfoCollection videoDevices;
private VideoCaptureDevice videoSource = null;
public bool WebCamStart(int DeviceIndex)
{
if (DeviceExist)
{
videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
//string myDevice = videoDevices[0].Name;
videoSource = new VideoCaptureDevice(videoDevices[0].MonikerString);
videoSource.NewFrame += new NewFrameEventHandler(video_NewFrame);
CloseVideoSource();
videoSource.DesiredFrameSize = new Size(640, 480);
//videoSource.DesiredFrameRate = 10;
videoSource.Start();
return true;
}
else return false;
}
public Bitmap lastImg;
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
Bitmap img = (Bitmap)eventArgs.Frame.Clone();
//in executes infinitely when execution comes here and i cant reach from Cliend side...
}
public string getFPS()
{
return videoSource.FramesReceived.ToString();
}
public void CloseVideoSource()
{
if (!(videoSource == null))
if (videoSource.IsRunning)
{
videoSource.SignalToStop();
videoSource.Stop();
videoSource = null;
}
}
public string getCamList()
{
string result = "No Device Found";
try
{
videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
//comboBox1.Items.Clear();
if (videoDevices.Count == 0)
throw new ApplicationException();
DeviceExist = true;
foreach (FilterInfo device in videoDevices)
{
//comboBox1.Items.Add(device.Name);
result = device.Name;
return result;
}
//comboBox1.SelectedIndex = 0; //make dafault to first cam
}
catch (ApplicationException)
{
DeviceExist = false;
//comboBox1.Items.Add("No capture device on your system");
return "No capture device on your system";
}
return result;
}
// and my client side...
private void timerWebCam_Tick(object sender, EventArgs e)
{
//lblFPS.Text ="Device Running... " + remObj.getFPS() + " FPS";
pictureBox1.Image = remObj.lastImg;
}
I have WCF WebService for Silverlight client.
Let's say client click "Make building".
Service will receive new task, and star counting time, until it's ready to make action (i.e add to database).
Time - how much time task will need to complete (i.e to construct building).
The point is how to delay task for the certain amount of time.
Also, is there a way to stream time from server to client ?
I have setup this:
[OperationContract]
public void GetTime()
{
foreach (IDuplexClient client in _clientDic.Values)
{
client.ShowStatus(DateTime.Now);
}
}
[OperationContract]
public void Login()
{
string clientID = OperationContext.Current.Channel.SessionId;
IDuplexClient client = OperationContext.Current.GetCallbackChannel<IDuplexClient>();
_clientDic.Add(clientID, client);
}
IDuplexClient:
[OperationContract(IsOneWay = true)]
void ShowStatus(DateTime status);
And client side:
_client.LoginAsync();
_client.GetTimeAsync();
_client.ShowStatusReceived += new EventHandler<ShowStatusReceivedEventArgs>(_client_ShowStatusReceived);
void _client_ShowStatusReceived(object sender, ShowStatusReceivedEventArgs e)
{
label1.Content = e.status.ToString();
}
It's working.. For first run. But time doesn't get refreshed, which is not what I want.
As well, after few forced refresh in browser, time stop to show at all.
public partial class MainPage : UserControl
{
Service1Client _client;
int time = 10000;
public MainPage()
{
InitializeComponent();
_client = new Service1Client(new PollingDuplexHttpBinding { DuplexMode = PollingDuplexMode.SingleMessagePerPoll, OpenTimeout = TimeSpan.FromMinutes(10), ReceiveTimeout = TimeSpan.FromMinutes(10) },
new EndpointAddress("http://localhost:44544/Service1.svc"));
_client.LoginAsync();
_client.DoWorkCompleted += new EventHandler<DoWorkCompletedEventArgs>(_client_DoWorkCompleted);
_client.DoWorkAsync();
_client.AddNewTaskAsync("testTaskzor", time);
_client.GetTimeAsync();
//_client.AddNewTaskCompleted += new EventHandler<AddNewTaskCompletedEventArgs>(_client_AddNewTaskCompleted);
_client.ShowStatusReceived += new EventHandler<ShowStatusReceivedEventArgs>(_client_ShowStatusReceived);
}
void _client_ShowStatusReceived(object sender, ShowStatusReceivedEventArgs e)
{
label1.Content = e.status.ToString();
}
void _client_DoWorkCompleted(object sender, DoWorkCompletedEventArgs e)
{
//label1.Content = e.Result;
}
}
That' entire client code.
Although I finally fixed and time is streaming properly to client (it wa surpsingly easy it was enough to enlose foreach with while(true) statment, at least for now).
But on other side. When I close browser, and open it again, nothing show up. As well as after I refresh it, time do not show up at all.
The easiest way would be to implement the delay on the client side. You can't really delay a RESTful service like WCF without breaking the model.