forked from decaff42/YFS2CSV
-
Notifications
You must be signed in to change notification settings - Fork 0
/
YFS2CSV_v0.1.py
297 lines (235 loc) · 8.78 KB
/
YFS2CSV_v0.1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
#!/usr/bin/env python
__author__ = "Decaff_42"
__contact__ = "decaff_42 on ysfhq.com"
__copyright__ = "2017 by Decaff_42"
__license__ = "GNU GPLv3"
__date__ = "24 July 2017"
__version__ = "0.1"
"""
PURPOSE:
The purpose of this tool is to take each sortie of an aircraft in the .yfs
file and extract the raw data into a csv file in order to make flight testing
an aircraft more accurate.
HOW TO USE:
Press F5 or Click Run and follow the on-screen prompts
"""
# Load Modules
import os
import csv
import time
def Break():
print("---------------------------------------------------------")
def PrintHeader():
"""Prints the preamble of the software into the command window."""
print("YFS2CSV Converter")
print("Version {}".format(__version__))
print("By {}".format(__author__))
print("Copyright (c) {}".format(__copyright__))
print("Licensed under {}".format(__license__))
Break()
print(("Refer to the Reference Document for License information, \n"
"instructions and for any questions about the output of \n"
"this program. Further questions may be addressed to \n"
"decaff_42 via a Private Message on YSFlight Headquarters."))
Break()
def CreateFileStructure():
"""Detect file structure of the Current Working Directory and
if there are missing folders, create them"""
cwd = os.getcwd()
folder_names = ["Input YFS Files", "Output CSV Files",
"Documentation"]
for name in folder_names:
dirpath = os.path.join(cwd, name)
if not os.path.exists(dirpath):
if name is not folder_names[-1]:
os.makedirs(dirpath)
print("Created {} Folder".format(name))
else:
print("Documentation Folder Missing.")
def DetectYFS():
"""Find YFS files in the Input YFS Folder and report names for selection"""
cwd = os.getcwd()
dirpath = os.path.join(cwd, "Input YFS Files")
files = os.listdir(dirpath)
YFS_files = []
for name in files:
if name.endswith(".yfs"):
YFS_files.append(name)
if len(YFS_files) < 1:
print(("No YFS files were found. \n"
"Please place your YFS files in the 'Input YFS Files' folder."))
return False
else:
print("Select a File to Load")
for ind, file in enumerate(YFS_files):
print("({}) {}".format(ind, file))
selected = -1
while selected < 0:
selected = Validate(len(YFS_files))
Break()
return YFS_files[selected]
def Validate(max_num):
"""Checks the input from the user to make sure it is a valid option given
the number of files to select from.
"""
user_input = input("Enter File Number Here:")
try:
user_input = int(user_input)
if user_input >= 0 and user_input <= max_num:
return user_input
else:
print("Provided number is not a valid option.")
return -1
except:
print("Please enter the number to the left of the file name")
return -1
def ExtractAirplane(fname):
"""Extract each sortie recorded in the .yfs file.
Ask the user to select the sortie to parse to csv file
"""
if fname is False:
print("Stopping Program")
return False
print("Extracting data from {}".format(fname))
raw_yfs = []
fpath = os.path.join(os.getcwd(), "Input YFS Files", fname)
with open(fpath) as input_file:
for line in input_file:
raw_yfs.append(line[:-1])
print("Raw Data Extracted... \nLooking for sorties to convert.")
flight = []
sorties = []
flights = {}
record = False
for ind, line in enumerate(raw_yfs):
if line.startswith("AIRPLANE") and record is False:
record = True
elif (line.startswith("AIRPLANE") \
or line.startswith("BULRECOR")) \
and record is True:
record = False
temp = sortie(flight,ind)
sorties.append(temp.gen_sortie_name())
flights["{}".format(len(sorties)-1)] = temp
flight = []
flight.append(line)
if record is True:
flight.append(line)
if len(sorties) < 1:
print("No Sorties Detected")
return False
else:
print("Select Sortie to convert to CSV.")
for ind, s in enumerate(sorties):
print("({}) {}".format(ind,s))
selected = -1
while selected < 0:
selected = Validate(len(sorties))
print("Parsing Sortie Data.")
data = flights[str(selected)].parse()
return data
def WriteCSV(data):
"""Write list of lists data to csv and add headers"""
Break()
headers = ["Time","X-Pos","Y-Pos","Z-Pos", "Compass Heading",
"Pitch Angle","Bank Angle","G","Flight State",
"Variable Geometry Wing","Air Brake","Landing Gear",
"Flaps","Brakes","Smoke","Vapor Trail","Misc","Strength",
"Throttle","Elevator","Aileron","Rudder","Trim",
"Thrust Vector","Reverse Thrust","Bomb Bay","Turrets"]
units = ["second","meter","meter","meter", "radians",
"radians","radians","N/A","N/A",
"N/A","N/A","N/A",
"N/A","N/A","N/A","N/A","N/A","N/A",
"N/A","N/A","N/A","N/A","N/A",
"N/A","N/A","N/A","N/A"]
output = []
output.append(headers)
output.append(units)
for line in data:
output.append(line)
print("Please enter a name for the output csv file.")
fname = input("CSV Name:")
if fname == "":
fname = "YFS2CSV_{}_{}".format(time.strftime('%d-%B-%Y'),
time.strftime('%H.%M.%S'))
if fname.endswith(".csv") is False:
fname = fname + ".csv"
fpath = os.path.join(os.getcwd(),"Output CSV Files",fname)
with open(fpath,"w") as outputfile:
writer = csv.writer(outputfile)
writer.writerows(output)
print("Data Written to File: {}".format(fname))
"""Class written to help extract data"""
class sortie():
def __init__(self,raw,raw_start):
"""Initialize Class Instance with raw data defining aircraft.
Note: Not all of this data is used in YFS2CSV v0.1. Future releases
may be expanded to utilize some of this data.
"""
self.raw = raw
self.aircraft_name = ""
self.username = ""
self.start_position = ""
self.parsed_data = []
self.raw_start = raw_start
self.raw_data = []
self.NUMRECOR = 0
self.start = 0
self.sortie_name = ""
self.extract_data_from_header()
def extract_data_from_header(self):
"""Takes the header block of the aircraft's raw data and assigns
values for important variables.
"""
for ind,row in enumerate(self.raw):
if row.startswith("AIRPLANE"):
self.aircraft_name = row.split()[1]
elif row.startswith("STARTPOS"):
self.start_position = row[12:]
elif row.startswith("AIRPCMND INITFUEL"):
self.start_fuel = int(row.split()[-1][:-1])
elif row.startswith("AIRSPEED"):
self.start_speed = float(row.split()[-1][:-3])
elif row.startswith("THROTTLE"):
self.start_throttle = float(row.split()[-1])
elif row.startswith("NUMRECOR"):
self.NUMRECOR = int(row.split()[1])
self.start = ind
break
def gen_sortie_name(self):
"""Generate the sortie name"""
if self.username == "":
self.sortie_name = self.aircraft_name
else:
self.sortie_name = self.aircraft_name + self.username
return self.sortie_name
def parse(self):
"""Parses Flight Data into a list of lists."""
self.data = self.raw[self.start+1:]
self.parse_data = []
row_num = 0
slices = 0
while slices < self.NUMRECOR:
line = self.data[row_num].split()
line.extend(self.data[row_num + 1].split())
line.extend(self.data[row_num + 2].split())
line.extend(self.data[row_num + 3].split())
self.parse_data.append(line)
row_num += 4
slices += 1
return self.parse_data
""" Run the code"""
def RunYFS2CSV():
"""Run through the process"""
PrintHeader()
CreateFileStructure()
WriteCSV(ExtractAirplane(DetectYFS()))
print("\n\n")
Break()
print("Run Again? 0 = Yes / 1 = No")
if int(input("")) == 0:
print("\n\n")
RunYFS2CSV()
# Call Function to Run the Code
RunYFS2CSV()