FreeCalypso > hg > fc-magnetite
comparison src/g23m-gprs/sm/sm_user_plane_control.c @ 183:219afcfc6250
src/g23m-gprs: initial import from TCS3.2/LoCosto
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 13 Oct 2016 04:24:13 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
182:f02d0a0e1849 | 183:219afcfc6250 |
---|---|
1 /*---------------------------------------------------------------------------- | |
2 | Project : 3G PS | |
3 | Module : SM | |
4 +----------------------------------------------------------------------------- | |
5 | Copyright 2003 Texas Instruments. | |
6 | All rights reserved. | |
7 | | |
8 | This file is confidential and a trade secret of Texas | |
9 | Instruments . | |
10 | The receipt of or possession of this file does not convey | |
11 | any rights to reproduce or disclose its contents or to | |
12 | manufacture, use, or sell anything it may describe, in | |
13 | whole, or in part, without the specific written consent of | |
14 | Texas Instruments. | |
15 +----------------------------------------------------------------------------- | |
16 | Purpose: User Plane Control state machine implementation in the SM entity. | |
17 | For design details, see: | |
18 | 8010.908 SM Detailed Specification | |
19 +---------------------------------------------------------------------------*/ | |
20 | |
21 /*==== DECLARATION CONTROL =================================================*/ | |
22 | |
23 /*==== INCLUDES =============================================================*/ | |
24 | |
25 #include "sm.h" | |
26 | |
27 #include "sm_user_plane_control.h" | |
28 #include "sm_context_control.h" | |
29 | |
30 #include "sm_upm_output_handler.h" | |
31 | |
32 /*==== CONSTS ===============================================================*/ | |
33 | |
34 /*==== TYPES ================================================================*/ | |
35 | |
36 typedef void (*T_SM_USER_PLANE_CONTROL_TRANSITION_FUNC)(struct T_SM_CONTEXT_DATA *ptr_context_data, /*@null@*/ void *data); | |
37 | |
38 typedef struct { | |
39 #ifdef DEBUG | |
40 T_SM_USER_PLANE_CONTROL_EVENT event; | |
41 #endif /* DEBUG */ | |
42 T_SM_USER_PLANE_CONTROL_TRANSITION_FUNC func; | |
43 } T_SM_USER_PLANE_CONTROL_TRANSITION; | |
44 | |
45 /*==== LOCALS ===============================================================*/ | |
46 | |
47 static void state_event_error(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data); | |
48 static void ignored (struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data); | |
49 static void handle_activate_start(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data); | |
50 static void handle_activate_complete(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data); | |
51 static void handle_deactivate(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data); | |
52 static void handle_deactivate_local(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data); | |
53 static void handle_modify(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data); | |
54 static void handle_sm_activate_res(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data); | |
55 static void handle_sm_deactivate_res(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data); | |
56 static void handle_sm_modify_res(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data); | |
57 | |
58 /*********************************************************************** | |
59 * State/Transition Table | |
60 */ | |
61 static const T_SM_USER_PLANE_CONTROL_TRANSITION | |
62 transition[SM_USER_PLANE_CONTROL_NUMBER_OF_STATES][SM_USER_PLANE_CONTROL_NUMBER_OF_EVENTS] = | |
63 { | |
64 { /* S0: SM USER PLANE DEACTIVATED */ | |
65 M_TRANSITION(SM_P_SM_ACTIVATE_RES, state_event_error), | |
66 M_TRANSITION(SM_P_SM_DEACTIVATE_RES, ignored), | |
67 M_TRANSITION(SM_P_SM_MODIFY_RES, state_event_error), | |
68 M_TRANSITION(SM_I_USER_PLANE_ACTIVATE_START, handle_activate_start), | |
69 M_TRANSITION(SM_I_USER_PLANE_ACTIVATE_COMPLETE, state_event_error), | |
70 M_TRANSITION(SM_I_USER_PLANE_DEACTIVATE_LOCAL, ignored), | |
71 M_TRANSITION(SM_I_USER_PLANE_MODIFY, state_event_error), | |
72 M_TRANSITION(SM_I_USER_PLANE_DEACTIVATE, ignored) | |
73 }, | |
74 { /* S1: SM USER PLANE ACTIVATE STARTED */ | |
75 M_TRANSITION(SM_P_SM_ACTIVATE_RES, state_event_error), | |
76 M_TRANSITION(SM_P_SM_DEACTIVATE_RES, state_event_error), | |
77 M_TRANSITION(SM_P_SM_MODIFY_RES, state_event_error), | |
78 M_TRANSITION(SM_I_USER_PLANE_ACTIVATE_START, state_event_error), | |
79 M_TRANSITION(SM_I_USER_PLANE_ACTIVATE_COMPLETE, handle_activate_complete), | |
80 M_TRANSITION(SM_I_USER_PLANE_DEACTIVATE_LOCAL, handle_deactivate_local), | |
81 M_TRANSITION(SM_I_USER_PLANE_MODIFY, state_event_error), | |
82 M_TRANSITION(SM_I_USER_PLANE_DEACTIVATE, handle_deactivate) | |
83 }, | |
84 { /* S2: SM USER PLANE ACTIVATE COMPLETING */ | |
85 M_TRANSITION(SM_P_SM_ACTIVATE_RES, handle_sm_activate_res), | |
86 M_TRANSITION(SM_P_SM_DEACTIVATE_RES, state_event_error), | |
87 M_TRANSITION(SM_P_SM_MODIFY_RES, state_event_error), | |
88 M_TRANSITION(SM_I_USER_PLANE_ACTIVATE_START, state_event_error), | |
89 M_TRANSITION(SM_I_USER_PLANE_ACTIVATE_COMPLETE, state_event_error), | |
90 M_TRANSITION(SM_I_USER_PLANE_DEACTIVATE_LOCAL, handle_deactivate_local), | |
91 M_TRANSITION(SM_I_USER_PLANE_MODIFY, state_event_error), | |
92 M_TRANSITION(SM_I_USER_PLANE_DEACTIVATE, handle_deactivate) | |
93 }, | |
94 { /* S3: SM USER PLANE ACTIVATED */ | |
95 M_TRANSITION(SM_P_SM_ACTIVATE_RES, state_event_error), | |
96 M_TRANSITION(SM_P_SM_DEACTIVATE_RES, state_event_error), | |
97 M_TRANSITION(SM_P_SM_MODIFY_RES, state_event_error), | |
98 M_TRANSITION(SM_I_USER_PLANE_ACTIVATE_START, state_event_error), | |
99 M_TRANSITION(SM_I_USER_PLANE_ACTIVATE_COMPLETE, state_event_error), | |
100 M_TRANSITION(SM_I_USER_PLANE_DEACTIVATE_LOCAL, handle_deactivate_local), | |
101 M_TRANSITION(SM_I_USER_PLANE_MODIFY, handle_modify), | |
102 M_TRANSITION(SM_I_USER_PLANE_DEACTIVATE, handle_deactivate) | |
103 }, | |
104 { /* S4: SM USER PLANE MODIFYING */ | |
105 M_TRANSITION(SM_P_SM_ACTIVATE_RES, state_event_error), | |
106 M_TRANSITION(SM_P_SM_DEACTIVATE_RES, state_event_error), | |
107 M_TRANSITION(SM_P_SM_MODIFY_RES, handle_sm_modify_res), | |
108 M_TRANSITION(SM_I_USER_PLANE_ACTIVATE_START, state_event_error), | |
109 M_TRANSITION(SM_I_USER_PLANE_ACTIVATE_COMPLETE, state_event_error), | |
110 M_TRANSITION(SM_I_USER_PLANE_DEACTIVATE_LOCAL, handle_deactivate_local), | |
111 M_TRANSITION(SM_I_USER_PLANE_MODIFY, state_event_error), | |
112 M_TRANSITION(SM_I_USER_PLANE_DEACTIVATE, handle_deactivate) | |
113 }, | |
114 { /* S5: SM USER PLANE DEACTIVATING */ | |
115 M_TRANSITION(SM_P_SM_ACTIVATE_RES, state_event_error), | |
116 M_TRANSITION(SM_P_SM_DEACTIVATE_RES, handle_sm_deactivate_res), | |
117 M_TRANSITION(SM_P_SM_MODIFY_RES, state_event_error), | |
118 M_TRANSITION(SM_I_USER_PLANE_ACTIVATE_START, state_event_error), | |
119 M_TRANSITION(SM_I_USER_PLANE_ACTIVATE_COMPLETE, state_event_error), | |
120 M_TRANSITION(SM_I_USER_PLANE_DEACTIVATE_LOCAL, handle_deactivate_local), | |
121 M_TRANSITION(SM_I_USER_PLANE_MODIFY, state_event_error), | |
122 M_TRANSITION(SM_I_USER_PLANE_DEACTIVATE, ignored) | |
123 } | |
124 }; | |
125 | |
126 /*==== PRIVATE FUNCTIONS ====================================================*/ | |
127 | |
128 /* | |
129 +------------------------------------------------------------------------------ | |
130 | Function : state_event_error | |
131 +------------------------------------------------------------------------------ | |
132 | Description : General function used to report state event errors. | |
133 | | |
134 | Parameters : context - Not used | |
135 | data - Not used | |
136 +------------------------------------------------------------------------------ | |
137 */ | |
138 static void state_event_error(/*@unused@*/ struct T_SM_CONTEXT_DATA *context, /*@unused@*/ /*@null@*/ void *data) | |
139 { | |
140 (void)TRACE_ERROR("SM User Plane Control: STATE EVENT ERROR!"); | |
141 } | |
142 | |
143 /* | |
144 +------------------------------------------------------------------------------ | |
145 | Function : ignored | |
146 +------------------------------------------------------------------------------ | |
147 | Description : General function used for transitions that shall be ignored | |
148 | | |
149 | Parameters : context - Not used | |
150 | data - Not used | |
151 +------------------------------------------------------------------------------ | |
152 */ | |
153 static void ignored(/*@unused@*/ struct T_SM_CONTEXT_DATA *context, /*@unused@*/ /*@null@*/ void *data) | |
154 { | |
155 (void)TRACE_FUNCTION("SM User Plane Control: Event ignored."); | |
156 } | |
157 | |
158 /* | |
159 +------------------------------------------------------------------------------ | |
160 | Function : handle_activate_start | |
161 +------------------------------------------------------------------------------ | |
162 | Description : Handle event SM_I_USER_PLANE_ACTIVATE_START in S0 | |
163 | | |
164 | Parameters : context - Context data | |
165 | data - Not used | |
166 +------------------------------------------------------------------------------ | |
167 */ | |
168 static void handle_activate_start(struct T_SM_CONTEXT_DATA *context, /*@unused@*/ /*@null@*/ void *data) | |
169 { | |
170 (void)TRACE_FUNCTION("handle_activate_start"); | |
171 | |
172 /* Send SM_ACTIVATE_STARTED_IND */ | |
173 send_sm_activate_started_ind(context); | |
174 | |
175 /* Go to state SM USER PLANE ACTIVATE STARTED */ | |
176 context->user_plane_control_state = SM_USER_PLANE_ACTIVATE_STARTED; | |
177 } | |
178 | |
179 /* | |
180 +------------------------------------------------------------------------------ | |
181 | Function : handle_activate_complete | |
182 +------------------------------------------------------------------------------ | |
183 | Description : Handle event SM_I_USER_PLANE_ACTIVATE_COMPLETE in S1 | |
184 | | |
185 | Parameters : context - Context data | |
186 | data - Not used | |
187 +------------------------------------------------------------------------------ | |
188 */ | |
189 static void handle_activate_complete(struct T_SM_CONTEXT_DATA *context, /*@unused@*/ /*@null@*/ void *data) | |
190 { | |
191 (void)TRACE_FUNCTION("handle_activate_complete"); | |
192 | |
193 /* Send SM_ACTIVATE_IND */ | |
194 send_sm_activate_ind(context); | |
195 | |
196 /* Go to state SM USER PLANE ACTIVATE COMPLETING */ | |
197 context->user_plane_control_state = SM_USER_PLANE_ACTIVATE_COMPLETING; | |
198 } | |
199 | |
200 /* | |
201 +------------------------------------------------------------------------------ | |
202 | Function : handle_modify | |
203 +------------------------------------------------------------------------------ | |
204 | Description : Handle event SM_I_USER_PLANE_MODIFY in S3 | |
205 | | |
206 | Parameters : context - Context data | |
207 | data - Update flags | |
208 +------------------------------------------------------------------------------ | |
209 */ | |
210 static void handle_modify(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data) | |
211 { | |
212 (void)TRACE_FUNCTION("handle_modify"); | |
213 | |
214 /* Send SM_MODIFY_IND */ | |
215 send_sm_modify_ind(context); | |
216 | |
217 /* Go to state SM USER PLANE MODIFYING */ | |
218 context->user_plane_control_state = SM_USER_PLANE_MODIFYING; | |
219 } | |
220 | |
221 /* | |
222 +------------------------------------------------------------------------------ | |
223 | Function : handle_deactivate | |
224 +------------------------------------------------------------------------------ | |
225 | Description : Handle event SM_I_USER_PLANE_DEACTIVATE in any state | |
226 | | |
227 | Parameters : context - Context data | |
228 | data - PS_rel_ind | |
229 +------------------------------------------------------------------------------ | |
230 */ | |
231 static void handle_deactivate(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data) | |
232 { | |
233 (void)TRACE_FUNCTION("handle_deactivate"); | |
234 | |
235 /* Send SM_DEACTIVATE_IND with local parameter taken from input */ | |
236 send_sm_deactivate_ind(sm_nsapi2nsapi_set(context->nsapi), | |
237 (data == NULL ? PS_REL_IND_NO : PS_REL_IND_YES)); | |
238 | |
239 /* Go to state SM USER PLANE DEACTIVATING */ | |
240 context->user_plane_control_state = SM_USER_PLANE_DEACTIVATING; | |
241 } | |
242 | |
243 /* | |
244 +------------------------------------------------------------------------------ | |
245 | Function : handle_deactivate_local | |
246 +------------------------------------------------------------------------------ | |
247 | Description : Handle event SM_I_USER_PLANE_DEACTIVATE_LOCAL in any state | |
248 | | |
249 | Parameters : context - Context data | |
250 | data - BOOL (TRUE = send SM_DEACTIVATE_IND) | |
251 +------------------------------------------------------------------------------ | |
252 */ | |
253 static void handle_deactivate_local(struct T_SM_CONTEXT_DATA *context, /*@null@*/ void *data) | |
254 { | |
255 (void)TRACE_FUNCTION("handle_deactivate_local"); | |
256 | |
257 if (data) | |
258 { | |
259 /* Send SM_DEACTIVATE_IND with local parameter true */ | |
260 send_sm_deactivate_ind(sm_nsapi2nsapi_set(context->nsapi), PS_REL_IND_YES); | |
261 | |
262 /* Go to state SM USER PLANE DEACTIVATING */ | |
263 context->user_plane_control_state = SM_USER_PLANE_DEACTIVATING; | |
264 } else { | |
265 /* Go to state SM USER PLANE DEACTIVATED */ | |
266 context->user_plane_control_state = SM_USER_PLANE_DEACTIVATED; | |
267 } | |
268 } | |
269 | |
270 /* | |
271 +------------------------------------------------------------------------------ | |
272 | Function : handle_sm_activate_res | |
273 +------------------------------------------------------------------------------ | |
274 | Description : Handle event SM_P_SM_ACTIVATE_RES in S2 | |
275 | | |
276 | Parameters : context - Context data | |
277 | data - Not used | |
278 +------------------------------------------------------------------------------ | |
279 */ | |
280 static void handle_sm_activate_res(struct T_SM_CONTEXT_DATA *context, /*@unused@*/ /*@null@*/ void *data) | |
281 { | |
282 (void)TRACE_FUNCTION("handle_sm_activate_res"); | |
283 | |
284 /* Go to state SM USER PLANE ACTIVATED */ | |
285 context->user_plane_control_state = SM_USER_PLANE_ACTIVATED; | |
286 | |
287 /* If comp params is sent by UPM copy it to context. When SMREG_ACTIVATE_CNF | |
288 * primitive is composed this values are copied. | |
289 */ | |
290 if ( (((T_SM_ACTIVATE_RES*)data)->v_comp_params == TRUE) ) | |
291 { | |
292 memcpy(&context->comp_params, &((T_SM_ACTIVATE_RES*)data)->comp_params, | |
293 sizeof(T_NAS_comp_params)); | |
294 } else { | |
295 memset(&context->comp_params, 0, sizeof(T_NAS_comp_params)); | |
296 } | |
297 /* Notify Context Control of activation completion */ | |
298 sm_context_control(context, SM_I_USER_PLANE_ACTIVATED, NULL); | |
299 } | |
300 | |
301 /* | |
302 +------------------------------------------------------------------------------ | |
303 | Function : handle_sm_deactivate_res | |
304 +------------------------------------------------------------------------------ | |
305 | Description : Handle event SM_P_SM_DEACTIVATE_RES in S5 | |
306 | | |
307 | Parameters : context - Context data | |
308 | data - Not used | |
309 +------------------------------------------------------------------------------ | |
310 */ | |
311 static void handle_sm_deactivate_res(struct T_SM_CONTEXT_DATA *context, /*@unused@*/ /*@null@*/ void *data) | |
312 { | |
313 (void)TRACE_FUNCTION("handle_sm_deactivate_res"); | |
314 | |
315 /* Go to state SM USER PLANE DEACTIVATED */ | |
316 context->user_plane_control_state = SM_USER_PLANE_DEACTIVATED; | |
317 | |
318 /* Notify Context Control of deactivation completion */ | |
319 sm_context_control(context, SM_I_USER_PLANE_DEACTIVATED, NULL); | |
320 } | |
321 | |
322 /* | |
323 +------------------------------------------------------------------------------ | |
324 | Function : handle_sm_modify_res | |
325 +------------------------------------------------------------------------------ | |
326 | Description : Handle event SM_P_SM_MODIFY_RES in S4 | |
327 | | |
328 | Parameters : context - Context data | |
329 | data - Not used | |
330 +------------------------------------------------------------------------------ | |
331 */ | |
332 static void handle_sm_modify_res(struct T_SM_CONTEXT_DATA *context, /*@unused@*/ /*@null@*/ void *data) | |
333 { | |
334 (void)TRACE_FUNCTION("handle_sm_modify_res"); | |
335 | |
336 /* Go to state SM USER PLANE ACTIVATED */ | |
337 context->user_plane_control_state = SM_USER_PLANE_ACTIVATED; | |
338 | |
339 /* Notify Context Control of modification completion */ | |
340 sm_context_control(context, SM_I_USER_PLANE_MODIFIED, NULL); | |
341 } | |
342 | |
343 /*==== PUBLIC FUNCTIONS =====================================================*/ | |
344 | |
345 /* | |
346 +------------------------------------------------------------------------------ | |
347 | Function : sm_user_plane_control_init | |
348 +------------------------------------------------------------------------------ | |
349 | Description : User Plane Control state machine initialization function | |
350 | |
351 | Parameters : context - Context data | |
352 +------------------------------------------------------------------------------ | |
353 */ | |
354 void sm_user_plane_control_init(struct T_SM_CONTEXT_DATA *context) | |
355 { | |
356 (void)TRACE_FUNCTION("sm_user_plane_control_init"); | |
357 | |
358 context->user_plane_control_state = SM_USER_PLANE_DEACTIVATED; | |
359 } | |
360 | |
361 /* | |
362 +------------------------------------------------------------------------------ | |
363 | Function : sm_user_plane_control_exit | |
364 +------------------------------------------------------------------------------ | |
365 | Description : User Plane Control state machine exit function | |
366 | |
367 | Parameters : context - Context data | |
368 +------------------------------------------------------------------------------ | |
369 */ | |
370 void sm_user_plane_control_exit(struct T_SM_CONTEXT_DATA *context) | |
371 { | |
372 (void)TRACE_FUNCTION("sm_user_plane_control_exit"); | |
373 | |
374 context->user_plane_control_state = SM_USER_PLANE_DEACTIVATED; | |
375 } | |
376 | |
377 /* | |
378 +------------------------------------------------------------------------------ | |
379 | Function : sm_user_plane_control_state | |
380 +------------------------------------------------------------------------------ | |
381 | Description : Returns a read-only string with the name of the active state. | |
382 | |
383 | Parameters : context - Context data | |
384 +------------------------------------------------------------------------------ | |
385 */ | |
386 #ifdef DEBUG | |
387 /*@observer@*/const char * | |
388 sm_user_plane_control_state(struct T_SM_CONTEXT_DATA *context) | |
389 { | |
390 /*@observer@*/ | |
391 static const char *state_name[SM_USER_PLANE_CONTROL_NUMBER_OF_STATES] = { | |
392 "S0_SM_USER_PLANE_DEACTIVATED", | |
393 "S1_SM_USER_PLANE_ACTIVATE_STARTED", | |
394 "S2_SM_USER_PLANE_ACTIVATE_COMPLETING", | |
395 "S3_SM_USER_PLANE_ACTIVATED", | |
396 "S4_SM_USER_PLANE_MODIFYING", | |
397 "S5_SM_USER_PLANE_DEACTIVATING" | |
398 }; | |
399 | |
400 TRACE_ASSERT(context->user_plane_control_state < SM_USER_PLANE_CONTROL_NUMBER_OF_STATES); | |
401 | |
402 return state_name[(U16)context->user_plane_control_state]; | |
403 } | |
404 #endif | |
405 | |
406 /* | |
407 +------------------------------------------------------------------------------ | |
408 | Function : sm_user_plane_control | |
409 +------------------------------------------------------------------------------ | |
410 | Description : User Plane Control state machine | |
411 | | |
412 | Parameters : context - Context data | |
413 | event - Internal event (see sm_user_plane_control.h) | |
414 | data - Event dependent parameter | |
415 +------------------------------------------------------------------------------ | |
416 */ | |
417 void sm_user_plane_control(struct T_SM_CONTEXT_DATA *context, | |
418 T_SM_USER_PLANE_CONTROL_EVENT event, | |
419 /*@null@*/ void *data) | |
420 { | |
421 #ifdef DEBUG | |
422 const char *old_state_name, *new_state_name; | |
423 T_SM_USER_PLANE_CONTROL_STATE old_state; | |
424 /*@observer@*/ | |
425 static const char *event_name[SM_USER_PLANE_CONTROL_NUMBER_OF_EVENTS] = { | |
426 "SM_P_SM_ACTIVATE_RES", | |
427 "SM_P_SM_DEACTIVATE_RES", | |
428 "SM_P_SM_MODIFY_RES", | |
429 "SM_I_USER_PLANE_ACTIVATE_START", | |
430 "SM_I_USER_PLANE_ACTIVATE_COMPLETE", | |
431 "SM_I_USER_PLANE_DEACTIVATE_LOCAL", | |
432 "SM_I_USER_PLANE_MODIFY", | |
433 "SM_I_USER_PLANE_DEACTIVATE" | |
434 }; | |
435 | |
436 TRACE_ASSERT(event < SM_USER_PLANE_CONTROL_NUMBER_OF_EVENTS); | |
437 | |
438 old_state = context->user_plane_control_state; | |
439 old_state_name = sm_user_plane_control_state(context); | |
440 | |
441 if (transition[(U16)old_state][(U16)event].event != event) { | |
442 (void)TRACE_ERROR("Event table error in sm_user_plane_control!"); | |
443 } | |
444 #endif /* DEBUG */ | |
445 | |
446 transition[(U16)context->user_plane_control_state] | |
447 [(U16)event].func(context, data); | |
448 | |
449 #ifdef DEBUG | |
450 new_state_name = sm_user_plane_control_state(context); | |
451 | |
452 (void)TRACE_EVENT_P4("SM U-PLANE #%d: %s => %s to %s", context->nsapi, | |
453 event_name[(U16)event], old_state_name, new_state_name); | |
454 #endif /* DEBUG */ | |
455 } | |
456 | |
457 /*==== END OF FILE ==========================================================*/ |