I'm building a TCP server in UWP to receive and send data from an NodeMCU (Arduino based) to an windows PC (later it will be a Raspberry Pi with Windows 10 IOT).
When setting up and startig the server there is no problem, and also the NodeMCU is changing the status to "connected" - it seems that the connection between PC and NodeMCU works just fine.
When receiving the data, I get an exception in the event handler, becaust the size (variable size in the code below) of the package is read as "1414743380" which is way too much and so I get an exception "Insufficient memory to continue the execution of the program." at line "await reader.LoadAsync((uint)size);" which seems just right.
The variable payloadsize contains this:
The question is why do I get such a package size and where does it come from?
Is there something wrong on the NodeMCU / Arduino side?
I used the code for the TCP Server from the Microsoft Example.
Starting the server:
public async Task<bool> StartListeningAsync()
{
if (_localSocket == null)
{
_localSocket = new StreamSocketListener();
_localSocket.ConnectionReceived += LocalSocketConnectionReceived;
await _localSocket.BindServiceNameAsync(CommunicationPort);
return true;
}
return false;
}
Event handler for TCP messages:
private async void LocalSocketConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
using (var reader = new DataReader(args.Socket.InputStream))
{
reader.InputStreamOptions = InputStreamOptions.None;
// Read the length of the payload that will be received.
byte[] payloadSize = new byte[(uint)BitConverter.GetBytes(0).Length];
await reader.LoadAsync((uint)payloadSize.Length);
reader.ReadBytes(payloadSize);
// Read the payload.
int size = BitConverter.ToInt32(payloadSize, 0);
byte[] payload = new byte[size];
await reader.LoadAsync((uint)size);
reader.ReadBytes(payload);
}
}
the message from the Arduino is this (from Wireshark):
EDIT: Full message description
Related
I have previously posted regarding the issue but haven't really found the problem.
Recently, I found this post regarding detachbuffer and wonder if this could be the reason i encounter the problem.
I have my UART for RS485 using a FTDI USB to 485 cable connected to Raspberry Pi on Windows IoT Core.
I set a dispatchertimer at every 1second to transmit polling to respective field devices.
I am able to tx and rx the 485 data with no problem.
However, after the polling loop to about 20 times it just crash and exited the debug mode.
I used try & catch to trap the exception but could not get it. However, i manage to read the error message at the debug output pane - The program [0xBB0] PwD.exe' has exited with code -1073741811 (0xc000000d).
I wonder if i repeatedly transmit polling, dataWriteObject.DetachBuffer(); would cause the problem?
Thanks.
snippets of my code are as follow;
private void PollTimer_Tick(object sender, object e)
{
if (pollCounter <= maxDevice)
{
var a = pollCounter | 0x80;
pollCounter++;
TxAdr = Convert.ToByte(a);
TxCmd = TxPoll;
TxPollCard();
}
else pollCounter = 0;
}
private async void TxPollCard()
{
if (serialPort != null)
{
List<byte> data = new List<byte>();
data.Add(TxHeader);
data.Add(TxAdr);
data.Add(TxCmd);
TxChkSum = 0;
foreach (byte a in data)
{
TxChkSum += a;
}
TxChkSum = (byte)(TxChkSum - 0x80);
data.Add(TxChkSum);
try
{
// Create the DataWriter object and attach to OutputStream
dataWriteObject = new DataWriter(serialPort.OutputStream);
dataWriteObject.WriteBytes(data.ToArray());
Task<UInt32> storeAsyncTask;
// Launch an async task to complete the write operation
storeAsyncTask = dataWriteObject.StoreAsync().AsTask();
UInt32 bytesWritten = await storeAsyncTask;
dataWriteObject.DetachBuffer();
}
catch (Exception ex)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
MainStatusDisplay.Text = ex.Message;
});
}
}
else
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
MainStatusDisplay.Text = "No UART port found";
});
}
}
Update:
Additional test i did which i disconnect the devices & keep transmitting without expecting response, it didn't crash.
On the other hand, i stop transmit and only listen to the 485 bus, it didn't crash either.
I'm working on porting functionality from an example Windows Forms App to a Xamarin.Forms UWP app where it should write to & read from a bluetooth device on a COM port. I have it working fine most of the time, but intermittently the UWP app will get itself into a state where any call to dataReader.LoadAsync will trigger the exception:
Exception thrown at 0x74AF1A62 (KernelBase.dll) in MyApp.UWP.exe: WinRT originate error - 0x800710DD : 'The operation identifier is not valid.'.
Exception thrown: 'System.Runtime.InteropServices.COMException' in MyApp.UWP.exe
WinRT information: The operation identifier is not valid.
Restarting the app or Visual Studio does not help, the issue persists.
The last time it happened it did not appear to impact my dataWriter writing to the device, only the subsequent read.
All of the code is in the UWP project.
private DataReader _dataReader;
private DataWriter _dataWriter;
private SerialDevice _currentSerialDevice;
private async Task ReadAsync(SerialDevice serialDevice)
{
const uint ReadBufferLength = 1024;
if (_dataReader == null)
{
_dataReader = new DataReader(_currentSerialDevice.InputStream) { InputStreamOptions = InputStreamOptions.Partial };
}
uint bytesRead = await _dataReader.LoadAsync(ReadBufferLength); // <- exception here
if (bytesRead > 0)
{
var vals = new byte[bytesRead];
_dataReader.ReadBytes(vals);
DoStuffWithBytes(vals);
}
}
The serial device is chosen from a list in the application.
// Get serial devices
DeviceInformationCollection serialDeviceCollection = await DeviceInformation.FindAllAsync(SerialDevice.GetDeviceSelector());
// Load serial device from user choosing a device from serialDeviceCollection
public async void ConnectToSerialDevice(DeviceInformation device)
{
_currentSerialDevice = await SerialDevice.FromIdAsync(device.Id);
_currentSerialDevice.BaudRate = 115200;
_currentSerialDevice.Parity = SerialParity.None;
_currentSerialDevice.DataBits = 8;
_currentSerialDevice.StopBits = SerialStopBitCount.One;
_currentSerialDevice.Handshake = SerialHandshake.RequestToSend;
}
Code for writing to the device, which works even when it gets in the odd state:
private async Task WriteToDevice(byte[] outBuffer)
{
if (_currentSerialDevice != null)
{
if (_dataWriter == null)
{
_dataWriter = new DataWriter(_currentSerialDevice.OutputStream);
}
_dataWriter.WriteBytes(outBuffer);
await _dataWriter.StoreAsync();
}
}
I've tried things like flushing the data writer, recreating the datawriter & datareaders each time, but I get the same error nonetheless and cannot read anything from the device. In normal operation I am able successfully read the bytes I'm expecting (even when there are no bytes to be read, it "reads" 0 bytes) and can output this result with no exception.
The curious thing about it all is that not only does the original Windows Forms app work fine (with the same bluetooth device) even after it gets in this state, but just opening the port and reading from the device (in the old app) actually fixes the issue in the UWP app for a time, allowing me to read from the device again.
This may be related to asynchronous methods. You can try this:
var task = await _dataReader.LoadAsync(ReadBufferLength);
task.AsTask().Wait();
uint bytesRead = task.GetResults();
For asynchronous methods (such as DataReader.LoadAsync), events occur on the UI thread and can only be triggered once, and can only continue to be triggered after the previous asynchronous method is completed. Your question may be related to this.
In the end it turns out that the cause of the problem was the LoadAsync method hanging while waiting to fill the entire buffer (1024 bytes) despite the InputStreamOptions being set to Partial. The exception I was getting was somewhat unrelated and was to do with the asynchronous method not working properly (the method was being called again when the first task had not completed).
The fix was a combination of adding a ReadTimeout to the SerialDevice:
_currentSerialDevice.ReadTimeout = TimeSpan.FromMilliseconds(500);
and also wrapping the LoadAsync task itself in a timed cancellation token:
using (var cts = new CancellationTokenSource(500))
{
var task = _dataReader.LoadAsync(ReadBufferLength);
var readTask = task.AsTask(cts.Token);
uint bytesRead = await readTask;
}
This allowed the LoadAsync method to complete both when the device had less than 1024 bytes to consume (handled by the SerialDevice.ReadTimeout) and also when the device had 0 bytes to consume (handled by the CancellationToken).
I'm still not sure why running the win forms app fixed the issue for a time, possibly it was setting the ReadTimeout (while my UWP app was not) and this was persisting on the serial port in some way.
I am developing an Xamarin application (currently focused on Android but will eventually support iOS) that communicates via bluetooth to a nearby C# console application. They both act as a client/server as they need to send messages back and forth.
The read code for the Android implementation is as follows:
byte[] buffer = new byte[1024];
int bytes;
// Listen to the input stream while connected
while (true)
{
try
{
// Read from the InputStream
bytes = this.InStream.Read(buffer, 0, buffer.Length);
var message = new Java.Lang.String(buffer, 0, bytes);
// TODO: Notify the UI of the message
}
catch (Java.IO.IOException e)
{
// TODO: Show some error
}
}
The problem with the above code is that since I am only reading a buffer size of 1024 I am only getting partial messages for anything over 1024 bytes. Using a DataWriter (as shown below in the console application) would be ideal for me, but it is not available for an Android implementation using Xamarin.
The write code for the Android application is as follows:
try
{
this.OutStream.Write(buffer, 0, buffer.Length);
// TODO: Notify the UI
}
catch (Java.IO.IOException e)
{
// TODO: Show some error
}
Now, for the console application the read code is as follows:
// socket here is a Windows.Networking.Sockets.StreamSocket
var reader = new DataReader(socket.InputStream);
while (true)
{
try
{
uint readLength = await reader.LoadAsync(sizeof(uint));
uint currentLength = reader.ReadUInt32();
await reader.LoadAsync(currentLength);
string message = reader.ReadString(readLength);
Console.WriteLine("Message received: " + message);
}
catch (Exception e)
{
// TODO: Show some error
}
}
The problem here, is the the await reader.LoadAsync(currentLength) is never resolved. I am guessing that is because the Android app is only sending the message and not the length, then the message. I can get rid of the second await and use a buffer size of 1024 as I am in the Android application, but I will again be getting partial messages. Simply increasing the buffer size to get a bigger message is another option, but that sounds incorrect to me.
And the write code for the console application:
// socket here is a Windows.Networking.Sockets.StreamSocket
var writer = new DataWriter(socket.OutputStream)
writer.WriteUInt32((uint)message.Length);
writer.WriteString(message);
try
{
await writer.StoreAsync();
}
catch (Exception exception)
{
// TODO: Show some error
}
I am unsure of the changes I need to make to be able to send and receive complete messages back and forth on both applications. As I stated before, the implementation of the console application will need to support iOS bluetooth communication as well.
On my Xamarin.Android app I'm sending udp broadcast message to find my servers on the local LAN.
My servers then return the MachineName they run on which I display in a ListView on my app in the form of
<MachineName> - <Ip address>
This all works well on the first time, however from the second time on all it reads is empty bytes.
The number of bytes it reads is correct but they are all zero.
Here is the code:
private static void ListenForBroadcastResponses()
{
udp.BeginReceive(OnBroadcastResponse, new object());
}
private static void OnBroadcastResponse(IAsyncResult ar)
{
// Recieve the message
IPEndPoint ip = new IPEndPoint(IPAddress.Any, port);
byte[] bytes = udp.EndReceive(ar, ref ip);
// Decode it
string message = Encoding.ASCII.GetString(bytes);
// If message is the awaited message from client or from the awaited port
if (ip.Port == port) //|| message == BRDCAST_ANSWER)
{
// Raise server found event
var handler = ServerFound;
if (handler != null)
handler(null, new ServerEventArgs
{
Server = new Server(message, ip.Address)
});
}
// Start listening again
ListenForBroadcastResponses();
}
Debug screenshots:
First time full bytes are recieved:
Second time and on bytes are empty:
What is wrong here?
Eventually I figured it out. It seems to be a bug caused by multiple threads trying to listen simultaneously (see this post) to replies so I'll post my solution:
I've added a RecieveTimeout of X seconds to the UdpClient.
Upon timeout, I execute an EndRecieve and Close method calls.
This will trigger the callback passed in BeginRecieve to execute so I've added a check to the callback method if the client is still open
if (udp.Client != null) ...
It fixed things for me, so hopefully it will help others
I'm writing an application for windows phone and I need to communicate with a server and transmit data. The SERVER is written in C++ and I cannot modify it. The CLIENT is what I have to write. The Server is designed such that the client connect to it and transmit data. The connection remains open for all the transmission. By writing my code in C# I am able to receive data from the server but after the first receive, the data that I read in the buffer are alway the same. So I need a way to flush the input buffer so I can receive the new data (data are sent continuously). I'm using the class defined in here:
http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202858%28v=vs.105%29.aspx
thanks a lot !!
I used this code for Receiving in the SocketClient.cs :
public string Receive()
{
string response = "Operation Timeout";
// We are receiving over an established socket connection
if (_socket != null)
{
// Create SocketAsyncEventArgs context object
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = _socket.RemoteEndPoint;
// Setup the buffer to receive the data
socketEventArg.SetBuffer(new Byte[MAX_BUFFER_SIZE], 0, MAX_BUFFER_SIZE);
// Inline event handler for the Completed event.
// Note: This even handler was implemented inline in order to make
// this method self-contained.
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
// *********************************************
// THIS part of the code was added to receive
// a vector of 3 double
Double[] OdomD = new Double[3];
for (int i = 0; i < 3; i++)
{
OdomD[i] = BitConverter.ToDouble(e.Buffer, 8 * i);
}
// *********************************************
}
else
{
response = e.SocketError.ToString();
}
_clientDone.Set();
});
// Sets the state of the event to nonsignaled, causing threads to block
_clientDone.Reset();
// Make an asynchronous Receive request over the socket
_socket.ReceiveAsync(socketEventArg);
// Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
// If no response comes back within this time then proceed
_clientDone.WaitOne(TIMEOUT_MILLISECONDS);
}
else
{
response = "Socket is not initialized";
}
return response;
}
The Connect() method is exactly the same reported in the link above. So when the application start, the Connect() method is called as follow:
SocketClient client = new SocketClient();
// Attempt to connect to server for receiving data
Log(String.Format("Connecting to server '{0}' over port {1} (data) ...", txtRemoteHost.Text, 4444), true);
result = client.Connect(txtRemoteHost.Text, 4444);
Log(result, false);
That is done just once at the beginning, then I need receive this array of 3 double that is updated every second. So I use:
Log("Requesting Receive ...", true);
result = client.Receive();
Log(result, false);
The problem is that also if I debug the code and stop the execution inside Receive(), I always read the same value, that is the first value sent by the server. What I'm expecting is that every time I call client.Receive(), I get the new value, but this is not appening.
I had a similar problem by writing the same client in Matlab environment. I solved the problem by using the function flushinput(t) before to read the input buffer. In this way I was able to read always the last data sent by the server. I'm lookin for a function similar to that one ..
The size of the input buffer is fixed equal to the data that I'm expecting to receive, in that case is 24 bytes ( 3* sizeof(double) ) ..
Thanks a lot for you time !!
oleksii is right, you should call client.Receive() in a loop. You can choose to start a thread that covers the receive section of your code. Also note that client.Receive() will keep trying to receive from the buffer, and it will get stuck if there is no data available.
The main question was **how to clear the input buffer? ** or am I wrong?=!
Nevertheless; since you don't have a fixed buffer denoted as seen from you posted code and receive it via the SocketAsyncEventArgs, you could clear it with:
Array.Clear(e.Buffer, 0, e.Buffer.Length);