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
use serde::{Deserialize, Serialize};
use crate::content::ContentId;
#[doc(hidden)]
#[derive(Clone, Debug)]
pub struct PisGroup {
pub name: String, // NAME
pub stations: Vec<PisStation>, // STNS
pub special_chars: Vec<PisSpecialChar>, // SPEC
pub routes: Vec<PisRoute>, // ROUT
pub server_name: Option<String>, // SERV
}
impl PisGroup {
/// Holt den Namen der aktiven PIS-Gruppe.
#[cfg(feature = "ffi")]
pub fn get_name() -> String {
let name =
lotus_script_sys::FfiObject::from_packed(unsafe { lotus_script_sys::pis::get_name() });
name.deserialize()
}
/// Holt die Station mit der gegebenen Code.
#[cfg(feature = "ffi")]
pub fn get_station(code: u32) -> Option<PisStation> {
let station = lotus_script_sys::FfiObject::from_packed(unsafe {
lotus_script_sys::pis::get_station(code)
});
station.deserialize()
}
/// Holt die gesamte Liste sämtlicher Sonderzeichen
#[cfg(feature = "ffi")]
pub fn get_special_char_with_line(line: u32, special_char_code: u32) -> String {
let route_codes = lotus_script_sys::FfiObject::from_packed(unsafe {
lotus_script_sys::pis::get_special_char_with_line(line, special_char_code)
});
route_codes.deserialize()
}
/// Holt die Route mit der gegebenen Linie und Code.
#[cfg(feature = "ffi")]
pub fn get_route(line_code: (u32, u32)) -> Option<PisRoute> {
let route = lotus_script_sys::FfiObject::from_packed(unsafe {
lotus_script_sys::pis::get_route(line_code.0, line_code.1)
});
route.deserialize()
}
/// Liefert eine Liste sämtlicher Route-Codes, die es für die gegebenen Linie gibt.
/// Die Liste ist bereits sortiert und frei von Duplikaten.
#[cfg(feature = "ffi")]
pub fn get_route_codes_by_line(line: u32) -> Vec<u32> {
let route_codes = lotus_script_sys::FfiObject::from_packed(unsafe {
lotus_script_sys::pis::get_route_codes_by_line(line)
});
route_codes.deserialize()
}
/// Holt den Namen des Leitstellen-Servers.
#[cfg(feature = "ffi")]
pub fn get_server_name() -> Option<String> {
let server_name = lotus_script_sys::FfiObject::from_packed(unsafe {
lotus_script_sys::pis::get_server_name()
});
server_name.deserialize()
}
}
/// Datensatz für eine Station im PIS.
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct PisStation {
/// Mit der ID wird die Station mit der Map verknüpft (auch dort gibt es eine ID für jede Station).
/// Dies ist u.A. für die Fahrgäste und die öffentlichen KI-Fahrzeuge notwendig.
pub id: String,
/// Der Code ist die Zahl, mit der die Station innerhalb des PIS identifiziert wird.
/// Dieser Code wird für die Anzeige auf dem PIS-Display verwendet.
pub code: u32,
/// Die Strings sind die Texte, die auf den Innenanzeigen angezeigt werden. Zwei Strings gibt es
/// z.B. für Wechselanzeigen
pub interieur_display: [String; 2],
/// Die folgenden Strings sind für die Außenanzeigen.
pub terminus_front_option: Option<[String; 2]>,
pub terminus_side_option: Option<[String; 2]>,
pub terminus_oneline: String,
}
pub enum PisStationTerminusOneLineTo {
FirstLine,
SecondLine,
}
impl PisStation {
/// Liefert die (zweizeilige) Front-Außenanzeige für das Ziel.
/// Verfügt die Ziel-Station über keine zweizeilige Front-Außenanzeige, so wird die einzeilige
/// Außenanzeige um eine Leerzeile erweitert, wobei one_to_two_line die Reihenfolge dieser
/// Erweiterung bestimmt:
/// - FirstLine: Die einzeilige Zeile wird in die erste Zeile und die Leerzeile in die zweite Zeile eingefügt
/// - SecondLine: Die einzeilige Zeile wird in die zweite Zeile und die Leerzeile in die erste Zeile eingefügt
pub fn terminus_front(&self, one_to_two_line: PisStationTerminusOneLineTo) -> [String; 2] {
if let Some(front) = &self.terminus_front_option {
front.clone()
} else {
match one_to_two_line {
PisStationTerminusOneLineTo::FirstLine => {
[self.terminus_oneline.clone(), String::new()]
}
PisStationTerminusOneLineTo::SecondLine => {
[String::new(), self.terminus_oneline.clone()]
}
}
}
}
pub fn terminus_side(&self, one_to_two_line: PisStationTerminusOneLineTo) -> [String; 2] {
if let Some(side) = &self.terminus_side_option {
side.clone()
} else {
self.terminus_front(one_to_two_line)
}
}
}
/// Datensatz für ein Sonderzeichen im PIS.
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct PisSpecialChar {
/// Der Code ist die Zahl, mit der das Sonderzeichen innerhalb des PIS identifiziert wird.
pub code: u32,
/// Der Sonderzeichen-String, wobei dieser auch über bestimmte Codes verfügen kann, mit denen
/// die originale Liniennummer eingefügt werden kann.
///
/// So bedeutet z.B. "M(R2-R1)", dass das auf dem Linienfeld ein M, gefolgt von
/// den Ziffern 2 bis 1 von RECHTS aus gezählt, angezeigt wird. Wenn die Liniennummer
/// z.B. 123 ist, dann wird hier M23 angezeigt.
/// Soll nur M2 angezeigt werden, müsste man "M(R2-R2)" als chars eintragen.
pub chars: String, // STRN
}
/// Datensatz für eine Route im PIS. Jeder Datensatz wird über eine
/// Liniennummer und einen Code innerhalb der Linie identifiziert.
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct PisRoute {
/// Liniennummer und Code innerhalb der Linie zur Zuordnung
pub line_code: (u32, u32),
/// Liste der Codes der Haltestellen, die auf der Route nacheinander
/// angefahren werden, inklusive der Abfahrts- und der Endhaltestelle.
pub stop_codes: Vec<u32>,
/// Der Codes des Sonderzeichens, welcher automatisch ausgewählt werden soll,
/// wenn diese Route eingestellt wird. Ob dieser Code überschrieben werden kann usw.
/// ist abhängig vom Bordrechner.
pub special_char_code: Option<u32>,
/// Sind für das Balisensystem/Anforderungen/Weichen individuelle Anmelde-Codes nötig?
pub routing_code: Option<u32>,
/// Zusätzliches Textfeld, welches aber aktuell keine bestimmte Bedeutung hat.
pub text: Option<String>,
/// Im einfachsten Fall ist das Ziel (der Zielcode) einer Route einfach die letzte
/// Haltestelle. Es kann aber sein, dass das angezeigte Ziel ab einer bestimmten
/// Haltestelle wechseln soll, oder auch die Zielhaltestelle anders angezeigt werden soll.
/// Für diese Fälle kann man Termini definieren.
pub termini: Vec<PisRouteTerminus>,
/// Linie/Code für die automatisch zu wählende folgende Route
pub following_line_code: Option<(u32, u32)>,
}
impl PisRoute {
pub fn new(
line_code: (u32, u32),
stop_codes: Vec<u32>,
special_char_code: Option<u32>,
routing_code: Option<u32>,
text: Option<String>,
termini: Vec<PisRouteTerminus>,
following_line_code: Option<(u32, u32)>,
) -> Self {
Self {
line_code,
stop_codes,
special_char_code,
routing_code,
text,
termini,
following_line_code,
}
}
pub fn get_current_direction(&self, stop_index: usize) -> Option<PisRouteTerminus> {
self.termini
.iter()
.find(|terminus| stop_index >= terminus.stop_index)
.cloned()
.or_else(|| {
self.stop_codes.last().map(|code| PisRouteTerminus {
stop_index: 0,
code: Some(*code),
line: Some(self.line_code.0),
special_char_code: self.special_char_code,
routing_code: self.routing_code,
})
})
}
}
#[derive(Default, Clone, Serialize, Deserialize, Debug)]
pub struct PisRouteTerminus {
/// Index of the stop of the route, from which this terminus applies
pub stop_index: usize,
/// New terminus code
pub code: Option<u32>,
/// New line
pub line: Option<u32>,
/// New special char code
pub special_char_code: Option<u32>,
/// New routing code
pub routing_code: Option<u32>,
}
impl PisRouteTerminus {
fn routing_code_hash(&self) -> u32 {
0
}
pub fn routing_code(&self) -> u32 {
self.routing_code.unwrap_or(self.routing_code_hash())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PisSpGroup {
pub name: String,
pub basic_pis_group: ContentId,
pub class: String,
pub add_lines: String,
pub add_lines_stations: Vec<PisSpAddLines>,
pub routes: Vec<PisSpRoute>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PisSpAddLines {
pub code: i32,
pub lines: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PisSpRoute {
pub code: i32,
pub lines: String,
pub stop_lines: Vec<String>,
}
impl PisSpGroup {
/// Liefert die ContentId der PISS-Gruppe, die zur aktiven PISG passt und die gegebene Klasse hat.
#[cfg(feature = "ffi")]
pub fn get_content_id(class: &str) -> Option<ContentId> {
let class = lotus_script_sys::FfiObject::new(&class);
let content_id = lotus_script_sys::FfiObject::from_packed(unsafe {
lotus_script_sys::pis::get_sp_content_id(class.packed())
});
content_id.deserialize()
}
/// Liefert die zusätzlichen Linien aus der gegebenen PISS-Gruppe.
#[cfg(feature = "ffi")]
pub fn get_group_strings(content_id: ContentId) -> String {
let content_id = lotus_script_sys::FfiObject::new(&content_id);
let lines = lotus_script_sys::FfiObject::from_packed(unsafe {
lotus_script_sys::pis::get_sp_group_strings(content_id.packed())
});
lines.deserialize()
}
/// Liefert die zusätzlichen Linien für eine Station aus der gegebenen PISS-Gruppe.
#[cfg(feature = "ffi")]
pub fn get_station_strings(content_id: ContentId, station_code: u32) -> Option<String> {
let content_id = lotus_script_sys::FfiObject::new(&content_id);
let lines = lotus_script_sys::FfiObject::from_packed(unsafe {
lotus_script_sys::pis::get_sp_station_strings(content_id.packed(), station_code)
});
lines.deserialize()
}
/// Liefert die Route mit dem gegebenen Code aus der gegebenen PISS-Gruppe.
#[cfg(feature = "ffi")]
pub fn get_route(content_id: ContentId, route_code: u32) -> Option<PisSpRoute> {
let content_id = lotus_script_sys::FfiObject::new(&content_id);
let route = lotus_script_sys::FfiObject::from_packed(unsafe {
lotus_script_sys::pis::get_sp_route_data(content_id.packed(), route_code)
});
route.deserialize()
}
}