Two-way communication between C# WPF application and python script - c#

I'm trying to get a tow-way communication between a c# application and a python script that c# will call.
I have some input channels in c# that changes constantly at high frequency (5000-1000 data/s) for let's say a minute. On every change of those inputs,results are calculated and assigned to output variables. What i'm trying to do is to move the logic to a python script. For instance:
Inputs: double x,y
Output: double z
So the pyhton script should be capable of read the inputs, perform the logic and write the results at a symilar frequency.
Any recomendations? Has anyone did anything similar before?
First I tried to call the script on every change and read the console output. But the code in the script is not as simple as z=x*y and variables that store values are required in the pyhon script. For example, the script mught want to save the maximum value of x and y reached.
I had a look to ZeroMQ library for the communication, not sure how to use it though.

Here is a solution:
Simple C# program: client which sends data and receive
using System;
using ZeroMQ;
namespace ZeroMQ_Client
{
class Program
{
static void Main(string[] args)
{
using (var requester = new ZSocket(ZSocketType.REQ))
{
// Connect
requester.Connect("tcp://127.0.0.1:5555");
for (int n = 0; n < 10; ++n)
{
string requestText = "Hello";
Console.Write("Sending {0}...", requestText);
// Send
requester.Send(new ZFrame(requestText));
// Receive
using (ZFrame reply = requester.ReceiveFrame())
{
Console.WriteLine(" Received: {0} {1}!", requestText, reply.ReadString());
}
}
}
}
}
}
python program, you have to install pyzmq:
#
# Hello World server in Python
# Binds REP socket to tcp://*:5555
# Expects b"Hello" from client, replies with b"World"
#
import time
import zmq
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://*:5555")
while True:
# Wait for next request from client
message = socket.recv()
print("Received request: %s" % message)
# Do some 'work'
time.sleep(1)
# Send reply back to client
socket.send(b"World")

Related

cmd Redirect Standard Input c#

