FORUM › Forums › Software › CLS2SIM Software › API, Interface control documentation › Sending button presses remotely via PowerShell.
Tagged: API, PowerShell, trim
- This topic has 7 replies, 2 voices, and was last updated 1 week, 1 day ago by
Howard.
-
AuthorPosts
-
09/06/2025 at 12:49 #4238
Howard
ParticipantHi,
I’ve just ordered a CLS-E Mk II yoke, and while awaiting delivery I started some tinkering with the API.
What I would like to do is send data to CLS2Sim to emulate the elevator trim up, and down buttons. From reviewing the API documentation that looks doable, but I want to sanity check what I’m trying with those that actually know what they are doing.
The documentation indicates that trim up is ID 1002, and down is ID 1003. It wasn’t clear to me how that should be formatted as elsewhere in the documentation it indicates things should be a UInt32, so I’m assuming that would be 0x0b,0xeb,0x00,0x00.
Further down it mentions that the command for Input Control is 0xd5, so that would be 0xd5,0x00,0x00,0x00.
What I came up with was this:
$client = new-object net.sockets.udpclient(0) $peerIP = "127.0.0.1" $peerPort = "15090" $command = $args[0] If ($command.GetType().Name -like "String") { $command = $command.Split(",")} Write-Host $command [Byte[]] $command [void] $client.send($command, $command.count, $peerIP, $peerPort) $client.close()
What I can then do is run the script with the following arguments:
0xd5,0x00,0x00,0x00,0x0b,0xeb,0x00,0x00
I ran Wireshark, and the packets in that sequence were sent, but I don’t have any hardware to interact with yet, so I’m unsure if I am well clear of the mark.
I used the PS2Exe module to turn that script into an EXE, and I can execute that from SPAD. The plan would be to run that command, with arguments, to emulate pressing the trim up down switch when I roll my trim wheel up or down.
09/06/2025 at 13:10 #4239Howard
ParticipantI re-read the document page, and noticed the ID should be formatted as UInt16, so that would be 0xea,0x03 for trim up, and 0xeb,0x0b for trim down, making the entire commands:
0xd5,0x00,0x00,0x00,0xea,0x03
0xd5,0x00,0x00,0x00,0xeb,0x03Or do those commands need to be sent as separate packets? The documentation below explains Command then Input Ids, but the documentation above states:
So if you want to enable the autopilot, you will send 2 packets.
The first contains the id 9003.
The second should arrive about 100ms later, to give CLS2Sim enough time to update the value in the simulation.So the Id is sent first, but it doesn’t explain what the “second” actually is. The command?
10/06/2025 at 08:30 #4241Diego BĂĽrgin
KeymasterHi Howard
The first packet contains the id 9003, to tell CLS2Sim, that this button is pressed.
0xD5, 0x00, 0x00, 0x00, 0x2B, 0x23The second packet should contain no id, only the 0xD5 command, to tell CLS2Sim that no button is pressed.
0xD5, 0x00, 0x00, 0x00
This effectively presses and releases the button again.
Updated the online help. (Delete your browser cache)Example: I want to press “Trim up”, and while keeping trim up pressed, I press “Flaps Down” and release it, then later I release “Trim Up” again.
At start of my script, I release all buttons: 0xD5, 0x00, 0x00, 0x00
Now I press “Trim up”: 0xD5, 0x00, 0x00, 0x00, 0xEA, 0x03
Now while keeping “Trim up” pressed, I also press “Flaps Down” : 0xD5, 0x00, 0x00, 0x00, 0xEA, 0x03, 0x03, 0x04
Now I release “Flaps Down” button, while keeping “Trim up” pressed: 0xD5, 0x00, 0x00, 0x00, 0xEA, 0x03
Now I release “Trim up”, no button is pressed now: 0xD5, 0x00, 0x00, 0x00
Now a very important caveat!
If you have mapped a button to a physical control (i.e. you mapped trim up to a button in CLS2Sim, you must first interdict this button with Input interdiction control commands, or CLS2SIm will immediately overwrite your button state.Hope that helps.
Regards
Diego10/06/2025 at 14:51 #4244Howard
ParticipantAh, that makes sense. I was just sending the button press, but no release. I’ve created a C# version of this, and just added the code to send the button release datagram. The difference here is the bytes are separated by spaces rather than commas.
using System; using System.Linq; using System.Net.Sockets; class Program { static void Main(string[] args) { string udpIp = "127.0.0.1"; int udpPort = 15090; // Choose any available port byte[] data = args.Select(arg => Convert.ToByte(arg, 16)).ToArray(); byte[] up = { 0xd5, 0x00, 0x00, 0x00 }; //byte[] data = { 0xd5, 0x00, 0x00, 0x00, 0xea, 0x03 }; using (UdpClient udpClient = new UdpClient()) { udpClient.Send(data, data.Length, udpIp, udpPort); udpClient.Send(up, up.Length, udpIp, udpPort); } } }
Wireshark indicates that the two packets are sent.
10/06/2025 at 14:59 #4245Howard
ParticipantRegarding the interdiction of buttons, the plan is to use the trim switch on the yoke, but also be allowed to use my trim wheel to send relevant up/down trim packets as well.
So I would want to interdict those buttons only during the remote code being sent. So that would be either:
0xd11,0x00,0x00,0x00,0x03,0xea – Trim up
0xd11,0x00,0x00,0x00,0x03,0xeb – Trim down
0xd11,0x00,0x00,0x00 – Remove interdictionI assume then that the trim switch is a three state switch, and it detects that neither trim up or down is set, and the rocker remains centred.
11/06/2025 at 13:44 #4249Howard
ParticipantI’ve looked through the documentation again, and the interdiction command is the only one that I can find that has three characters, being 0xd11. Is that correct or a typo? I can see that 0xd1 already exists, being override control.
So if it’s really 0xd11, I would send the following?
0x11 0x0d 0x00 0x00 + Input ID to override, and just that to clear the interdiction?
11/06/2025 at 16:22 #4250Howard
ParticipantUpdated the script with some assumptions. It includes lines to perform the interdiction, picking out bytes 5, and 6 to build that.
using System; using System.Linq; using System.Net.Sockets; class Program { static void Main(string[] args) { string udpIp = "127.0.0.1"; int udpPort = 15090; // Choose any available port if (args.Length != 0 && args.Length >= 6) { byte[] data = args.Select(arg => Convert.ToByte(arg, 16)).ToArray(); byte[] up = { data[0], 0x00, 0x00, 0x00 }; byte[] interdict_on = { 0x11, 0x0d, 0x00, 0x00, data[4], data[5] }; byte[] interdict_off = { 0x11, 0x0d, 0x00, 0x00 }; Console.WriteLine(data[0]); using (UdpClient udpClient = new UdpClient()) { udpClient.Send(interdict_on, interdict_on.Length, udpIp, udpPort); udpClient.Send(data, data.Length, udpIp, udpPort); udpClient.Send(up, up.Length, udpIp, udpPort); udpClient.Send(interdict_off, interdict_off.Length, udpIp, udpPort); udpClient.Close(); } } } }
-
AuthorPosts
- You must be logged in to reply to this topic.