Что оказалось для меня совсем не простой задачей. Тем более, что программа управления кабиной должна находиться на другом компьютере. Но надеюсь с помощью коллег по симулятору эту проблему решить.
Как известно работа с этой программой обеспечивается за счет взаимодействия по протоколу TCP.
Механизм работы примерно следующий : программа связи симулятора со внешними устройствами создает TCP «сервер» (ведущий процесс) , который ( упрощенно ) является областью в памяти компьютера .
Эту область программа связи симулятора с внешними устройствами постоянно прослушивает. В свою очередь ЛокОн создает «клиент» ( то есть ведомый процесс ) который постоянно передает в эту область данные. Увидев наличие данных программа связи должна считать их, и преобразовав выдать во внешние устройства. Лок Он при запуске анализирует, создан ли сервер. Если сервер не создан, то Лок Он не будет передавать данные. Таким образом, для корректной работы необходимо СНАЧАЛА запустить программу связи (сервер), и только после этого ЛокОн.
По совету Андрея (Lisa) попробуем применить такую схему:
Lock On => Lua => TCP/IP => Sioc => клиент => приборы.
SIOC используется исключительно как сервер на который Lock On посылает данные.
Для того , чтобы ЛокОн начал работать с созданным сервером необходимо :
— объяснить программе, что она должна работать по TCP.
— указать программе область памяти ( или сетевой адрес ) в который ей необходимо передавать данные.
— указать программе объем данных ( параметры ), который необходимо передавать .
— сформировав сервер дождаться начала обмена данными .
Эта последовательность действий обеспечивается следующим образом.
1. В файле …1CEagle DinamicsLOConfigExportConfig.lua
найти строку EnableExportScript = false ( в принципе она одна там и есть )…
и исправить её так :EnableExportScript = true
Этим мы дадим знать ЛокОн что ему необходимо начать работать на передачу (экспорт)
данных.
2. Заменитьфайл …1CEagle DinamicsLOConfigExportExport.lua
на одноименный файл , ( то есть с нашими данными )
Желательно старый файл не удалять а переименовать (на всякий случай ).
В этом файле находятся :
— настройки TCP ( номер порта и номер хоста )
— ————————————————————
—процедурыоткрытияпорта
functionLuaExportStart()
package.path =package.path..»;.\LuaSocket\?.lua»
package.cpath =package.cpath..»;.\LuaSocket\?.dll»
socket =require(«socket»)
host =»192.168.10.190″—сетевойадресSIOC
port =8092– порт SIOC
c = socket.try(socket.connect(host, port))
c:setoption(«tcp-nodelay»,true)
c:settimeout(.01)
end
————————————————————————————
—значения»host»и»port»поумолчаниюдляSIOC
host – сетевой адрес компьютера на котором установлен сервер.
Запускаем SIOC сервер, затем LockOn, выбираем миссию. Компьютеры связаны по локальной сети.
В строчке «Clientsconnecteds» должны увидеть, сколько клиентов подключены. Если соединение получилось уже хорошо.
Прикрепленные изображения
Сообщение отредактировал ra3dcs: 08 September 2012 — 14:44
— эта функция выполняется после отрисовки каждого кадра
function LuaExportAfterNextFrame()
local lSIOC_SendString = «»
local TAS = LoGetTrueAirSpeed()* 3.6 — получаем значение истинной скорости
local IAS = LoGetIndicatedAirSpeed()* 3.6 — получаем значение прибрной скорости
local AOA = LoGetAngleOfAttack() — угол атаки
local Gp = LoGetAccelerationUnits() — перегрузка
local VV = LoGetVerticalVelocity() — вертскорость
local altBar = LoGetAltitudeAboveSeaLevel()
local altRad = LoGetAltitudeAboveGroundLevel()
local pitch, bank, yaw = LoGetADIPitchBankYaw()
local Mach = LoGetMachNumber()
local HSI = LoGetControlPanel_HSI()
local engine = LoGetEngineInfo()
local route = LoGetRoute()
local PlaneID = LoGetPlayerPlaneId()
local obj = LoGetObjectById(PlaneID)
local myXCoord, myZCoord = getXYCoords(obj.LatLongAlt.Lat, obj.LatLongAlt.Long)
local navi = LoGetNavigationInfo()
R0 = TAS
R1 = IAS
R2 = AOA*ToDegree
R3 = Gp.y
R4 = VV
R5 = altBar
R6 = altRad
— округляем значение до целого
R0 = math.floor(R0 + 0.5)
R1 = math.floor(R1 + 0.5)
R2 = math.floor(R2 + 0.5)
R3 = math.floor(R3 + 0.5)
R4 = math.floor(R4 + 0.5)
R5 = math.floor(R5 + 0.5)
R6 = math.floor(R6 + 0.5)
— формируем строчку номер переменной = значение
R0 = «0=»..R0..»:»
R1 = «1=»..R1..»:»
R2 = «2=»..R2..»:»
R3 = «3=»..R3..»:»
R4 = «4=»..R4..»:»
R5 = «5=»..R5..»:»
R6 = «6=»..R6..»:»
— записываемстрочку
lSIOC_SendString = lSIOC_SendString..R0
lSIOC_SendString = lSIOC_SendString..R1
lSIOC_SendString = lSIOC_SendString..R2
lSIOC_SendString = lSIOC_SendString..R3
lSIOC_SendString = lSIOC_SendString..R4
lSIOC_SendString = lSIOC_SendString..R5
lSIOC_SendString = lSIOC_SendString..R6
— отправляем
if lSIOC_SendString ~= «» then
socket.try(c:send(«Arn.Resp:»..lSIOC_SendString..»n»))
end
end
— процедурызакрытияпорта
function LuaExportStop()
io.close()
socket.try(c:send(«quit»)) — to close the listener socket
c:close()
end
——————————————————————
Приведенный Андреем (Lisa) пример формирования строки переменной для SIOC выглядит очень громоздким. Если, к примеру, мне нужно 50 переменных понадобиться писать более 200 строк?
Наверно существует другой способ записи, может, кто знает и подскажет?
Сообщение отредактировал ra3dcs: 08 September 2012 — 21:03
ra3dcs (08 September 2012 — 21:02) писал:
Если этот язык программирования поддерживает массивы и циклы, то, очевидно, надо данные сложить в массив и отправить их в цикле. А приведенный вами код тоже не самый удачный — в нем все переменные складываются в одну строку и отсылаются все скопом если изменилась хотя бы одна переменная. По-хорошему надо отсылать только те переменные, которые не изменились. Описание этого языка программирования доступно? Я мог бы почитать его и что-нибудь присоветовать…
САБ (09 September 2012 — 02:17) писал:
Нет, даже хуже -все переменные отсылаются при каждом проходе этой функции. Условие if lSIOC_SendString ~= «» then будет истинно всегда, ибо перед этим мы заносили в строку значения переменных: lSIOC_SendString = lSIOC_SendString..R0. Тут бы добавить глобальную переменную lSIOC_SendStringPrev и сравнивать с ней, а обновлять ее значение после отправки… Но лучше массив, цикл и отправлять только действительно изменившиеся переменные..
САБ (09 September 2012 — 02:17) писал:
Это скрипт на Lua. Значит поддерживаются ассоциативные массивы (таблицы), циклы и ещё много чего.
САБ (09 September 2012 — 02:17) писал:
Доступно:
http://www.lua.ru/doc/
http://steps3d.narod…a-tutorial.html
http://www.script-coding.com/Lua.html
http://w3d.wiki-site….php/Основы_Lua
http://ltwood.wikido…ipting:lua-lang
http://symmetrica.net/lua/lua1.pdf
вроде можно сократить таким образом:
R0 = «0=»..math.floor(TAS + 0.5)..»:»
R1 = «1=»..math.floor(IAS + 0.5)..»:»
R2 = «2=»..math.floor(AOA*ToDegree + 0.5)..»:»
R3 = «3=»..math.floor(Gp.y + 0.5)..»:»
R4 = «4=»..math.floor(VV + 0.5)..»:»
R5 = «5=»..math.floor(altBar + 0.5)..»:»
R6 = «6=»..math.floor(altRad + 0.5)..»:»
Jeka_M (09 September 2012 — 03:58) писал:
вроде можно сократить таким образом:
R0 = «0=»..math.floor(TAS + 0.5)..»:»
R1 = «1=»..math.floor(IAS + 0.5)..»:»
R2 = «2=»..math.floor(AOA*ToDegree + 0.5)..»:»
R3 = «3=»..math.floor(Gp.y + 0.5)..»:»
R4 = «4=»..math.floor(VV + 0.5)..»:»
R5 = «5=»..math.floor(altBar + 0.5)..»:»
R6 = «6=»..math.floor(altRad + 0.5)..»:»
Спасибо! Работает!!!
Прикрепленные изображения
ra3dcs (08 September 2012 — 21:02) писал:
lSIOC_SendString = lSIOC_SendString..R0
lSIOC_SendString = lSIOC_SendString..R1
lSIOC_SendString = lSIOC_SendString..R2
lSIOC_SendString = lSIOC_SendString..R3
lSIOC_SendString = lSIOC_SendString..R4
lSIOC_SendString = lSIOC_SendString..R5
lSIOC_SendString = lSIOC_SendString..R6
можно сократить вот так:
lSIOC_SendString = lSIOC_SendString..R0..R1..R2..R3..R4..R5..R6
или даже так:
lSIOC_SendString = R0..R1..R2..R3..R4..R5..R6
(Если предполагается, что раньше этого фрагмента НЕ будет присвоено какое-то значение переменной lSIOC_SendString, которое также нужно добавить в отправляемую строку. В данном скрипте так и есть, эта переменная объявляется пустой в функции LuaExportAfterNextFrame() )
———
Если же количество пересылаемых данных влияет на производительность, то как писал ув. САБ, можно подумать и попробовать переделать скрипт так, чтобы отправлялись только те переменные, которые поменяли своё значение, а не все подряд. Это при условии, что SIOC не обязательно каждый раз пересылать значение переменной, если оно не изменилось. Я с SIOC и с «железными кокпитами» вообще не сталкивался, поэтому не уверен.
Сообщение отредактировал Jeka_M: 09 September 2012 — 13:41
Jeka_M (09 September 2012 — 13:22) писал:
lSIOC_SendString = lSIOC_SendString..R0..R1..R2..R3..R4..R5..R6
Спасибо!
Подскажите максимальная длинна строки переменной какая может быть?
ra3dcs (09 September 2012 — 18:19) писал:
К сожалению не могу подсказать, нигде не нашёл такой информации. Нужно пробовать.
ra3dcs (10 September 2012 — 14:47) писал:
Странно, у меня сложилось противоположное мнение.
ra3dcs (10 September 2012 — 14:47) писал:
По «разведданным» эта программа есть еще у Сергея (Саб) может он, что подскажет в этом направлении?
Функция вывода примерно будет выглядеть пока так.
function LuaExportAfterNextFrame()
local lSIOC_SendString = «»
local TAS = LoGetTrueAirSpeed()* 3.6 — значение истинной скорости
local IAS = LoGetIndicatedAirSpeed()* 3.6 — значение приборной скорости
local AOA = LoGetAngleOfAttack() — угол атаки
local Gp = LoGetAccelerationUnits() — перегрузка
local VV = LoGetVerticalVelocity() — верт. скорость
local altBar = LoGetAltitudeAboveSeaLevel() — высота баром.
local altRad = LoGetAltitudeAboveGroundLevel() — радио высота
local pitch, bank, yaw = LoGetADIPitchBankYaw() — крен, тангаж, курс.
local Mach = LoGetMachNumber()
local Magn_yaw = LoGetMagneticYaw() — ????
local HSI = LoGetControlPanel_HSI() — ????
local engine = LoGetEngineInfo() — параметры двигателя температура, обороты, топливо, гидро.
local route = LoGetRoute()
local PlaneID = LoGetPlayerPlaneId()
local obj = LoGetObjectById(PlaneID)
local myXCoord, myZCoord = getXYCoords(obj.LatLongAlt.Lat, obj.LatLongAlt.Long)
local navi = LoGetNavigationInfo()
— формируем строчку номер переменной = значение
— округляем значение до целого
R0 = «0=»..math.floor(TAS + 0.5)..»:»
R1 = «1=»..math.floor(IAS + 0.5)..»:»
R2 = «2=»..math.floor(AOA*ToDegree + 0.5)..»:»
R3 = «3=»..math.floor(Gp.y + 0.5)..»:»
R4 = «4=»..math.floor(VV + 0.5)..»:»
R5 = «5=»..math.floor(altBar + 0.5)..»:»
R6 = «6=»..math.floor(altRad + 0.5)..»:»
R7 = «7=»..math.floor(HSI.Compass + 0.5)..»:»
R8 = «8=»..math.floor(engine.RPM.left + 0.5)..»:»
R9 = «9=»..math.floor(engine.RPM.right + 0.5)..»:»
R10 = «10=»..math.floor(engine.Temperature.left + 0.5)..»:»
R11 = «11=»..math.floor(engine.Temperature.right + 0.5)..»:»
R12 = «12=»..math.floor(pitch*ToDegree + 0.5)..»:»
R13 = «13=»..math.floor(bank*ToDegree + 0.5)..»:»
R14 = «14=»..math.floor(yaw*ToDegree + 0.5)..»:»
R15 = «15=»..math.floor(Magn_yaw*ToDegree + 0.5)..»:»
R16 = «16=»..math.floor(engine.fuel_internal + 0.5)..»:»
R17 = «17=»..math.floor(engine.fuel_external + 0.5)..»:»
R18 = «18=»..math.floor(engine.HydraulicPressure.left + 0.5)..»:»
R19 = «19=»..math.floor(engine.HydraulicPressure.right + 0.5)..»:»
R20 = «20=»..math.floor(navi.Requirements.roll + 0.5)..»:»
R21 = «21=»..math.floor(navi.Requirements.pitch + 0.5)..»:»
R22 = «22=»..math.floor(navi.Requirements.altitude + 0.5)..»:»
R23 = «23=»..math.floor(myXCoord + 0.5)..»:»
R24 = «24=»..math.floor(obj.LatLongAlt.Alt + 0.5)..»:»
R25 = «25=»..math.floor(myZCoord + 0.5)..»:»
— записываем строчку
lSIOC_SendString = lSIOC_SendString..R0..R1..R2..R3..R4..R5..R6..R7..R8..R9..R10..R11..R12..R13..R14..R15..R16..R17..R18..R19..R20..R21..R22..R23..R24..R25
— отправляем
if lSIOC_SendString ~= «» then
socket.try(c:send(«Arn.Resp:»..lSIOC_SendString..»n»))
end
end
————————————————————————————————
Однако получить данные от Локк Она оказалось еще пол дела, теперь нужно эти переменные вытащить из SIOС-а.
Иван (Sly) написал программу клиент, но с Иваном на эту тему говорить бесполезно, не создан он для общения с коллегами.
По «разведданным» эта программа есть еще у Сергея (Саб) может он, что подскажет в этом направлении?
LISА (10 September 2012 — 18:12) писал:
Жаль! Пригодилось бы!
Не помню чтобы я кому-нибудь отказывал…
Александр и и не помню чтобы вы обращались ко мне с подобной просьбой.
Собственно прокладку можете взять у Сергея, могу отправить я как первоисточник )
С Уважением, Иван.
кроме функции LuaExportAfterNextFrame()
есть еще другой способ получения данных через равные интервалы времени:
кроме того массив состояния сигнальных ламп можно (даже нужно!) обработать с помощью цикла,
рабочий код приводить не буду, лень искать (для лок она это все равно не атуально)
ra3dcs (13 September 2012 — 14:22) писал:
Александр, еще чуть-чуть и сможете наконец выбросить свой комп с виндовсом МЕ
Язык программирования Delphi.
В строку подключаемых модулей добавляем модуль Sockets.
И на существующую форму добавляем объект ClientSocket . Так же нам еще понадобятся три кнопки и два поля редактирования компоненты Edit для ввода адреса сервера и номера порта,
Прикрепленные изображения
procedure TForm1.Connect_Buttonclick(Sender: TObject);
begin
ClientSocket.Address := Adress_SIOC.Text;
ClientSocket.Host := Adress_SIOC.Text;
ClientSocket.Port := StrToInt(Port_SIOC.Text);
ClientSocket.Active := True;
end;
procedure TForm1.ClientSocketError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
if ErrorCode = 10061 then begin
ShowMessage(‘Сервер не найден!’);
ErrorCode := 0;
end else begin
ShowMessage(‘Неизвестная ошибка!’);
ErrorCode := 0;
end;
end;
procedure TForm1.ClientSocketRead(Sender: TObject;
Socket: TCustomWinSocket);
var
sBuffer: string;
iPos, iVar, iVal: integer;
begin
sBuffer := Socket.ReceiveText;
if pos(‘Resp’, sBuffer) <> 0 then begin
sBuffer := StringReplace(sBuffer, ‘Arn.Vivo:’, », [rfReplaceAll]);
sBuffer := StringReplace(sBuffer, ‘Arn.Resp:’, », [rfReplaceAll]);
sBuffer := StringReplace(sBuffer, #$D + #$A, », [rfReplaceAll]);
if length(sBuffer) > 0 then begin
while (length(sBuffer) > 1) do begin
iPos := pos(‘=’, sBuffer);
iVar := StrToInt(copy(sBuffer, 1, iPos — 1));
delete(sBuffer, 1, iPos);
iPos := pos(‘:’, sBuffer);
iVal := StrToInt(copy(sBuffer, 1, iPos — 1));
delete(sBuffer, 1, iPos);
Log_window.Lines.Add(IntToStr(iVar) + ‘==’ + IntToStr(iVal))
end;
end;
end;
sBuffer := »;
end;
procedure TForm1.ClientSocketConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
Connect_Button.Enabled := False;
Disconnect_Button.Enabled := True;
Button1.Enabled := True;
ClientSocket.Socket.SendText(SIOC_Hello);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
SIOC_Quest := ‘0:1:2:3:4:5:6:7:8:9:10:11:12:13:14:15:16:17:18:19:20‘;
SIOC_Vars := ‘Arn.Inicio:’ + SIOC_Quest + #$D + #$A;
ClientSocket.Socket.SendText(SIOC_Vars);
SIOC_Vars := »;
end;
procedure TForm1.ClientSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
Connect_Button.Enabled := True;
Disconnect_Button.Enabled := False;
Button1.Enabled := False;
end;
procedure TForm1.Disconnect_Buttonclick(Sender: TObject);
begin
ClientSocket.Socket.SendText(‘Arn.Fin’ + #$D + #$A);
ClientSocket.Active := False;
end;
Соединение с сервером есть, данные получаю, но использовать пока не могу, так как переменные iVar , iVal оказались локальные и доступны пока в процедуре чтения данных.
Прикрепленные изображения
САБ (13 September 2012 — 15:39) писал:
Пока еще такого сделать не могу!!!!!