Jump to content

Lua.export...(A-10c) How to SEND SWITCH STATE to UDP/TCP Listener.


Recommended Posts

Posted

Hello to everyone.

 

I'm trying to solve how can I receive SWITCH STATE (If it is ON or OFF state) data through the Export.lua to my VB.Net Listener program.

 

I have read many (I think everything, depending of this Switch State stuff with .Lua) post on ED Forums, but not managed any of those codes to work with DCS 1.2.7.23803. ((Too many information , and some out of date, and I´m noob with lua))

 

So here is my code to from Export.lua to TCP/UDP listener. For connection, disconnection and some radar altitude, pitch and bank info. And everything works as it should. :thumbup:


function LuaExportStart()
   package.path = package.path .. ";.\\LuaSocket\\?.lua"
   package.cpath = package.cpath .. ";.\\LuaSocket\\?.dll"

   socket = require("socket")
   host = "127.0.0.1"
   port = 9800
   connection = socket.try(socket.connect(host, port))
   connection:setoption("tcp-nodelay", true)
   socket.try(connection:send("Yhteys löydetty... DCS A-10C."))
end


function LuaExportAfterNextFrame()

local tNext = t
local o = LoGetWorldObjects()
for k,v in pairs(o) do
local Aika = LoGetModelTime()
local Nimi = LoGetPilotName()
local altBar = LoGetAltitudeAboveSeaLevel()
local altRad = LoGetAltitudeAboveGroundLevel()
local pitch, bank, yaw = LoGetADIPitchBankYaw() 

socket.try(connection:send(string.format("Aika = %.2f, Nimi = %s, KorkeusBaro = %.2f, TutkaKorkeus = %.2f, pitch = %.2f, bank = %.2f, yaw = %.2f\n", Aika, Nimi, altRad, altBar, pitch, bank, yaw)))

end
tNext = tNext + 1.0
return tNext 
end

function LuaExportActivityNextEvent(t)

end

function LuaExportStop()
   if connection then
   socket.try(connection:send("Yhteys Katkaistu..."))
   connection:close()
   end
end

But.. How to recognise one little switch move from OFF to ON?

 

So if here is anyone who can tell me how I can RECEIVE information...

 

For example.

 

 

Battery Power Switch State...

ON to send my listener "1" and if it is OFF then send "0" to my listener program.?

 

If somebody can direct me from right track with some code example I would be grateful...

 

Sorry for my English, and some Finnish words on the code... :cry:

 

Thanks...

 

HarSu.

Posted

The cockpit state is stored as floating point values. Each floating point value has an "argument number" which is used to retrieve it.

The argument number for the battery power switch position in the A-10C is 246. You can get it with the following Lua code:

local batSwitchState = GetDevice(0):get_argument_value(246)

 

For the battery switch, the value is 0 if the switch is off and 1.0 if the switch is on. Different controls use different conventions (some three-position switches use -1,0,1 and some use 0, 0.1, 0.2 for example).

To find out which argument numbers to use, you need to read through the Lua files of the A-10C (starting with "clickabledata.lua" and "mainpanel_init.lua") and make some educated guesses regarding which argument numbers correspond to which controls, then do some trial and error to verify your results and find out which values correspond to which control state.

 

Fortunately, for the A-10C and UH-1H, that work has already been done for you.

Take a look at DCS-BIOS. It exports the complete A-10C cockpit and supports both UDP and TCP (it acts as a TCP server).

 

The Developer Guide describes how to connect to the data stream and how to parse it. You can also look at existing implementations of the protocol parser (C++ version in the Arduino library code, JavaScript version in the reference documentation).

  • Like 1
Posted (edited)

Ok, thanks Ian.

 

So is this the code for sending that switch state to my listener?

 

function LuaExportActivityNextEvent(t)

local tNext = t
local batSwitchState = GetDevice(0):get_argument_value(246)

Socket.try(connection:send(string.format( "batSwitchState = %.1f"\n ,batSwitchState)))

end
tNext = tNext + 1
return tNext
end

I can not get to try this because I'm at work the moment..

 

 

 

Edit:

This is the code, how it should to be...

 

function LuaExportActivityNextEvent(t)
local tNext = t
local batSwitchState = GetDevice(0):get_argument_value(246)
socket.try(connection:send(string.format("batSwitchState = %.1f\n" ,batSwitchState)))
tNext = tNext + 1
return tNext
end

Edited by HarSu
Posted

Yes, it should be (except for the two syntax errors I can spot, the \n belongs inside the string literal and there is one extra "end" in there).

 

I am curious; what is the goal of your VB.NET application?

 

Also, if you do take a look at DCS-BIOS and decide against using it, I'd be interested in the reasons why so I can improve it in the future. The goal of DCS-BIOS is to avoid duplication of efforts; if it is easier to roll your own Lua code than using DCS-BIOS, I consider that a bug. Of course, confirming your own understanding of DCS internals by programming the Lua part yourself is a perfectly good reason :)

Posted

Hi Ian.

 

I also noticed those errors in that code , but only after I had already posted it here.

 

I just do not bother to edit it , because the writing and viewing this small phone screen is quite difficult.

 

I intend to try DCS-BIOS but I have not received my Arduino boards yet...

 

So for the moment I'll just play for fun and to learn to do something with lua files.

 

HarSu.

Posted

Hi.

 

Ok, the code works...

 

But the issue with the "LuaExportActivityNextEvent" function is that it keeps sending me that data all the time.

 

How can I make this work the way It sends data to listener ONLY if the switch state is changed.

 

Thanks.

 

By the way, I did not fix the code on post#3. Instead I added the code how it should be. If somebody like me is learning these things. :smilewink:

 

HarSu.

Posted
How can I make this work the way It sends data to listener ONLY if the switch state is changed.

 

This kind of question is more suited to a site like stackoverflow.com, since it is not DCS-specific in any way. If you want to become an effective programmer, you should get used to figure out this kind of thing by yourself.

 

Whenever asking a "How do I" question, it is also a good idea to add what you already thought about and tried and how it failed, so people can actually answer the question in a meaningful way without creating a complete and tested code example. This reduces the time needed to answer the question, which increases the chance to get a good answer quickly.

Posted
This kind of question is more suited to a site like stackoverflow.com, since it is not DCS-specific in any way
I think it is very much DCS related question.

 

What do you think if I ask help from stackoverflow.com guys that