I am writing my own terminal and want to add the ability to execute CMD commas. I found this code on Microsoft website:
using System;
using System.IO;
using System.Diagnostics;
using System.ComponentModel;
namespace ProcessStandardInputSample
{
class StandardInputTest
{
static void Main()
{
Console.WriteLine("Ready to sort one or more text lines...");
// Start the Sort.exe process with redirected input.
// Use the sort command to sort the input text.
using (Process myProcess = new Process())
{
myProcess.StartInfo.FileName = "cmd.exe";
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.Start();
StreamWriter myStreamWriter = myProcess.StandardInput;
// Prompt the user for input text lines to sort.
// Write each line to the StandardInput stream of
// the sort command.
String inputText;
int numLines = 0;
do
{
Console.WriteLine("Enter a line of text (or press the Enter key to stop):");
inputText = Console.ReadLine();
if (inputText.Length > 0)
{
numLines++;
myStreamWriter.WriteLine(inputText);
}
} while (inputText.Length > 0);
// Write a report header to the console.
if (numLines > 0)
{
Console.WriteLine($" {numLines} sorted text line(s) ");
Console.WriteLine("------------------------");
}
else
{
Console.WriteLine(" No input was sorted");
}
// End the input stream to the sort command.
// When the stream closes, the sort command
// writes the sorted text lines to the
// console.
myStreamWriter.Close();
// Wait for the sort process to write the sorted text lines.
myProcess.WaitForExit();
}
}
}
}
I tested this code on several commands and everything worked fine, without errors. But I decided to test running python scripts with this code. I decided to run sqlmap through my terminal with the command:
python C:\sqlmap\sqlmap.py --wizard
I got the following result:
___
__H__
___ ___["]_____ ___ ___ {1.6.11.3#dev}
|_ -| . [(] | .'| . |
|___|_ ["]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting # 22:26:59 /2022-12-07/
[22:26:59] [INFO] starting wizard interface
Please enter full target URL (-u):
At this stage, everything works properly, without errors.
When I enter any link, I always get the same result:
POST data (--data) [Enter for None]:
Injection difficulty (--level/--risk). Please choose:
[1] Normal (default)
[2] Medium
[3] Hard
> 1
Enumeration (--banner/--current-user/etc). Please choose:
[1] Basic (default)
[2] Intermediate
[3] All
> 1
sqlmap is running, please wait..
The problem is that after entering the link in the future, the program does not expect any input from the user, all the parameters in the above result were not entered by the user
I did not find an answer to my question on the Internet, why the parameters are set themselves, without user participation. I would be very grateful if I get an answer to my question, because I do not understand what exactly the problem is
I wanted all parameters to be requested from the user, and not set without his knowledge.

Read more than one MAX31865

We are implementing temperature reading using PT100 (3 wires) and Raspberry 4 with .NET 6.
We are able to read the temperature using as reference this article.
SpiConnectionSettings settings = new(0, 0)
{
ClockFrequency = Max31865.SpiClockFrequency,
Mode = Max31865.SpiMode1,
DataFlow = Max31865.SpiDataFlow
};
using (SpiDevice device = SpiDevice.Create(settings))
{
using (Max31865 sensor = new(device, PlatinumResistanceThermometerType.Pt100, ResistanceTemperatureDetectorWires.ThreeWire, ElectricResistance.FromOhms(430)))
{
while (true)
{
Console.WriteLine(sensor.Faults.ToString());
Thread.Sleep(1000);
}
}
}
Actually to work the script need the CS pin of Max31865 connected to pin 12 of raspberry GPIO. We would like to connect more than one Max31865 in order to record some temperatures from different Pt100.
How we can specify the right/specific GPIO port in the C# script for every Max31865 CS output pin? Actually seems there are no properties to change that pin but this feature will permit us to read more than one sensor.
The easiest thing is to do the CS handling manually, as automatic CS handling with multiple devices on the same bus is not fully implemented for the Raspberry Pi.
var controller = new GpioController();
controller.OpenPin(CsPinOfSensor1);
controller.OpenPin(CsPinOfSensor2);
controller.Write(CsPinOfSensor1, PinValue.Low); // CS is low-active!
controller.Write(CsPinOfSensor2, PinValue.High);
using Max31865 sensor1 = new(device, PlatinumResistanceThermometerType.Pt100, ResistanceTemperatureDetectorWires.ThreeWire, ElectricResistance.FromOhms(430));
controller.Write(CsPinOfSensor1, PinValue.High); // CS is low-active!
controller.Write(CsPinOfSensor2, PinValue.Low);
using Max31865 sensor2 = new(device, PlatinumResistanceThermometerType.Pt100, ResistanceTemperatureDetectorWires.ThreeWire, ElectricResistance.FromOhms(430));
{
while (true)
{
controller.Write(CsPinOfSensor1, PinValue.Low); // CS is low-active!
controller.Write(CsPinOfSensor2, PinValue.High);
Console.WriteLine(sensor1.Temperature.ToString());
controller.Write(CsPinOfSensor1, PinValue.High);
controller.Write(CsPinOfSensor2, PinValue.Low);
Console.WriteLine(sensor2.Temperature.ToString());
Thread.Sleep(1000);
}
}
There are multiple pins reserved as CS pins for each SPI bus, but I honestly do not even know how they would need to be selected at the OS level.
Alternatively, you can of course also connect the second sensor to a second SPI bus. The Raspberry Pi4 has a total of 6 SPI channels.

Parsing JSON string from Python to .NET C# WPF

I'm pretty new to this so any help would be greatly appreciated. I have two pieces of code and there is a missing link which I'm hoping someone can fill in. I'm new to both platforms and I don't have much experience with back-end nor with web architecture.
So below is the first bit of code, it's an adapted python server and it shows me a formatted JSON string when I enter http://localhost:8000 into the browser. This is great. It's what I want to see.
#!/usr/bin/python
"""
Save this file as server.py
>>> python server.py 0.0.0.0 8001
serving on 0.0.0.0:8001
or simply
>>> python server.py
Serving on localhost:8000
You can use this to test GET and POST methods.
"""
import SimpleHTTPServer
import SocketServer
import logging
import cgi
import sys
import json
import simplejson
import time
if len(sys.argv) > 2:
PORT = int(sys.argv[2])
I = sys.argv[1]
elif len(sys.argv) > 1:
PORT = int(sys.argv[1])
I = ""
else:
PORT = 8000
I = ""
current_milli_time = lambda: int(round(time.time() * 1000))
class ServerHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_GET(self):
logging.warning("======= GET STARTED =======")
logging.warning(self.headers)
SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
def do_POST(self):
logging.warning("======= POST STARTED =======")
logging.warning(self.headers)
data_string = self.rfile.read(int(self.headers['Content-Length']))
#print "data_string: "
#print data_string
data = simplejson.loads(data_string)
#print "json data: "
#print data
response = {}
response = {"time": current_milli_time()}
# Send a repsonse
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
self.wfile.write(json.dumps(data))
Handler = ServerHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
print "#rochacbruno Python http server version 0.1 (for testing purposes only)"
print "Serving at: http://%(interface)s:%(port)s" % dict(interface=I or "localhost", port=PORT)
httpd.serve_forever()
I have a WPF/C# Application which contains a background worker and I have previously used this to get JSON string from a REST service.
public void getData(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
var url = "http://localhost:xxxx/";
var syncClient = new WebClient();
while (true)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
System.Threading.Thread.Sleep(100);
var content = syncClient.DownloadString(url);
Console.WriteLine(content);
}
}
}
So I pretty much need some direction on how to proceed, how do I get the JSON string into my WPF/C# Application? I hope this is clear enough, let me know if you need more info.
Edit: I have a feeling I need to get the current python server to post to another server which is RESTful which I can then HTTP GET the JSON string.
Cheers!

Cannot convert TCL serial com to C#

I'm trying to convert TCL code, used to communicate with a serial port to a "robot", to C#. But for some reason my commands are not getting responses.
This is the serial com init in TCL:
proc openUart {} {
set robot::fd_ [open COM${robot::port_num}: w+]
fconfigure $robot::fd_ -mode 9600,e,7,1
fconfigure $robot::fd_ -blocking 0
fconfigure $robot::fd_ -buffering none
fileevent $robot::fd_ readable ""
}
A "command" is sent like this:
proc SendCmd {command} {
set commandlen [string length $command]
for {set i 0} {$i < $commandlen} {incr i} {
set letter [string index $command $i]
after 10
puts -nonewline $robot::fd_ $letter
}
after [expr 2 * 10]
puts -nonewline $robot::fd_ "\n"
flush $robot::fd_
}
This is how I translated this to C#. Opening the port:
private void Initialize(string com)
{
_comPort = new SerialPort(com,9600,Parity.Even,7,StopBits.One)
{
Encoding = Encoding.ASCII,
NewLine = "\n"
};
_comPort.Open();
}
And sending a command:
private string SendCommand(Commands cmd)
{
string commandToWrite = Command(cmd);
for (int i = 0; i < CommandLen; i++)
{
Thread.Sleep(10);
_comPort.Write(commandToWrite.ToCharArray(), i, 1);
}
Thread.Sleep(10 * 2);
_comPort.Write("\n");
_comPort.BaseStream.Flush();
}
I connected my PC to the robot with a serial to USB cable and ran both TCL and C# programs -
The TCL script turns on a LED on the robot.
My C# code doesn't turn the LED on, meaning the robot did not recognize the command.
I'm using the same com port, so I believe the problem is one of these:
I did not initialize the com port correctly in C#. How do you set the blocking and buffering?
Could there be an encoding issue in C#? isn't ASCII the default encoding in TCL?
Could there be a timing difference in how I'm sending the command letter-by-letter between the two languages?
Issue resolved!
I finally looped back the cable into my PC using another serial cable and 2 blue wires, crossing the RX\TX (thanks don_q for the idea!).
Using a simple serial monitor, "UART Terminal", I sniffed the commands, and to my surprise the TCL script was adding a '\r' before the '\n'!
So in fact the robot was expecting this command format -
:010508010000F1\r\n
I changed the NewLine property in C# to be "\r\n", and now I finish a command by using -
_comPort.WriteLine("");
And now everything works.

Cannot convert from SharpPcap.RawCapture to PacketDotNet.Packet

I've been following the guide over at http://www.codeproject.com/KB/IP/sharppcap.aspx for implementing a simple packet sniffer to automate authentications for me, I've managed to get to the Filtering section, and have had to make some adjustments to the tutorial code so far for it to work, but I am now stumped.
The error I am receiving is;
The best overloaded method match for 'PacketDotNet.TcpPacket.GetEncapsulated(PacketDotNet.Packet)' has some invalid arguments
Argument 1: cannot convert from 'SharpPcap.RawCapture' to 'PacketDotNet.Packet'
But I've yet to make any references to PacketDotNet my self (everything so far has been SharpPcap).
Entire code I have so far is included, the problem is in the device_OnPacketArrival() function.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PacketDotNet;
using SharpPcap;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string ver = SharpPcap.Version.VersionString;
Console.WriteLine("SharpPcap {0}, Example1.IfList.cs", ver);
// Retrieve the device list
CaptureDeviceList devices = CaptureDeviceList.Instance;
// If no devices were found print an error
if (devices.Count < 1)
{
Console.WriteLine("No devices were found on this machine");
return;
}
// Extract a device from the list
ICaptureDevice device = devices[0];
// Register our handler function to the
// 'packet arrival' event
device.OnPacketArrival +=
new SharpPcap.PacketArrivalEventHandler(device_OnPacketArrival);
// Open the device for capturing
int readTimeoutMilliseconds = 1000;
device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);
// tcpdump filter to capture only TCP/IP packets
string filter = "ip and tcp";
device.Filter = filter;
Console.WriteLine();
Console.WriteLine("-- The following tcpdump filter will be applied: \"{0}\"",
filter);
Console.WriteLine("-- Listening on {0}, hit 'Enter' to stop...",
device.Description);
// Start capturing packets indefinitely
device.Capture();
// Close the pcap device
// (Note: this line will never be called since
// we're capturing indefinitely
device.Close();
}
private static void device_OnPacketArrival(object sender, CaptureEventArgs e)
{
var tcp = TcpPacket.GetEncapsulated(e.Packet);
}
}
}
A SharpPcap.RawPacket is used to hold the raw data captured over the network adapter but PacketDotNet needs the packet parsed before the GetEncapsulated() methods will work. The step you need will look like:
var packet = PacketDotNet.Packet.ParsePacket(rawPacket.LinkLayerType, rawPacket.Data);
Then you can extract the encapsulated TcpPacket via the GetEncapsulated() method by passing it packet.
Example 12 in the SharpPcap source download at https://sourceforge.net/projects/sharppcap/ shows the syntax and how packets can be modified.
Keep in mind that PacketType.GetEncapsulated() is returning a reference to that portion of the packet so modifying it will alter the original packet.
As an update to Chris Morgan's answer (because I find myself doing this today), getEncapsulated() is now obsolete, instead you should use packet.Extract() to extract the encapsulated packet.
Alternatively, you can use Pcap.Net, which only has one Packet class that you can dynamically parse to get whatever it may contain without doing any packet cast.
You just get a Packet object and do (for example):
uint sequenceNumber = packet.Ethernet.IpV4.Tcp.SequenceNumber;
No need to cast it or know what kind of packet it is in advance, all parsing is done dynamically.

Categories

Resources