FSEPIC Posted June 28, 2020 Report Posted June 28, 2020 Hi Paul , i am looking to use either fsuipc client dll , or lua and i noticed in one of your replies , that you suggested to a user to try lua instead of the client dll Is there any functional difference , as both talk to fsuipc ? I would like to hear your take on this , ? ( to me, on the surface lua looks very simple to program , and no GBs VS download etc needed 😉 ) best regards , Peter
Paul Henty Posted June 28, 2020 Report Posted June 28, 2020 Hi Peter, The two technologies are used for different kinds of tasks, so It really depends on what your program will do. Generally Lua can be thought of as a way of writing 'plug ins' that extend the functionality of FSUIPC. Typical uses are driving hardware connected to the sim monitoring the flight, looking for certain conditions then taking actions (e.g. play a cabin announcement at the right time) creating functions that can be bound to buttons/keys (e.g. set fuel to 80% when a key is pressed) creating simple display windows to show information from the sim. (e.g. calculate time until fuel runs out and show it in a window in real time). Using the DLL in an external program is better (or required) if any of these are true: you need a complex user interface where users need to interact with your application (selecting menus, filling out forms etc, drawing charts) the application needs to do other things beside interacting with FSUIPC (e.g. has a flight planner than plans routes) the application will require hundreds of lines of code (debugging and code organisation is much easier in Visual Studio) Other considerations: Lua scripts can only be run on a registered copy of FSUIPC. An external program can be used with an unregistered copy. If you want others to use your program this might be a consideration. If you need to access many L:Vars (Panel Variables) Lua is much more efficient for this. Hopefully that helps. If you're still unsure let me know what your program will be doing and I can give more specific advice. Paul
FSEPIC Posted June 28, 2020 Author Report Posted June 28, 2020 Hi Paul, - thanks for your very clear explanation , ( looks like your code 😉 ) - the task at hand is to let my arduino board talk to fsx , the buttons and switches , and also receive data , to set leds , and 7-segm. display , therefore no user interaction is necessary . - so the lua program would be only an intermediary , and it can speak "serial " very easily according to the lua docs . - could you expand a bit on the öther considerations ? Why is lua mor effiecint ? - i thought from your docs that the .net client also needs a copy of fsuipc installed ? Peter
Paul Henty Posted June 28, 2020 Report Posted June 28, 2020 Quote Why is lua mor effiecint ? It's just the way LVARs are read and written from an external program. The FSUIPC external interface can only process one LVar at a time. So each LVar requires a complete data exchange cycle (Process() Call). This takes time so reading 20 or more Lvars in real time isn't very practical from an external program. This doesn't apply to normal Offsets of course, just LVars. Quote - i thought from your docs that the .net client also needs a copy of fsuipc installed ? Yes, both require FSUIPC. Lua needs a paid (registered) copy. External programs can use a free (unregistered) copy. Quote the task at hand is to let my arduino board talk to fsx This seems like the sort of thing the Lua system was intended for, but I can't say how easy it would be; I'm not a Lua expert and don't do anything with hardware. If you have a registered copy of FSUIPC I would try Lua first and see if you can get a switch and a LED working. Paul
FSEPIC Posted September 7, 2020 Author Report Posted September 7, 2020 Hi Paul , - am still comparing , so last but not least .... your dll , so diving into C# and Visual Studio . It is a lot... ;-) - this morning i got this error when trying to add the fsuipc dll as you described in your video . Error Could not install package 'FSUIPCClientDLL 3.1.20'. You are trying to install this package into a project that targets '.NETFramework,Version=v3.5', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author. what gives ??? best regards , Peter
Paul Henty Posted September 7, 2020 Report Posted September 7, 2020 Hi Peter, The minimum version of the .NET framework that my DLL will work with is 4.0. Your project seems to be targeting version 3.5 which is from the days of Windows XP, so very old. You'll need to change the target runtime by going to PROJECT -> Properties: The minimum I recommend is 4.5 which will run on any Windows from Vista onwards. Paul
FSEPIC Posted September 7, 2020 Author Report Posted September 7, 2020 Hi Paul , - am still comparing , so last but not least .... your dll , so diving into C# and Visual Studio . It is a lot... 😉 - this morning i got this error when trying to add the fsuipc dll as you described in your video . Error Could not install package 'FSUIPCClientDLL 3.1.20'. You are trying to install this package into a project that targets '.NETFramework,Version=v3.5', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author. what gives ??? best regards , Peter Hi Paul , - thanks , that was indeed part of the problem , i took a gamble and added the fsuipcclient folder to the solution , and added then the reference to the dll . - great , thanks , making progress now best regards , Peter
FSEPIC Posted September 18, 2020 Author Report Posted September 18, 2020 (edited) Hi Paul , - basically all is working now for pmdg , and receiving data over serial port from hw, starting to like Visual Studio ( just kidding 😉 - i am using the FSUIPCConnection.SendControlToFS(PMDG_737_NGX_Control. properties , which is fantastic , thanks ! - but it looks like about 20 times about the same code , for the pushbutton switches . for example : --------------------------------------- // event or loop , i can choose in my code , so i am basically receiving the pin numbers over a serial port . case pin.EVT_MCP_LVL_CHG_SWITCH: FSUIPCConnection.SendControlToFS(PMDG_737_NGX_Control.EVT_MCP_LVL_CHG_SWITCH, Convert.ToInt32(!(MCP_annunLVL_CHG.Value > 0)) ); break; --------------------------------------------------- pin.EVT_MCP_LVL_CHG_SWITCH: defined as 23 ( in separate class , similar to enumeration ) using your naming conventions PMDG_737_NGX_Control.EVT_MCP_LVL_CHG_SWITCH defined as 70023 Convert.ToInt32(!(MCP_annunLVL_CHG.Value > 0)) , using petes naming convention , and your > 0 trick 😉 Q . I would like to keep this idea , but use a dictionary , would that be more elegant / short ??? - So use the 23 as key , lookup your value . Then use the same key in a second dictionary , lookup the last MCP_annunLVL_CHG.Value name , and its value ( maybe in tuple) . - in this way , it would be 1 function call , with the key as parameter . - the key value pairs or tuples could be neatly stored in a text file , and read into the dictionary at formload time . best regards , Peter Edit: I thought about it again , and don't know if it is possible in c# , If the text file has rows like this: ( for the above example ) , ( to be read into the dictionary ) Pinnumber( enum) (dict-key) controlname offsetname pin.EVT_MCP_LVL_CHG_SWITCH PMDG_737_NGX_Control.EVT_MCP_LVL_CHG_SWITCH MCP_annunLVL_CHG then call function , and use the 2 strings in this row from the dict. to BUILD the code line : FSUIPCConnection.SendControlToFS("controlname" , " offsetname" .Value > 0)) ); if this magic is possible , then that would be the most simple solution , unless you have other tricks up your sleeve ... best regards , Peter Edited September 18, 2020 by FSEPIC clarification
Paul Henty Posted September 18, 2020 Report Posted September 18, 2020 Hi Peter, Glad to hear it's all going well. I like the dictionary idea. As well as cutting down on the code, it will also allow you to change and add switches without recompiling the code. Paul
FSEPIC Posted September 18, 2020 Author Report Posted September 18, 2020 Hi Paul , that was the idea , indeed. For the implementation ( not for the dict. stuff ) , do you have some pointers , what this is called in c# ?? So i can study this in the net . I found something called " dynamic programming " , but that was about recursive programming , and not applicable here , i think ... , best regards , Peter
Paul Henty Posted September 19, 2020 Report Posted September 19, 2020 Hi Peter, It's quite complicated to compile and run .NET code at runtime. It's usually called Dynamic Execution. I don't think it's needed here however; there is a way you can do this with the base (untyped) Offset class. I suggest something along these lines... Text File: In the text file have the following: pin, controlName, offset address, type, size e.g. 23, EVT_MCP_LVL_CHG_SWITCH, FFFF, byte, 1 Dictionary: Create a structure to hold the pin, the event, the offset, and a method to get the offset value back as an int: internal struct pinInfo { public int pin; public string eventName; public Offset offset; public string offsetType; public pinInfo(int Pin, string EventName, Offset FSUIPCOffset, string OffsetType) { this.pin = Pin; this.eventName = EventName; this.offset = FSUIPCOffset; this.offsetType = OffsetType; } public int getOffsetValue() { int value = 0; switch (this.offsetType) { case "byte": value = (int)this.offset.GetValue<byte>(); break; case "short": value = (int)this.offset.GetValue<short>(); break; case "int": value = this.offset.GetValue<int>(); break; } return value; } } Create the dictionary to hold these entries, keyed on the pin: Dictionary<int, pinInfo> pins = new Dictionary<int, pinInfo>(); Populating the dictionary: As you read each line in the text file, create an instance of pinInfo and add to the dictionary: // these would be from the file... string pinID = "23"; string controlName = "EVT_MCP_LVL_CHG_SWITCH"; string offsetAddressHex = "FFFF"; string offsetType = "byte"; string offsetSize = "1"; // convert pin to int int pinInt = int.Parse(pinID); // convert offset address from string to int (as hexadecimal) int offsetAddressInt = int.Parse(offsetAddressHex, NumberStyles.HexNumber); // convert size to int int offsetSizeInt = int.Parse(offsetSize); // convert event string to int int eventInt = (int)Enum.Parse(typeof(PMDG_737_NGX_Control), controlName, false); // create (untyped) offset Offset offset = new Offset(offsetAddressInt, offsetSizeInt); // create new pinInfo and add to the dictionary pinInfo newPin = new pinInfo(pinInt, eventInt, offset, offsetType); pins.Add(newPin.pin, newPin); Using the dictionary: When the pin number arrives, get the pinInfo using the pin number. Then use the pin info to get the offset value and send the control: int incommingPinNumber = 23; pinInfo pin = pins[incommingPinNumber]; FSUIPCConnection.SendControlToFS(pin.controlID, pin.getOffsetValue()); Paul
FSEPIC Posted September 21, 2020 Author Report Posted September 21, 2020 Hi Paul , was just reading up on your offset.GetValue example in your advanced tutorial section , but it did not compute , until now... ! I got the swithces to work with datatables , but this is more elegant ! Great ! best regard , Peter 1
FSEPIC Posted October 5, 2020 Author Report Posted October 5, 2020 Hi Paul , was going to ask you about the possibility of events ( for data coming from fsuipc ) , to avoid "flooding" the serial port 😉 Then I came across your FSUIPC WebSocket Server project . That would nicely solve the problem: Studying the protocol , because it is used on a LAN only , the latency is about 0 . edit : could not connect , because did not notice the protocol parameter in the websocketsharp lib . , All is fine now , great thanks Paul ! Best regards , Peter
Paul Henty Posted October 5, 2020 Report Posted October 5, 2020 Hi Peter, I don't know either of those libraries. You can specify the protocol on the native WebSocket object built into .NET. I guess using that would require more coding than using a library though. However, using the WebSocket Server just for event notifications seems like a lot of work. Using the DLL you can check the .ValueChanged property on the Offset. This will tell you if the value is different since the last Process() call. If this is false you can choose not to send the data to the serial port. This feature was only added in the last few months. Do you think that will work for you? Paul
FSEPIC Posted October 5, 2020 Author Report Posted October 5, 2020 Hi Paul, - right now , ( after implementing the "pininfodictionary " , as per your example above ) i decided to to the same thing on the receiving end , and created a "leddictionary ". - so with 2 lines of code , i could get rid of all offset definitions in c# : var list = LedDictionary.Keys.ToList(); foreach (var key in list) checkbox[LedDictionary[key].LedNumber].Checked = LedDictionary[key].getOffsetValue() > 0; ( i am using checkboxes , ( i found a way to dynamically generate them ) , as a way to "fake" Events . ) So the whole program is now reduced from hundreds of lines of code to < 100 lines of code . - you are right , is more work , but on the other hand , since i use 2 .csv files, they can be read in in 1 codeline using a lib ( by now you understand i am a fan of using libs 😉 - and i am starting to like c# VS ( forget LUA .... ) . - so i would like to give it a try . - now on testing i did run into a snag : - websocket is open , and i am testing on pmdg SE , 737 , FSX Win10 - i am sending the command as per your example in your doc: test cmdtest = new test { Command = "about.read", Name = "about", }; string json = JsonConvert.SerializeObject(cmdtest); =========================================== this is the response: ws open {"Command":"about.read","Name":"about"} fsuipc says: { "command": "Unknown", "name": "Unknown", "success": false, "errorMessage": "Request message is invalid. No command specified.", "errorCode": "BadMessage" } any ideas ? it would be very nice if there was also 1 example in c# in the doc , for us who don't want to delve to deep into jscript 😉 , best regards , Peter
Paul Henty Posted October 5, 2020 Report Posted October 5, 2020 Hi Peter, It's good you got the connection working. The problem with your request is that the property names are case-sensitive. Your 'Command' should be 'command'. Like this: test cmdtest = new test { command = "about.read", name = "about", }; Quote it would be very nice if there was also 1 example in c# in the doc , for us who don't want to delve to deep into jscript I'll put it on the list of things to do. I really didn't expect anyone to be using it from C# :-) Paul
FSEPIC Posted October 5, 2020 Author Report Posted October 5, 2020 - great , works like a charm now . - Well , is a nice challenge ... , e.g. name: 'altitude', address: 0x0570, type: 'int', size: 8 }, , apparently in JS you can format JSON like that. but the JSON docs state hex numbers are not supported 😉 , so i guess will have to use string here . ah , going through the doc examples , i did get exception , maybe quitting FS before the server ??? and small data error in HDG , consistently 2 degrees off, but no big deals . best regards , Peter - right now , ( after implementing the "pininfodictionary " , as per your example above ) i decided to to the same thing on the receiving end , and created a "leddictionary ". - so with 2 lines of code , i could get rid of all offset definitions in c# : var list = LedDictionary.Keys.ToList(); foreach (var key in list) checkbox[LedDictionary[key].LedNumber].Checked = LedDictionary[key].getOffsetValue() > 0; ( i am using checkboxes , ( i found a way to dynamically generate them ) , as a way to "fake" Events . ) So the whole program is now reduced from hundreds of lines of code to < 100 lines of code . - you are right , is more work , but on the other hand , since i use 2 .csv files, they can be read in in 1 codeline using a lib ( by now you understand i am a fan of using libs 😉 - and i am starting to like c# VS ( forget LUA .... ) . - so i would like to give it a try . - now on testing i did run into a snag : - websocket is open , and i am testing on pmdg SE , 737 , FSX Win10 - i am sending the command as per your example in your doc: ws open {"Command":"about.read","Name":"about"} fsuipc says: { "command": "Unknown", "name": "Unknown", "success": false, "errorMessage": "Request message is invalid. No command specified.", "errorCode": "BadMessage" }
Paul Henty Posted October 5, 2020 Report Posted October 5, 2020 Quote but the JSON docs state hex numbers are not supported 😉 , so i guess will have to use string here . I don't think a string will work here. It's got to be a number when it arrives at the server. JSON may not support hex, but C# does! It should be fine. You declare it as a normal hex number in the C# object. Then your JSON encoder will write it out as a base 10 integer and send it like that. My server will understand that. Quote and small data error in HDG , consistently 2 degrees off, but no big deals . Sounds like a magnetic variation error. The headings from FSUIPC are usually in degrees True. You need to convert to Magnetic (used by the aircraft instruments) using the current Magnetic Variation. There's an offset for that. Paul
FSEPIC Posted October 16, 2020 Author Report Posted October 16, 2020 Hi Paul , you wrote: "-Using the DLL you can check the .ValueChanged property on the Offset" - , yes , great , thanks! , works nicely. ( the alternative implementation using the websockets is indeed lot of work ;-) , but nice challenge . It is a bit more hairy in c# , because the websockets data arrive in separate thread, so invoke must be used . In your JS examples that problem does not seem to arise . ) - Using your .net client dll, all is working stable , but the encoders are a bit sluggish , to my taste . I am experimenting with settings of 10ms for timerMain , but i can't see a noticeable improvement. ( they are in their own group of 6 ) . I did do separate testing of the encoders , with a serial port viewer and there is no problem there with speed. That seems to suggest that the bottleneck is the part where the fsuipc offset is written . Is there a limit / update rate as far as fsuipc is concerned ? best regards , Peter
Paul Henty Posted October 16, 2020 Report Posted October 16, 2020 Quote Is there a limit / update rate as far as fsuipc is concerned ? The limit will be how long it takes for a Process() call to complete. This depends on your particular setup. e.g. if the flight sim is running complex 3rd-party aircraft, if the PC is doing other things, if there are any other addons using FSUIPC or SimConnect etc. On my PC with no addons and a default Cessna it takes about 12ms. So a timer loop under 12ms would not improve the update rate. 12 ms would be the maximum. On your system you can see the average time taken for Process() calls by displaying the value of this property: FSUIPCConnection.Statistics.ProcessAvg.TimeForProcessCall Let you application run for a bit so it can build an average. The value is in milliseconds. You can also see min and max values using ProcessMin and ProcessMax. Paul
FSEPIC Posted October 16, 2020 Author Report Posted October 16, 2020 Hi Paul , that is good news, and in my setup FSX , SE , and pmdg 737 I am getting around 9 ms. avg , so will investigate further ;-) Peter
spokes2112 Posted October 16, 2020 Report Posted October 16, 2020 Not to step on this discussion, having a similar problem. This is an untested hypothesis based on a post in the main FSUIPC room, of which I cannot find. It will get rid of the constant reading / writing of the aircraft's internal vars therefore speeding up the response. It should also work on almost all encoders when there is a matching led display being used ( Hand to eye response ). Some things like frequencies may be a bit tougher. ----------------------------------------------------------------------- Pete had mentioned something in regards to encoder delays and I think it is the way to go, if this is how he does it.. I believe it is. This is an example for a MCP heading encoder w/ LED display - 1) When the aircraft is first loaded, get the aircraft's internal HDG value and send it to a user offset. Do this only once, as an ini. ( .exe, .dll or .lua ) 2a) From the encoder, set it up in the FSUIPC interface as button/key press command. ( the key/button polling setting in the .ini is your adjustment ) 2b) Use the special commands listed on/near page 38 of FSUIPC for Advanced Users.pdf, "FSUIPC Offset Controls:" Heading up: x5200zzzz Offset Word Cyclic Increment (user offset = zzzz), hexadecimal, with parameter(s) of: Slow Increment ( 1° ), with a cyclic limit of 359 - 00000001011001110000000000000001 = 0x1670001 = 23527425 Fast Increment ( 10° ), with a cyclic limit of 359 - 00000001011001110000000000001010 = 0x167000A = 23527434 Decrement should be similar with the opposite control. 2c) Use the offset directly, with formatting as needed, to drive the LED display, I believe this will be quicker in response, for the eyes. 3) Using .exe, .dll or .lua, listen for the user offset to change, if it does, only then update the aircraft's internal heading variable so it matches the led display ( the offset ). Again, just a hypothesis.. Good luck, carry on. 😁 Roman
FSEPIC Posted November 10, 2020 Author Report Posted November 10, 2020 Hi Paul, ( btw , thanks Roman , for your input , 2b has always worked very well for me , but is not the solution, 3 needs sync of hw and fsuipc ..... so... ;-) ... ) Solved , i did not call the function: connection() ;-) , deleted too much of your code... as easy as it was to get your websockets example to work in c# , the harder it seems in javascript , so no copy paste ? The setup using javascript only as simple as possible , because JS is rather new to me index.html and connection.js live in 1 folder , i started from the JS example in Visual Studio and Visual Studio Code. here is the index.html =============== <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>FSUIPC WebSocket Server</title> <script type="text/javascript" src="connection.js"></script> </head> <body> <h2>FSUIPC WebSocket</h2> </body> </html> ----------------- and here the connection.js var connection = new function () { var ws = null; // WebSocke this.start = function () { }; this.stop = function () { if (ws) { ws.close(); } }; var clearMessages = function () { document.getElementById("connectionStatus").innerText = ""; document.getElementById("connectionError").innerText = ""; }; this.openConnection = function () { if (!ws) { clearMessages(); // Create a new WebSocket. // The server url is from the text box on the form //var serverURL = document.getElementById("serverURL").value; ws = new WebSocket("ws://localhost:2048/fsuipc/", "fsuipc"); // Handle the onopen event ws.onopen = function () { console.log("open"); document.getElementById("connectionStatus").innerText = "Connection Open"; }; // Handle the onclose event ws.onclose = function () { document.getElementById("connectionStatus").innerText = "Connection Closed"; // clear the WebSocket so we can try again ws = null; }; // Handle the onerror event ws.onerror = function () { console.log("error"); document.getElementById("connectionError").innerText = "WebSocket Error"; }; } } this.closeConnection = function () { if (ws) { clearMessages(); ws.close(); } } }; ------------------------ only this line changed : ws = new WebSocket("ws://localhost:2048/fsuipc/", "fsuipc"); in the chrome dev tools i get this result : messages: connected and under headers: Request URL: ws://127.0.0.1:5500/index.html/ws Request Method: GET Status Code: 101 Switching Protocols Response Headersview source Connection: Upgrade Sec-WebSocket-Accept: ulRY6vxyLAMR+6zT9PFntYFrNiY= Upgrade: websocket Request Headersview source Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9 Cache-Control: no-cache Connection: Upgrade Host: 127.0.0.1:5500 Origin: http://127.0.0.1:5500 Pragma: no-cache Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits Sec-WebSocket-Key: 1Ns9YcRWpb+SRrzeS0jt+A== Sec-WebSocket-Version: 13 Upgrade: websocket User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36 ================== But the fsuipc websockets server has : number of sockets connected 0 ( i start the index.html from the live server in VS code ) : http://127.0.0.1:5500/index.html What could be the problem ??? Peter
Paul Henty Posted November 10, 2020 Report Posted November 10, 2020 I think there are two problems here... 1. There is nothing in the script (connection.js) or the webpage (index.html) that runs any of the code in the connection function. I therefore don't think this is being run at all. 2. The dev tools output says the WebSocket URL is ws://127.0.0.1:5500/index.html/ws. However your code (which I don't think is being run) says ws://localhost:2048/fsuipc/. I can't see anywhere in your code that the first URL is referenced, and it's certainly wrong. It shouldn't have index.html in it. I suspect problem 2 is because you've got the WebSocket server running on the same port as your WWW server (5500). The WebSocket server should run on a different port. Your code specifies 2048 so you should configure the WebSocket server to run on 2048. For problem 1 you need to call connection.openConnection() from somewhere. Maybe a button press on the webpage. Maybe when the page has finished loading (set code for the window.onload event). Note that you'll need a <div> on the html page with an ID of 'connectionStatus' to show the connection status. Paul
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now