"How can I send switch state value from DCS to my TCP listener only if state is changed?"

 

What is the answer??. Do they even know what DCS is.

 

But maybe I should go to stackoverflow.com cause I might found the answer from there... From here apparently I don´t get it..

 

But Thanks Any Way.!

Posted

You need to see (and solve) the more general problem.

There is a value that changes. You have a way to look at the current value repeatedly, and you want to send a message only when that value has changed.

 

Think about how you would do it as a human. If your buddy instructs you to "tell me when that light changes color", you would remember the last color you saw, compare it to the current color, and only when those two were different you would tell your buddy.

 

But maybe I should go to stackoverflow.com cause I might found the answer from there... From here apparently I don´t get it..

Without showing what you tried yourself so far, you may not have that much luck over there either.

 

Please read the intoduction of How To Ask Questions the Smart Way by Eric S. Raymond to understand my reaction here.

If you decide to come to us for help' date=' you don't want to be one of the losers. You don't want to seem like one, either. The best way to get a rapid and responsive answer is to ask it like a person with smarts, confidence, and clues who just happens to need help on one particular problem.[/quote']

Note the "you don't want to seem like one, either" part. Without showing that you tried for yourself (and making the question more specific and easier to answer in the process), you are indistinguishable from the "time sink" people who will simply ask one simple question after the other without learning anything in between.

Posted

OK, reformulate the question again, because it was apparently unclear to you.

 

But let's go back in time a little bit at first

 

1. Did you remember that I said that I am a noob with Lua programming?

 

I have read many (I think everything, depending of this State Switch stuff with .Lua) post-ED Forums, but not managed any of Those codes to work with DCS 1.2.7.23803. ((Too many information, and some out of date, and I'm noob with lua))
2. Then you (Ian) wanted to provide a DCS BIOS (yours) program to me ... And you were curious about what I do with my VB.Net application.

 

Fortunately, for the A-10C and UH-1H, That Work has Already been done for you.

Take a look at the DCS-BIOS. It exports the complete A-10C cockpit and Supports Both UDP and TCP (it acts as a TCP server).

I am curious; what is the goal of your VB.NET application?
3. And my answer to that was that ...

 

I intend to try the DCS BIOS but I have not Received my Arduino boards yet ...

 

So for the moment I'll just play for fun and to learn to do something with lua files.

4. Then, let's get to the DCS BIOS. I told you that my intention is to use it,
If you want to Become an Effective programmer, you shouldnt get used to figure out this kind of thing by yourself.
so WHY should I have to be Effective programmer ??? I'll just try this lua thing for fun.

 

Borrowed from a website page of the DCS-BIOS:

 

DCS BIOS is "easy to use".

 

... DCS-BIOS was produced so you do not have to worry about learning how to make your own Lua files.

Is your attitude (Ian) similar with DCS-BIOS program? If someone jerk like I will ask something similar?

After all, it is of course easy to criticize other people's stupid questions (if you actually know everything about everything), but in my opinion there is no stupid questions, only stupid answers. Especially when the Honourable Member has really limited information or no information at all of Lua programming or from something which there is no practical experience.

 

5. Let's go to the question ...

 

Why are you even bothering to answer my stupid questions?

 

Posted
OK, reformulate the question again, because it was apparently unclear to you.

5. Let's go to the question ...

 

Why are you even bothering to answer my stupid questions?

I get the impression you are more interested in a flame war than getting an answer to your question. Since flame wars are a time sink, I will no longer bother.

 

Your first question was a "this is how far I got and here is how I got stuck", so I answered it.

Your second one was just "how do I do X?". I reacted because it was a follow-up to the first one. I did not answer the question because without knowing more about your understanding of the problem, I have to assume you know absolutely nothing. Which means I would have to start by teaching you how to use a text editor. Which means I don't have the time to answer your question at an appropriate level of detail.

 

"I am a noob at Lua" is no excuse for asking a simple question. "I am a noob at Lua, read through the Lua manuals and got stuck at this specific place" is.

Posted
Ian;2304517']The cockpit state is stored as floating point values. Each floating point value has an "argument number" which is used to retrieve it.

The argument number for the battery power switch position in the A-10C is 246. You can get it with the following Lua code:

local batSwitchState = GetDevice(0):get_argument_value(246)

[...]

 

While I was reading this, I already learned several new things even though (or because of?) I'm vaguely familiar with the ME and the Scripting Environment. Great post, Ian, very informative! :thumbup:

 

OK, reformulate the question again, because it was apparently unclear to you. [...]

 

Your questions have been answered in a comprehensive, systematic and direct manner. I don't see how the answers given to your questions could have been more on the money.

 

The question, I guess, is: Do you want people to help you solve your problems, or do you want them to solve the problems for you? Either way, your tone doesn't make it too likely that either is going to happen around here anytime soon.

Posted
Ian;2305175']Please read the intoduction of How To Ask Questions the Smart Way by Eric S. Raymond to understand my reaction here.

 

Sorry for getting back at this, but that link is such a perfect summary!

 

Yes, it will take some 30 or 60 or 120 minutes to read and understand it, maybe even longer.

 

However, it's a one-time-commitment. Once it has been read, digested and understood, I don't see any reason why any websurfer/forum participant/whoever wouldn't be able to follow the advice laid out there.

 

That guide is not necessarily the only way to do it, but it's been around for a long time, and in the age of Twitter, Facebook, Whatsapp and Whatnot this guide has not lost a single bit of value IMO.

 

Returning to the topic at hand, I would advise the OP to read, digest and understand that guide before returning to the initial and follow-up questions.

  • 2 weeks later...
Posted

Hey all.

I would first like to apologize for my stupidity regarding the previous messages ...

 

(Ian, thank you for understanding me)

 

But, however ...

 

I have now managed to get "all" the data that I need out from sim to "my" UDP Server.

 

I use Gadroc's Export.lua file (Helios generated file) ...

 

gHost = "127.0.0.1"
gPort = 9089
gExportInterval = 0.067
gExportLowTickInterval = 1
gEveryFrameArguments = {[540]="%0.1f", [541]="%0.1f", [542]="%0.1f", [730]="%0.1f", [731]="%0.1f", [732]="%0.1f", [76]="%.4f", [77]="%.4f", [78]="%.4f", [80]="%.4f", [84]="%.4f", [85]="%.4f", [70]="%.4f", [73]="%.4f", [82]="%.4f", [83]="%.4f", [13]="%.4f", [14]="%.4f", [48]="%.4f", [12]="%.4f", [4]="%.4f", [55]="%0.1f", [17]="%.4f", [18]="%.4f", [24]="%.4f", [23]="%.4f", [25]="%0.1f", [19]="%0.1f", [26]="%0.1f", [20]="%.4f", [21]="%.4f", [27]="%.4f", [63]="%.4f", [64]="%.4f", [65]="%0.1f", [715]="%.4f", [40]="%0.1f", [32]="%0.1f", [46]="%0.1f", [34]="%.4f", [36]="%.4f", [47]="%.4f", [41]="%.4f", [33]="%.4f", [35]="%.4f", [662]="%0.1f", [663]="%0.1f", [665]="%0.1f", [664]="%0.1f", [215]="%0.1f", [216]="%0.1f", [217]="%0.1f", [404]="%0.1f", [372]="%0.1f", [373]="%0.1f", [374]="%0.1f", [654]="%1d", [659]="%0.1f", [660]="%0.1f", [661]="%0.1f", [737]="%0.1f", [653]="%.4f", [88]="%.4f", [89]="%.4f", [647]="%.4f", [648]="%.4f", [606]="%0.1f", [608]="%0.1f", [610]="%0.1f", [612]="%0.1f", [614]="%0.1f", [616]="%0.1f", [618]="%0.1f", [619]="%0.1f", [620]="%0.1f", [274]="%.4f", [604]="%.4f", [600]="%0.1f", [281]="%.4f", [289]="%1d", [480]="%0.1f", [481]="%0.1f", [482]="%0.1f", [483]="%0.1f", [484]="%0.1f", [485]="%0.1f", [486]="%0.1f", [487]="%0.1f", [488]="%0.1f", [489]="%0.1f", [490]="%0.1f", [491]="%0.1f", [492]="%0.1f", [493]="%0.1f", [494]="%0.1f", [495]="%0.1f", [496]="%0.1f", [497]="%0.1f", [498]="%0.1f", [499]="%0.1f", [500]="%0.1f", [501]="%0.1f", [502]="%0.1f", [503]="%0.1f", [504]="%0.1f", [505]="%0.1f", [506]="%0.1f", [507]="%0.1f", [508]="%0.1f", [509]="%0.1f", [510]="%0.1f", [511]="%0.1f", [512]="%0.1f", [513]="%0.1f", [514]="%0.1f", [515]="%0.1f", [516]="%0.1f", [517]="%0.1f", [518]="%0.1f", [519]="%0.1f", [520]="%0.1f", [521]="%0.1f", [522]="%0.1f", [523]="%0.1f", [524]="%0.1f", [525]="%0.1f", [526]="%0.1f", [527]="%0.1f", [260]="%0.1f", [269]="%.4f", [129]="%1d", [185]="%1d", [186]="%1d", [187]="%1d", [188]="%1d", [191]="%0.1f", [798]="%0.1f", [799]="%0.1f", [178]="%0.1f", [179]="%0.1f", [181]="%0.1f", [182]="%0.1f"}
gArguments = {[22]="%.3f", [101]="%.1f", [102]="%1d", [103]="%1d", [104]="%1d", [105]="%1d", [300]="%.1f", [301]="%.1f", [302]="%.1f", [303]="%.1f", [304]="%.1f", [305]="%.1f", [306]="%.1f", [307]="%.1f", [308]="%.1f", [309]="%.1f", [310]="%.1f", [311]="%.1f", [312]="%.1f", [313]="%.1f", [314]="%.1f", [315]="%.1f", [316]="%.1f", [317]="%.1f", [318]="%.1f", [319]="%.1f", [320]="%1d", [321]="%1d", [322]="%1d", [323]="%1d", [324]="%1d", [325]="%0.1f", [326]="%.1f", [327]="%.1f", [328]="%.1f", [329]="%.1f", [330]="%.1f", [331]="%.1f", [332]="%.1f", [333]="%.1f", [334]="%.1f", [335]="%.1f", [336]="%.1f", [337]="%.1f", [338]="%.1f", [339]="%.1f", [340]="%.1f", [341]="%.1f", [342]="%.1f", [343]="%.1f", [344]="%.1f", [345]="%.1f", [346]="%1d", [347]="%1d", [348]="%1d", [349]="%1d", [350]="%1d", [351]="%0.1f", [385]="%.1f", [386]="%.1f", [387]="%.1f", [388]="%.1f", [389]="%.1f", [390]="%.1f", [391]="%.1f", [392]="%.1f", [393]="%.1f", [395]="%.1f", [396]="%.1f", [394]="%.1f", [397]="%.1f", [398]="%.1f", [399]="%.1f", [400]="%.1f", [401]="%.1f", [402]="%.1f", [405]="%1d", [406]="%1d", [407]="%1d", [408]="%1d", [409]="%1d", [531]="%.1f", [532]="%.1f", [533]="%.1f", [403]="%.1f", [365]="%.1f", [366]="%.1f", [369]="%.1f", [370]="%.1f", [371]="%.1f", [367]="%.3f", [368]="%.3f", [716]="%1d", [655]="%0.1f", [651]="%.1f", [375]="%0.1f", [376]="%0.1f", [377]="%0.1f", [378]="%1d", [379]="%0.1f", [380]="%1d", [381]="%1d", [382]="%1d", [383]="%1d", [384]="%0.1f", [645]="%0.1f", [646]="%.1f", [605]="%.1f", [607]="%.1f", [609]="%.1f", [611]="%.1f", [613]="%.1f", [615]="%.1f", [617]="%.1f", [621]="%1d", [711]="%.1f", [622]="%0.1f", [623]="%1d", [624]="%.3f", [626]="%.3f", [636]="%0.2f", [638]="%0.2f", [640]="%0.2f", [642]="%0.2f", [644]="%1d", [628]="%.1f", [630]="%.1f", [632]="%.1f", [634]="%.1f", [410]="%.1f", [411]="%.1f", [412]="%.1f", [413]="%.1f", [414]="%.1f", [415]="%.1f", [416]="%.1f", [417]="%.1f", [418]="%.1f", [419]="%.1f", [420]="%.1f", [421]="%.1f", [422]="%.1f", [423]="%.1f", [425]="%.1f", [426]="%.1f", [427]="%.1f", [428]="%.1f", [429]="%.1f", [430]="%.1f", [431]="%.1f", [432]="%.1f", [433]="%.1f", [434]="%.1f", [435]="%.1f", [436]="%.1f", [437]="%.1f", [438]="%.1f", [439]="%.1f", [440]="%.1f", [441]="%.1f", [442]="%.1f", [443]="%.1f", [444]="%.1f", [445]="%.1f", [446]="%.1f", [447]="%.1f", [448]="%.1f", [449]="%.1f", [450]="%.1f", [451]="%.1f", [452]="%.1f", [453]="%.1f", [454]="%.1f", [455]="%.1f", [456]="%.1f", [457]="%.1f", [458]="%.1f", [459]="%.1f", [460]="%.1f", [461]="%.1f", [462]="%.1f", [466]="%.1f", [467]="%.1f", [468]="%.1f", [470]="%.1f", [471]="%.1f", [424]="%1d", [463]="%1d", [469]="%1d", [472]="%1d", [241]="%1d", [242]="%1d", [243]="%1d", [244]="%1d", [245]="%1d", [246]="%1d", [601]="%1d", [602]="%1d", [603]="%1d", [712]="%0.2f", [352]="%.1f", [353]="%.1f", [354]="%.1f", [355]="%.1f", [356]="%1d", [357]="%.1f", [358]="%1d", [359]="%.3f", [360]="%0.1f", [361]="%0.1f", [362]="%0.1f", [363]="%0.1f", [364]="%0.1f", [275]="%.1f", [276]="%1d", [277]="%.3f", [278]="%1d", [279]="%1d", [280]="%1d", [282]="%1d", [283]="%1d", [284]="%.3f", [287]="%1d", [288]="%.3f", [290]="%.3f", [291]="%1d", [292]="%.3f", [293]="%.3f", [294]="%1d", [295]="%1d", [296]="%.3f", [297]="%.3f", [258]="%0.2f", [259]="%.1f", [261]="%.3f", [262]="%0.1f", [266]="%1d", [247]="%1d", [248]="%0.1f", [250]="%0.1f", [249]="%.3f", [251]="%0.1f", [252]="%0.1f", [270]="%1d", [273]="%1d", [272]="%1d", [271]="%.3f", [267]="%.1f", [268]="%.3f", [473]="%0.1f", [474]="%1d", [475]="%0.1f", [476]="%1d", [477]="%1d", [106]="%1d", [107]="%1d", [108]="%1d", [109]="%1d", [110]="%1d", [111]="%1d", [112]="%1d", [113]="%1d", [114]="%1d", [115]="%.1f", [117]="%1d", [118]="%1d", [119]="%1d", [120]="%1d", [121]="%1d", [116]="%.3f", [122]="%1d", [123]="%1d", [124]="%1d", [125]="%1d", [126]="%1d", [127]="%.1f", [132]="%1d", [131]="%.1f", [130]="%1d", [137]="%0.3f", [138]="%0.1f", [135]="%0.1f", [133]="%.3f", [136]="%.1f", [134]="%1d", [139]="%0.2f", [140]="%0.2f", [141]="%0.2f", [142]="%0.2f", [151]="%0.3f", [153]="%0.2f", [154]="%0.2f", [155]="%0.2f", [156]="%0.2f", [152]="%0.1f", [149]="%0.1f", [147]="%.3f", [150]="%.1f", [148]="%1d", [189]="%1d", [190]="%.1f", [192]="%.3f", [197]="%.1f", [196]="%1d", [193]="%.3f", [195]="%.3f", [194]="%0.1f", [198]="%.1f", [161]="%0.2f", [162]="%0.1f", [163]="%0.2f", [164]="%0.2f", [165]="%0.2f", [166]="%0.2f", [167]="%0.1f", [168]="%0.1f", [169]="%1d", [170]="%1d", [171]="%.3f", [172]="%.1f", [173]="%.1f", [735]="%.1f", [734]="%1d", [779]="%1d", [778]="%1d", [780]="%1d", [781]="%0.1f", [782]="%0.1f", [783]="%0.1f", [784]="%1d", [772]="%1d", [199]="%0.1f", [200]="%0.1f", [201]="%1d", [202]="%1d", [203]="%1d", [204]="%1d", [205]="%1d", [206]="%1d", [207]="%1d", [208]="%1d", [209]="%0.2f", [210]="%0.2f", [211]="%0.2f", [212]="%0.2f", [213]="%0.2f", [214]="%0.2f", [174]="%1d", [175]="%1d", [176]="%0.1f", [177]="%1d", [180]="%1d", [183]="%1d", [184]="%1d", [221]="%.3f", [222]="%1d", [223]="%.3f", [224]="%1d", [225]="%.3f", [226]="%1d", [227]="%.3f", [228]="%1d", [229]="%.3f", [230]="%1d", [231]="%.3f", [232]="%1d", [233]="%.3f", [234]="%1d", [235]="%.3f", [236]="%1d", [237]="%1d", [238]="%.3f", [239]="%0.1f", [240]="%.1f", [704]="%.3f", [705]="%.3f", [718]="%1d", [722]="%.1f", [733]="%1d"}

function ProcessHighImportance(mainPanelDevice)
   -- Send Altimeter Values    
   SendData(2051, string.format("%0.4f;%0.4f;%0.5f", mainPanelDevice:get_argument_value(52), mainPanelDevice:get_argument_value(53), mainPanelDevice:get_argument_value(51)))
   SendData(2059, string.format("%0.2f;%0.2f;%0.2f;%0.3f", mainPanelDevice:get_argument_value(56), mainPanelDevice:get_argument_value(57), mainPanelDevice:get_argument_value(58), mainPanelDevice:get_argument_value(59)))        
   -- Calcuate HSI Value
   SendData(2029, string.format("%0.2f;%0.2f;%0.4f", mainPanelDevice:get_argument_value(29), mainPanelDevice:get_argument_value(30), mainPanelDevice:get_argument_value(31)))
   -- Calculate Total Fuel
   SendData(2090, string.format("%0.2f;%0.2f;%0.5f", mainPanelDevice:get_argument_value(90), mainPanelDevice:get_argument_value(91), mainPanelDevice:get_argument_value(92)))
end

function ProcessLowImportance(mainPanelDevice)
   -- Get Radio Frequencies
   local lUHFRadio = GetDevice(54)
   SendData(2000, string.format("%7.3f", lUHFRadio:get_frequency()/1000000))
   -- ILS Frequency
   --SendData(2251, string.format("%0.1f;%0.1f", mainPanelDevice:get_argument_value(251), mainPanelDevice:get_argument_value(252)))
   -- TACAN Channel
   SendData(2263, string.format("%0.2f;%0.2f;%0.2f", mainPanelDevice:get_argument_value(263), mainPanelDevice:get_argument_value(264), mainPanelDevice:get_argument_value(265)))
end

os.setlocale("ISO-8559-1", "numeric")

-- Simulation id
gSimID = string.format("%08x*",os.time())

-- State data for export
gPacketSize = 0
gSendStrings = {}
gLastData = {}

-- Frame counter for non important data
gTickCount = 0

-- DCS Export Functions
function LuaExportStart()
-- Works once just before mission start.
   
   -- 2) Setup udp sockets to talk to helios
   package.path  = package.path..";.\\LuaSocket\\?.lua"
   package.cpath = package.cpath..";.\\LuaSocket\\?.dll"
  
   socket = require("socket")
   
   c = socket.udp()
   c:setsockname("*", 0)
   c:setoption('broadcast', true)
   c:settimeout(.001) -- set the timeout for reading the socket 
end

function LuaExportBeforeNextFrame()
   ProcessInput()
end

function LuaExportAfterNextFrame()    
end

function LuaExportStop()
-- Works once just after mission stop.
   c:close()
end

function ProcessInput()
   local lInput = c:receive()
   local lCommand, lCommandArgs, lDevice, lArgument, lLastValue
   
   if lInput then
   
       lCommand = string.sub(lInput,1,1)
       
       if lCommand == "R" then
           ResetChangeValues()
       end
   
       if (lCommand == "C") then
           lCommandArgs = StrSplit(string.sub(lInput,2),",")
           lDevice = GetDevice(lCommandArgs[1])
           if type(lDevice) == "table" then
               lDevice:performClickableAction(lCommandArgs[2],lCommandArgs[3])    
           end
       end
   end 
end

function LuaExportActivityNextEvent(t)
   t = t + gExportInterval

   gTickCount = gTickCount + 1

   local lDevice = GetDevice(0)
   if type(lDevice) == "table" then
       lDevice:update_arguments()

       ProcessArguments(lDevice, gEveryFrameArguments)
       ProcessHighImportance(lDevice)

       if gTickCount >= gExportLowTickInterval then
           ProcessArguments(lDevice, gArguments)
           ProcessLowImportance(lDevice)
           gTickCount = 0
       end

       FlushData()
   end

   return t
end

-- Helper Functions
function StrSplit(str, delim, maxNb)
   -- Eliminate bad cases...
   if string.find(str, delim) == nil then
       return { str }
   end
   if maxNb == nil or maxNb < 1 then
       maxNb = 0    -- No limit
   end
   local result = {}
   local pat = "(.-)" .. delim .. "()"
   local nb = 0
   local lastPos
   for part, pos in string.gfind(str, pat) do
       nb = nb + 1
       result[nb] = part
       lastPos = pos
       if nb == maxNb then break end
   end
   -- Handle the last field
   if nb ~= maxNb then
       result[nb + 1] = string.sub(str, lastPos)
   end
   return result
end

function round(num, idp)
 local mult = 10^(idp or 0)
 return math.floor(num * mult + 0.5) / mult
end

-- Status Gathering Functions
function ProcessArguments(device, arguments)
   local lArgument , lFormat , lArgumentValue
       
   for lArgument, lFormat in pairs(arguments) do 
       lArgumentValue = string.format(lFormat,device:get_argument_value(lArgument))
       SendData(lArgument, lArgumentValue)
   end
end

-- Network Functions
function SendData(id, value)    
   if string.len(value) > 3 and value == string.sub("-0.00000000",1, string.len(value)) then
       value = value:sub(2)
   end
   
   if gLastData[id] == nil or gLastData[id] ~= value then
       local data =  id .. "=" .. value
       local dataLen = string.len(data)

       if dataLen + gPacketSize > 576 then
           FlushData()
       end

       table.insert(gSendStrings, data)
       gLastData[id] = value    
       gPacketSize = gPacketSize + dataLen + 1
   end    
end

function FlushData()
   if #gSendStrings > 0 then
       local packet = gSimID .. table.concat(gSendStrings, ":") .. "\n"
       socket.try(c:sendto(packet, gHost, gPort))
       gSendStrings = {}
       gPacketSize = 0
   end
end

function ResetChangeValues()
   gLastData = {}
   gTickCount = 10
end

I understand that I have a "connection" to the DCS because I get data out fom the sim, but I am unable to send anything back to the sim.

 

if I understand correctly... I should send a command from the UDP Server "C0,3006,1" to the DCS. and it should change the Battery Power button to ON .... "C0,3006, -1" to OFF. but nothing happens ...

 

function ProcessInput()     local lInput = c:receive()     local lCommand, lCommandArgs, lDevice, lArgument, lLastValue          if lInput then              lCommand = string.sub(lInput,1,1)                  if lCommand == "R" then             ResetChangeValues()         end              if (lCommand == "C") then             lCommandArgs = StrSplit(string.sub(lInput,2),",")             lDevice = GetDevice(lCommandArgs[1])             if type(lDevice) == "table" then                 lDevice:performClickableAction(lCommandArgs[2],lCommandArgs[3])                 end         end     end  end

If I use a program called "Echotool" I get ALL the data from the DCS and UDP Server (sent and received data) but DCS does not accept the data transmitted for processing.

 

So do I have to change something in Export.lua. Or is the problem in "my" UDP server.

 

OK, once again, the shit translation by GOOGLE TRANSLATOR (just tried to fix it ...somehow)

 

HarSu.

Posted

You will need to assign a port to the socket to receive on, I am no lua expert like some of these guys so am not sure of the correct way of doing things, but what worked for me was to create a second socket just to receive on.

Posted

HarSu, you could instead try and chaange this line of code c:setsockname("*", 0) to 'c:setsockname("*", port_number)'

where port_number is the port to receive on.''

  • Like 1
Posted

Sorry HarSu I never sent you that export.lua since it is for TCP. The battery switch is part of the "ELEC_INTERFACE" device which is C1 and not C0.

 

I had never seen lua before until I found DCS so I am still quite new to the language. I had to get a friend to help create the files for A2DCS and did not use UDP.

Posted (edited)

Hi.

 

HarSu, you could instead try and chaange this line of code c:setsockname("*", 0) to 'c:setsockname("*", port_number)'

where port_number is the port to receive on.''

:thumbup: Thanks cefs, you are my HERO!! :clap_2:

 

Now everything works as it should, and the Helios Also still runs like it should, and everything works in sync. So I'm really happy with your advice cefs.

 

Reputation may send to you, I just do not know how to, yet..

 

Sorry HarSu I never sent you that export.lua since it is for TCP. The battery switch is part of the "ELEC_INTERFACE" device which is C1 and not C0.
Boltz

 

There is no problem at all, but maybe at some point I have to ask for advice with Arduino Boards from you.

 

And you're right, For the battery switch command should be started by C1 NOT C0. I know that, but I seem to have accidentally entered (in the middle of the night, no actually in the morning) command C0. Sorry about that.

 

So here is Export.lua file. Which is able to receive and send data to the DCS even if you are also using Helios. Only one line must be changed (line 52) and the 1 line to add (line 183).

 

gHost = "127.0.0.1"
gPort = 9089
gExportInterval = 0.067
gExportLowTickInterval = 1
gEveryFrameArguments = {[540]="%0.1f", [541]="%0.1f", [542]="%0.1f", [730]="%0.1f", [731]="%0.1f", [732]="%0.1f", [76]="%.4f", [77]="%.4f", [78]="%.4f", [80]="%.4f", [84]="%.4f", [85]="%.4f", [70]="%.4f", [73]="%.4f", [82]="%.4f", [83]="%.4f", [13]="%.4f", [14]="%.4f", [48]="%.4f", [12]="%.4f", [4]="%.4f", [55]="%0.1f", [17]="%.4f", [18]="%.4f", [24]="%.4f", [23]="%.4f", [25]="%0.1f", [19]="%0.1f", [26]="%0.1f", [20]="%.4f", [21]="%.4f", [27]="%.4f", [63]="%.4f", [64]="%.4f", [65]="%0.1f", [715]="%.4f", [40]="%0.1f", [32]="%0.1f", [46]="%0.1f", [34]="%.4f", [36]="%.4f", [47]="%.4f", [41]="%.4f", [33]="%.4f", [35]="%.4f", [662]="%0.1f", [663]="%0.1f", [665]="%0.1f", [664]="%0.1f", [215]="%0.1f", [216]="%0.1f", [217]="%0.1f", [404]="%0.1f", [372]="%0.1f", [373]="%0.1f", [374]="%0.1f", [654]="%1d", [659]="%0.1f", [660]="%0.1f", [661]="%0.1f", [737]="%0.1f", [653]="%.4f", [88]="%.4f", [89]="%.4f", [647]="%.4f", [648]="%.4f", [606]="%0.1f", [608]="%0.1f", [610]="%0.1f", [612]="%0.1f", [614]="%0.1f", [616]="%0.1f", [618]="%0.1f", [619]="%0.1f", [620]="%0.1f", [274]="%.4f", [604]="%.4f", [600]="%0.1f", [281]="%.4f", [289]="%1d", [480]="%0.1f", [481]="%0.1f", [482]="%0.1f", [483]="%0.1f", [484]="%0.1f", [485]="%0.1f", [486]="%0.1f", [487]="%0.1f", [488]="%0.1f", [489]="%0.1f", [490]="%0.1f", [491]="%0.1f", [492]="%0.1f", [493]="%0.1f", [494]="%0.1f", [495]="%0.1f", [496]="%0.1f", [497]="%0.1f", [498]="%0.1f", [499]="%0.1f", [500]="%0.1f", [501]="%0.1f", [502]="%0.1f", [503]="%0.1f", [504]="%0.1f", [505]="%0.1f", [506]="%0.1f", [507]="%0.1f", [508]="%0.1f", [509]="%0.1f", [510]="%0.1f", [511]="%0.1f", [512]="%0.1f", [513]="%0.1f", [514]="%0.1f", [515]="%0.1f", [516]="%0.1f", [517]="%0.1f", [518]="%0.1f", [519]="%0.1f", [520]="%0.1f", [521]="%0.1f", [522]="%0.1f", [523]="%0.1f", [524]="%0.1f", [525]="%0.1f", [526]="%0.1f", [527]="%0.1f", [260]="%0.1f", [269]="%.4f", [129]="%1d", [185]="%1d", [186]="%1d", [187]="%1d", [188]="%1d", [191]="%0.1f", [798]="%0.1f", [799]="%0.1f", [178]="%0.1f", [179]="%0.1f", [181]="%0.1f", [182]="%0.1f"}
gArguments = {[22]="%.3f", [101]="%.1f", [102]="%1d", [103]="%1d", [104]="%1d", [105]="%1d", [300]="%.1f", [301]="%.1f", [302]="%.1f", [303]="%.1f", [304]="%.1f", [305]="%.1f", [306]="%.1f", [307]="%.1f", [308]="%.1f", [309]="%.1f", [310]="%.1f", [311]="%.1f", [312]="%.1f", [313]="%.1f", [314]="%.1f", [315]="%.1f", [316]="%.1f", [317]="%.1f", [318]="%.1f", [319]="%.1f", [320]="%1d", [321]="%1d", [322]="%1d", [323]="%1d", [324]="%1d", [325]="%0.1f", [326]="%.1f", [327]="%.1f", [328]="%.1f", [329]="%.1f", [330]="%.1f", [331]="%.1f", [332]="%.1f", [333]="%.1f", [334]="%.1f", [335]="%.1f", [336]="%.1f", [337]="%.1f", [338]="%.1f", [339]="%.1f", [340]="%.1f", [341]="%.1f", [342]="%.1f", [343]="%.1f", [344]="%.1f", [345]="%.1f", [346]="%1d", [347]="%1d", [348]="%1d", [349]="%1d", [350]="%1d", [351]="%0.1f", [385]="%.1f", [386]="%.1f", [387]="%.1f", [388]="%.1f", [389]="%.1f", [390]="%.1f", [391]="%.1f", [392]="%.1f", [393]="%.1f", [395]="%.1f", [396]="%.1f", [394]="%.1f", [397]="%.1f", [398]="%.1f", [399]="%.1f", [400]="%.1f", [401]="%.1f", [402]="%.1f", [405]="%1d", [406]="%1d", [407]="%1d", [408]="%1d", [409]="%1d", [531]="%.1f", [532]="%.1f", [533]="%.1f", [403]="%.1f", [365]="%.1f", [366]="%.1f", [369]="%.1f", [370]="%.1f", [371]="%.1f", [367]="%.3f", [368]="%.3f", [716]="%1d", [655]="%0.1f", [651]="%.1f", [375]="%0.1f", [376]="%0.1f", [377]="%0.1f", [378]="%1d", [379]="%0.1f", [380]="%1d", [381]="%1d", [382]="%1d", [383]="%1d", [384]="%0.1f", [645]="%0.1f", [646]="%.1f", [605]="%.1f", [607]="%.1f", [609]="%.1f", [611]="%.1f", [613]="%.1f", [615]="%.1f", [617]="%.1f", [621]="%1d", [711]="%.1f", [622]="%0.1f", [623]="%1d", [624]="%.3f", [626]="%.3f", [636]="%0.2f", [638]="%0.2f", [640]="%0.2f", [642]="%0.2f", [644]="%1d", [628]="%.1f", [630]="%.1f", [632]="%.1f", [634]="%.1f", [410]="%.1f", [411]="%.1f", [412]="%.1f", [413]="%.1f", [414]="%.1f", [415]="%.1f", [416]="%.1f", [417]="%.1f", [418]="%.1f", [419]="%.1f", [420]="%.1f", [421]="%.1f", [422]="%.1f", [423]="%.1f", [425]="%.1f", [426]="%.1f", [427]="%.1f", [428]="%.1f", [429]="%.1f", [430]="%.1f", [431]="%.1f", [432]="%.1f", [433]="%.1f", [434]="%.1f", [435]="%.1f", [436]="%.1f", [437]="%.1f", [438]="%.1f", [439]="%.1f", [440]="%.1f", [441]="%.1f", [442]="%.1f", [443]="%.1f", [444]="%.1f", [445]="%.1f", [446]="%.1f", [447]="%.1f", [448]="%.1f", [449]="%.1f", [450]="%.1f", [451]="%.1f", [452]="%.1f", [453]="%.1f", [454]="%.1f", [455]="%.1f", [456]="%.1f", [457]="%.1f", [458]="%.1f", [459]="%.1f", [460]="%.1f", [461]="%.1f", [462]="%.1f", [466]="%.1f", [467]="%.1f", [468]="%.1f", [470]="%.1f", [471]="%.1f", [424]="%1d", [463]="%1d", [469]="%1d", [472]="%1d", [241]="%1d", [242]="%1d", [243]="%1d", [244]="%1d", [245]="%1d", [246]="%1d", [601]="%1d", [602]="%1d", [603]="%1d", [712]="%0.2f", [352]="%.1f", [353]="%.1f", [354]="%.1f", [355]="%.1f", [356]="%1d", [357]="%.1f", [358]="%1d", [359]="%.3f", [360]="%0.1f", [361]="%0.1f", [362]="%0.1f", [363]="%0.1f", [364]="%0.1f", [275]="%.1f", [276]="%1d", [277]="%.3f", [278]="%1d", [279]="%1d", [280]="%1d", [282]="%1d", [283]="%1d", [284]="%.3f", [287]="%1d", [288]="%.3f", [290]="%.3f", [291]="%1d", [292]="%.3f", [293]="%.3f", [294]="%1d", [295]="%1d", [296]="%.3f", [297]="%.3f", [258]="%0.2f", [259]="%.1f", [261]="%.3f", [262]="%0.1f", [266]="%1d", [247]="%1d", [248]="%0.1f", [250]="%0.1f", [249]="%.3f", [251]="%0.1f", [252]="%0.1f", [270]="%1d", [273]="%1d", [272]="%1d", [271]="%.3f", [267]="%.1f", [268]="%.3f", [473]="%0.1f", [474]="%1d", [475]="%0.1f", [476]="%1d", [477]="%1d", [106]="%1d", [107]="%1d", [108]="%1d", [109]="%1d", [110]="%1d", [111]="%1d", [112]="%1d", [113]="%1d", [114]="%1d", [115]="%.1f", [117]="%1d", [118]="%1d", [119]="%1d", [120]="%1d", [121]="%1d", [116]="%.3f", [122]="%1d", [123]="%1d", [124]="%1d", [125]="%1d", [126]="%1d", [127]="%.1f", [132]="%1d", [131]="%.1f", [130]="%1d", [137]="%0.3f", [138]="%0.1f", [135]="%0.1f", [133]="%.3f", [136]="%.1f", [134]="%1d", [139]="%0.2f", [140]="%0.2f", [141]="%0.2f", [142]="%0.2f", [151]="%0.3f", [153]="%0.2f", [154]="%0.2f", [155]="%0.2f", [156]="%0.2f", [152]="%0.1f", [149]="%0.1f", [147]="%.3f", [150]="%.1f", [148]="%1d", [189]="%1d", [190]="%.1f", [192]="%.3f", [197]="%.1f", [196]="%1d", [193]="%.3f", [195]="%.3f", [194]="%0.1f", [198]="%.1f", [161]="%0.2f", [162]="%0.1f", [163]="%0.2f", [164]="%0.2f", [165]="%0.2f", [166]="%0.2f", [167]="%0.1f", [168]="%0.1f", [169]="%1d", [170]="%1d", [171]="%.3f", [172]="%.1f", [173]="%.1f", [735]="%.1f", [734]="%1d", [779]="%1d", [778]="%1d", [780]="%1d", [781]="%0.1f", [782]="%0.1f", [783]="%0.1f", [784]="%1d", [772]="%1d", [199]="%0.1f", [200]="%0.1f", [201]="%1d", [202]="%1d", [203]="%1d", [204]="%1d", [205]="%1d", [206]="%1d", [207]="%1d", [208]="%1d", [209]="%0.2f", [210]="%0.2f", [211]="%0.2f", [212]="%0.2f", [213]="%0.2f", [214]="%0.2f", [174]="%1d", [175]="%1d", [176]="%0.1f", [177]="%1d", [180]="%1d", [183]="%1d", [184]="%1d", [221]="%.3f", [222]="%1d", [223]="%.3f", [224]="%1d", [225]="%.3f", [226]="%1d", [227]="%.3f", [228]="%1d", [229]="%.3f", [230]="%1d", [231]="%.3f", [232]="%1d", [233]="%.3f", [234]="%1d", [235]="%.3f", [236]="%1d", [237]="%1d", [238]="%.3f", [239]="%0.1f", [240]="%.1f", [704]="%.3f", [705]="%.3f", [718]="%1d", [722]="%.1f", [733]="%1d"}

function ProcessHighImportance(mainPanelDevice)
   -- Send Altimeter Values    
   SendData(2051, string.format("%0.4f;%0.4f;%0.5f", mainPanelDevice:get_argument_value(52), mainPanelDevice:get_argument_value(53), mainPanelDevice:get_argument_value(51)))
   SendData(2059, string.format("%0.2f;%0.2f;%0.2f;%0.3f", mainPanelDevice:get_argument_value(56), mainPanelDevice:get_argument_value(57), mainPanelDevice:get_argument_value(58), mainPanelDevice:get_argument_value(59)))        
   -- Calcuate HSI Value
   SendData(2029, string.format("%0.2f;%0.2f;%0.4f", mainPanelDevice:get_argument_value(29), mainPanelDevice:get_argument_value(30), mainPanelDevice:get_argument_value(31)))
   -- Calculate Total Fuel
   SendData(2090, string.format("%0.2f;%0.2f;%0.5f", mainPanelDevice:get_argument_value(90), mainPanelDevice:get_argument_value(91), mainPanelDevice:get_argument_value(92)))
end

function ProcessLowImportance(mainPanelDevice)
   -- Get Radio Frequencies
   local lUHFRadio = GetDevice(54)
   SendData(2000, string.format("%7.3f", lUHFRadio:get_frequency()/1000000))
   -- ILS Frequency
   --SendData(2251, string.format("%0.1f;%0.1f", mainPanelDevice:get_argument_value(251), mainPanelDevice:get_argument_value(252)))
   -- TACAN Channel
   SendData(2263, string.format("%0.2f;%0.2f;%0.2f", mainPanelDevice:get_argument_value(263), mainPanelDevice:get_argument_value(264), mainPanelDevice:get_argument_value(265)))
end

os.setlocale("ISO-8559-1", "numeric")

-- Simulation id
gSimID = string.format("%08x*",os.time())

-- State data for export
gPacketSize = 0
gSendStrings = {}
gLastData = {}

-- Frame counter for non important data
gTickCount = 0

-- DCS Export Functions
function LuaExportStart()
-- Works once just before mission start.
   
   -- 2) Setup udp sockets to talk to helios
   package.path  = package.path..";.\\LuaSocket\\?.lua"
   package.cpath = package.cpath..";.\\LuaSocket\\?.dll"
  
   socket = require("socket")
   
   c = socket.udp()
   c:setsockname("*", 9801) -- CHANGE THIS .........enter the UDP port forsending from your server .. the original was "c: setsockname ("*", 0)"
   c:setoption('broadcast', true)
   c:settimeout(.001) -- set the timeout for reading the socket 
   
end

function LuaExportBeforeNextFrame()
   ProcessInput()
end

function LuaExportAfterNextFrame()    
end

function LuaExportStop()
-- Works once just after mission stop.
   c:close()
   b:close()
end

function ProcessInput()
   local lInput = c:receive()
   --local lInput = b:receive()
   local lCommand, lCommandArgs, lDevice, lArgument, lLastValue
   
   if lInput then
   
       lCommand = string.sub(lInput,1,1)
       
       if lCommand == "R" then
           ResetChangeValues()
       end
   
       if (lCommand == "C") then
           lCommandArgs = StrSplit(string.sub(lInput,2),",")
           lDevice = GetDevice(lCommandArgs[1])
           if type(lDevice) == "table" then
               lDevice:performClickableAction(lCommandArgs[2],lCommandArgs[3])    
           end
       end
   end 
end

function LuaExportActivityNextEvent(t)
   t = t + gExportInterval

   gTickCount = gTickCount + 1

   local lDevice = GetDevice(0)
   if type(lDevice) == "table" then
       lDevice:update_arguments()

       ProcessArguments(lDevice, gEveryFrameArguments)
       ProcessHighImportance(lDevice)

       if gTickCount >= gExportLowTickInterval then
           ProcessArguments(lDevice, gArguments)
           ProcessLowImportance(lDevice)
           gTickCount = 0
       end

       FlushData()
   end

   return t
end

-- Helper Functions
function StrSplit(str, delim, maxNb)
   -- Eliminate bad cases...
   if string.find(str, delim) == nil then
       return { str }
   end
   if maxNb == nil or maxNb < 1 then
       maxNb = 0    -- No limit
   end
   local result = {}
   local pat = "(.-)" .. delim .. "()"
   local nb = 0
   local lastPos
   for part, pos in string.gfind(str, pat) do
       nb = nb + 1
       result[nb] = part
       lastPos = pos
       if nb == maxNb then break end
   end
   -- Handle the last field
   if nb ~= maxNb then
       result[nb + 1] = string.sub(str, lastPos)
   end
   return result
end

function round(num, idp)
 local mult = 10^(idp or 0)
 return math.floor(num * mult + 0.5) / mult
end

-- Status Gathering Functions
function ProcessArguments(device, arguments)
   local lArgument , lFormat , lArgumentValue
       
   for lArgument, lFormat in pairs(arguments) do 
       lArgumentValue = string.format(lFormat,device:get_argument_value(lArgument))
       SendData(lArgument, lArgumentValue)
   end
end

-- Network Functions
function SendData(id, value)    
   if string.len(value) > 3 and value == string.sub("-0.00000000",1, string.len(value)) then
       value = value:sub(2)
   end
   
   if gLastData[id] == nil or gLastData[id] ~= value then
       local data =  id .. "=" .. value
       local dataLen = string.len(data)

       if dataLen + gPacketSize > 576 then
           FlushData()
       end

       table.insert(gSendStrings, data)
       gLastData[id] = value    
       gPacketSize = gPacketSize + dataLen + 1
   end    
end

function FlushData()
   if #gSendStrings > 0 then
       local packet = gSimID .. table.concat(gSendStrings, ":") .. "\n"
       socket.try(c:sendto(packet, gHost, gPort))
       socket.try(c:sendto(packet, gHost, 9800)) -- ADD THIS LINE TO RECEIVE DATA TO YOUR UDP SERVER - Port number is your UDP Server Port.
       gSendStrings = {}
       gPacketSize = 0
   end
end

function ResetChangeValues()
   gLastData = {}
   gTickCount = 10
end


HarSu.

Edited by HarSu
Code error
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...