I am having issues sending messages from a C# web service using clrzmq to C++ using ZeroMQ. I installed clrzmq with NuGet and I built libzmq from source for C++.
I have no issues sending and receiving to/from C++, however, every message send from C# to C++ arrives with zero size.
This is the C# code that does the PUSH.
var context = new ZMQ.Context(1);
var requester = Socket(ZMQ.SocketType.PUSH);
String connectionendpoint = "tcp://127.0.0.1:9997";
requester.Bind(connectionendpoint);
String testrequest = "TESTMESSAGE";
byte[] msg = Encoding.ASCII.GetBytes(testrequest);
SendStatus r = requester.Send(msg);
if (r == SendStatus.Sent)
{
Console.WriteLine("Sent OK"); // <- Debugger arrives here with OK status
}
Output
Sent OK
This is the receiving end in C++
zmq::context_t context(1);
zmq::socket_t receiver(context, ZMQ_PULL);
int rc = zmq_connect(receiver, "tcp://127.0.0.1:9997");
std::cout << "Waiting for message " << std::endl;
zmq::message_t message;
bool success = receiver.recv(&message);
size_t msgsize = message.size();
std::cout << "Success " << success << std::endl;
std::cout << "Message Size " << msgsize << std::endl;
Output
Success 1
Message Size 0
I have also tried the following combinations of Connect/Bind from C# to C++:
Bind - Connect
Connect - Bind
Connect - Connect
Bind - Bind (fails, as expected. Both cannot bind to the same port)
Q. Is there something obvious I am missing/doing wrong?
Q. Why do both sender and receiver report successful transport with no errors when the message size is zero?
Thanks in advance.
Edit 1: After looking at other questions similar to this, I checked the versions and the clrzmq libzmq.dll version is 4.1.5.0 and the C++ version I built from source is 4.2.1.0. I tried aligning these versions, but this had no effect.
Related
I am working with an FTDI device that has native software for Windows, but nothing available for Linux. I am trying to read data from the device using pylibftdi. I would like to translate C# code that is provided by the device manufacturer and purportedly works (unclear if this is true) but have not been successful. So far I have done the following:
Installed the Linux D2XX drivers based on these instructions. Installation was successful.
Followed the directions here and here to enable the FTDI device to connect to the Linux system.
After plugging the FTDI device into the Linux system USB port:
$ lsusb
Bus 006 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 046d:c52b Logitech, Inc. Unifying Receiver
Bus 001 Device 002: ID 04f2:0833 Chicony Electronics Co., Ltd KU-0833 Keyboard
**Bus 001 Device 006: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) IC**
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
The bolded device (Bus 001 Device 006: ID 0403:6001) is the device from which I would like to read.
Then installed pylibftdi and verified that the device was readable via the pylibftdi API:
$ python3
Python 3.9.5 (default, Jun 4 2021, 12:28:51)
[GCC 7.5.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys, pylibftdi as ftdi
>>> print(ftdi.Driver().list_devices())
[('FTDI', 'Cognionics Quick-20 20CH 1706Q20N', 'AI2SUN90')]
As is clear, the device is connected and recognized. However, when I try to read from the device, I receive empty arrays:
>>> d = ftdi.Device()
>>> vars(d)
{'_opened': True, 'driver': <pylibftdi.driver.Driver object at 0x7fd819320910>, 'fdll': <CDLL 'libftdi.so.1', handle 557bc3ca6560 at 0x7fd8190aee80>, 'device_id': None, 'mode': 'b', 'encoding': 'latin1', 'encoder': <encodings.latin_1.IncrementalEncoder object at 0x7fd819320a60>, 'decoder': <encodings.latin_1.IncrementalDecoder object at 0x7fd8190aefd0>, '_baudrate': 9600, 'interface_select': None, 'device_index': 0, 'list_index': None, 'ctx': <ctypes.c_char_Array_1024 object at 0x7fd819342c40>}
>>> d.read(100)
b''
>>> d.read(100)
b''
>>> d.read(100)
b''
This C# code (provided by the manufacturer) purportedly works, but I haven't been able to test it. It seems like the easiest approach would be to translate this into python but even that is challenging as I do not know how to replicate the constants and ftdi function calls that are being used. The provided C# code is:
UInt32 ftDevCount = 0;
ftStatus = ftDev.GetNumberOfDevices(ref ftDevCount);
ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftDevCount];
ftStatus = ftDev.GetDeviceList(ftdiDeviceList);
String[] deviceNames = new String[ftDevCount];
for (int c = 0; c < ftDevCount; c++)
{
deviceNames[c] = ftdiDeviceList[c].Description.ToString();
}
Connecting to a device and configuring the serial port settings
if (ftDev.OpenBySerialNumber(ftdiDeviceList[devID].SerialNumber) == FTDI.FT_STATUS.FT_OK)
{ ftDev.SetFlowControl(FTDI.FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11, 0x13);
ftDev.SetDataCharacteristics(FTDI.FT_DATA_BITS.FT_BITS_8, FTDI.FT_STOP_BITS.FT_STOP_BITS_1, FTDI.FT_PARITY.FT_PARITY_NONE);
ftDev.SetLatency(2);
ftDev.SetBaudRate((uint)3000000);
connectedName = ftdiDeviceList[devID].Description.ToString();
return true;
}
else
{
return false; //failed to open!
}
public byte ReadByte()
{
UInt32 bytesRead = 0;
byte[] t_data = new byte[1];
ftDev.Read(t_data, 1, ref bytesRead);
return t_data[0];
}
public void WriteByte(byte dat)
{
UInt32 bytesWritten = 0;
byte[] data = new byte[1];
data[0] = dat;
ftDev.Write(data, 1, ref bytesWritten);
}
//wait for sync byte 0xFF
while (byteInterface.ReadByte() != 255) {};
//read packet counter
int packetCount = byteInterface.ReadByte();
//read the 20 EEG channels
int NumEEG = 20;
for (int c = 0; c < NumEEG; c++)
{
msb = byteInterface.ReadByte();
lsb2 = byteInterface.ReadByte();
lsb1 = byteInterface.ReadByte();
int tempEEG = (msb << 24) | (lsb2 << 17) | (lsb1 << 10);
}
int NumACC = 3;
//read the 3 ACC channels
for (int c = 0; c < NumACC; c++)
{
msb = byteInterface.ReadByte();
lsb2 = byteInterface.ReadByte();
lsb1 = byteInterface.ReadByte();
int tempACC = (msb << 24) | (lsb2 << 17) | (lsb1 << 10);
}
//read packet tail
int impStatus = byteInterface.ReadByte();
//read battery voltage
int batteryByte = byteInterface.ReadByte();
//read trigger
int trigger = (byteInterface.ReadByte()<<8) + byteInterface.ReadByte();
Based on the documentation in pylibftdi github repo, I can find some wrapper function calls as well as a few constants, but I am unaware of how to turn just the setup snippet, for example, :
ftDev.SetFlowControl(FTDI.FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11, 0x13);
ftDev.SetDataCharacteristics(FTDI.FT_DATA_BITS.FT_BITS_8, FTDI.FT_STOP_BITS.FT_STOP_BITS_1, FTDI.FT_PARITY.FT_PARITY_NONE);
ftDev.SetLatency(2);
ftDev.SetBaudRate((uint)3000000);
into something in python. I think I can reset the baudrate using d.baudrate = 3000000, and I can change the latency timer using d.ftdi_fn.ftdi_set_latency_timer(2) but I do not know how to set the data characteristics, what the constants mean (FTDI.FT_DATA_BITS.FT_BITS_8, etc.), and how to set the flow control identically to the C# code.
Other SO posts have also referred to the D2XX programmers guide found here but didn't see a way to apply it to this problem
Any suggestions would be appreciated.
As response to the comment and as an follow up answer:
I cannot confirm the claim that D2XX is more reliable than the VCP from personal experience and the second one is only partially correct: one can e.g. use the VID:PID combination in most cases IIRC.
I would highly recommend to stick to the easier VCP + pyserial solution. But if you really want (or need to) use pylibftdi, you can take a look at https://github.com/codedstructure/pylibftdi/blob/4662ebe069eefd5a89709d4165e3be808cad636c/docs/advanced_usage.rst - it describes how to access none exposed functionality directly. The naming is slightly different e.g. ftdi_setflowctrl instead of SetFlowControl but you will figure it out. Just check https://www.intra2net.com/en/developer/libftdi/documentation/ftdi_8c.html .
Following the advice to the question (TwinCAT 3.0 Automation Interface without Visual Studio?) I receive 1793 error (Service is not supported by server).
I try to write program to start/restart/config Beckhoff PLC using Twincat3 (this is the same functionality like the small Beckhoff GUI application). I'm trying to follow advices from solution presented above, but it seems that I cannot set the state. Reading values from the device works:
nPort = AdsPortOpen();
nErr = AdsGetLocalAddress(pAddr);
if (nErr)
cerr << "Error: AdsGetLocalAddress: " << nErr << '\n';
// TwinCAT 3 PLC1 = 851
pAddr->port = 10000;// 10000 as advised # stackoverflow;
cout << "(R) -> PLC Run\n";
cout << "(S) -> PLC Stop\n";
cout.flush();
ch = _getch();
ch = toupper(ch);
while ((ch == 'R') || (ch == 'S'))
{
switch (ch)
{
case 'R':
nAdsState = ADSSTATE_RUN;
break;
case 'S':
nAdsState = ADSSTATE_CONFIG;
break;
}
nErr = AdsSyncReadStateReq(pAddr, &nAdsState, &nDeviceState);// , 0, pData);
if (nErr) cerr << "Error: AdsSyncReadStateReq: " << nErr << '\n';
cout << nAdsState << " " << nDeviceState << endl;
nErr = AdsSyncWriteControlReq(pAddr, nAdsState, nDeviceState, 0, pData);
if (nErr) cerr << "Error: AdsSyncWriteControlReq: " << nErr << '\n'; //1793
ch = _getch();
ch = toupper(ch);
}
Ok, I have found the solution, maybe someone will find it useful. There is no error in the code above, but required AdsState is wrong. It seems that ADSSTATE_RUN and ADSSTATE_CONFIG (and some others in this enum) are used only to return the state.
To actually change the state of device you should use ADSSTATE_RESET and ADSSTATE_RECONFIG (those two values reflect the functionality of start/restart in run mode and config mode). Also with ADSSTATE_STOP you can completely stop PLC, while ADSSTATE_SHUTDOWN allows for rebooting or turning off the PC (depending on DeviceState value 0/1).
In my project (C#, WPF application) I have device that appears as VCP. I need connect to it. I am detecting serial port using WMI and filter by VID and PID. It makes job done in 90%. Device manufacturer uses same VID/PID pair for all devices. Accurate model is in USB descriptor (Device Decsriptor part, property iProduct). I can't find this anywhere exploring WMI.
How can I get to USB decriptor with .NET? In C# read USB Descriptor answers suggest to use WMI. In WMI device description is not USB descriptor. I don't need to list connected USB devices but to read specific data from USB device descriptor.
Very helpful article https://lihashgnis.blogspot.com/2018/07/getting-descriptors-from-usb-device.html
I have just added some code to get String Descriptor:
USB_STRING_DESCRIPTOR* stringDescriptor = nullptr;
int sBufferSize = sizeof(USB_DESCRIPTOR_REQUEST) + MAXIMUM_USB_STRING_LENGTH;
BYTE *sBuffer = new BYTE[sBufferSize];
memset(sBuffer, 0, sBufferSize);
requestPacket = (USB_DESCRIPTOR_REQUEST*)sBuffer;
stringDescriptor = (USB_STRING_DESCRIPTOR*)((BYTE*)sBuffer + sizeof(USB_DESCRIPTOR_REQUEST));
requestPacket->SetupPacket.bmRequest = 0x80;
requestPacket->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
requestPacket->ConnectionIndex = usbPortNumber;
requestPacket->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8); // String Descriptior 0
requestPacket->SetupPacket.wLength = MAXIMUM_USB_STRING_LENGTH;
err = DeviceIoControl(hUsbHub, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, sBuffer, sBufferSize, sBuffer, sBufferSize, &bytesReturned, nullptr);
// Now get iProduct string in language at zero index
requestPacket->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) | deviceDescriptor->iProduct;
requestPacket->SetupPacket.wIndex = (USHORT)stringDescriptor->bString[0];
err = DeviceIoControl(hUsbHub, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, sBuffer, sBufferSize, sBuffer, sBufferSize, &bytesReturned, nullptr);
std::wcout << stringDescriptor->bString
I'm familiar with C#, and know some python. Recent days I'm learning the book Programming Python, 4th Edition and have run the very basic socket samples: echo-server.py and echo-client.py
They work well on my Windows, python 3.x.
python server:
from socket import *
myHost = 'localhost'
myPort = 50007
sockobj = socket(AF_INET, SOCK_STREAM)
sockobj.bind((myHost, myPort))
sockobj.listen(5)
while True:
connection, address = sockobj.accept()
print('Server connected by', address)
while True:
data = connection.recv(1024)
if not data: break
connection.send(b'Echo=>' + data)
connection.close()
Now I want to learn socket in C# too, so I wrote a C# .net framework 4.5 socket client, expecting to receive and show what echo-client.py does.
I got the C# demo from msdn and made some refactor to reduce code size.
public static void Main(string[] args)
{
string server = "localhost";
int port = 50007;
string request = "GET / HTTP/1.1\r\nHost: " + server +
"\r\nConnection: Close\r\n\r\n";
Byte[] sent = Encoding.ASCII.GetBytes(request);
Byte[] recv = new Byte[256];
IPHostEntry hostEntry = Dns.GetHostEntry(server);
IPEndPoint ipe = new IPEndPoint(hostEntry.AddressList[1], port);
Socket s =
new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
s.Connect(ipe);
s.Send(sent, sent.Length, 0);
int bytes = 0;
string page = "recived:\r\n";
//do
{
bytes = s.Receive(recv, recv.Length, 0);
page = page + Encoding.ASCII.GetString(recv, 0, bytes);
}
//while (bytes > 0);
Console.WriteLine(page);
Console.WriteLine("result");
Console.ReadKey();
}
My test steps:
If I set up a web site using local IIS, such as
http://localhost:801, then above code can show the homepage html
contents, this means my C# code is working.
Run echo-server.py, and change C# code's port to 50007, then run,
nothing output in console, and application does not exit, if I place a break point within the loop, I can see the loop has only run once. The python server did output some log saying C# is connecting.
Comment do while loop(as commented in code), this time the output is exactly same as echo-client.py(expected).
So I'm wondering what's wrong when I'm using do while loop?
I am trying to send a message from a C# application to my arduino on the serial port.
However it hangs on the WriteLine. It never ends and when I read whats been stored in my buffer on the arduino it's like ive been sending it over and over 100 times.
Code on c# app
public void testSend()
{
if (mySerialPort.IsOpen)
{
//setup
//mySerialPort.Open();
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.None;
mySerialPort.RtsEnable = true;
mySerialPort.WriteTimeout = 500;
try
{
mySerialPort.WriteLine("Sent from my c# app!");
}
catch(TimeoutException)
{
//Console.WriteLine("Timeout while sending data");
}
//mySerialPort.Close();
}
else
{
Console.WriteLine("Port already open!");
}
}
Code on arduino(for reference and clearance )
void setup()
{
//Initialize serial and wait for port to open:
Serial.begin(9600);
while (!Serial)
{
; // wait for serial port to connect. Needed for native USB
}
}
char* buf = malloc(1024);
int ReciveData()
{
if (Serial.available())
{
// read the incoming bytes:
String temp = Serial.readString();
if (temp.length() > 0)
{
temp.toCharArray(buf, temp.length() + 1);
}
}
}
void loop()
{
Serial.print("Sent from arduino!");
Serial.println(buf);
delay(1000);
ReciveData();
}
}
This is how it looks. Here is 4 messages, every send start with "Sent from arduino!". when i read it. You can see on line 1 and 2 everything is good but when I start the c# application and it goes Hawaii
Sent from arduino!Sent from serial terminal!
Sent from arduino!Sent from serial terminal!
Sent from arduino!Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Sent from arduino!Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Sent from my c# app!
Not sure why. But when i tried to add \0 at end of the string it worked.
try
{
mySerialPort.WriteLine("Sent from my c# app! \0");
}
In c \0 is the string terminator character. Without it the read won't know the characher array has ended.
The mySerialPort.WriteLine method would send the string you specified + the mySerialPort.NewLine value, which in your case is the default value - System.Environment.NewLine (which is "\r\n").
Before the usage of WriteLine (and also ReadLine) - specify the protocol EOL character, in your case:
mySerialPort.NewLine = "\0"
And there will be no need to add manually the EOL character on each writing (and to miss the purpose of WriteLine over just Write)