summaryrefslogtreecommitdiffstats
path: root/afb-client/gulpfile.js
blob: a79835afe340c500a28a2466d7235e18a187f5c0 (plain)
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
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
// BUG Symlink not working

var gulp = require('gulp');
var debug = require('gulp-debug');
var plugins = require('gulp-load-plugins')();
var del = require('del');
var es = require('event-stream');
var bowerFiles = require('main-bower-files');
var print = require('gulp-print');
var Q = require('q');
var imagemin = require('gulp-imagemin'), pngquant = require('imagemin-pngquant');
var taskListing = require('gulp-task-listing');
var symlink = require('gulp-sym');
var rename = require("gulp-rename");

// addon for Foundation6
var router   = require('front-router');

// == PATH STRINGS ========
var appdir  = "./app/";   // Warning to not forget trailling '/'
config=require (appdir + "etc/_Config"); // upload user local preferences if any

// Run node in debug mode in developpement mode ?
var nodeopts = config.DEBUG !== undefined ? '--debug='+config.DEBUG : ''; 
var frontend= appdir + config.FRONTEND;

var paths = {
    application : frontend,
    scripts     : frontend+'/**/*.js',
    appStyles   : [frontend+'/**/*.scss', '!'+frontend+'/styles/*/*-conf.scss'],
    globalStyles: [frontend+'/styles/**/*.scss'],
    images      : [frontend+'/**/*.png',frontend+'/**/*.jpg',frontend+'/**/*.jpeg',frontend+'/**/*.svg',frontend+'/**/*.ttf'],
    index       : frontend+'/index.html',
    partials    : [frontend + '/**/*.html', '!' + frontend +'/index.html'],
    distDev     : './dist.dev',
    distProd    : './dist.prod',
    sass:  [frontend+'/styles', 'bower_components/foundation-apps/scss','bower_components/foundation-icon-fonts'],
    fonts: ['bower_components/**/*.woff'],
    favicon: frontend+'/favicon.ico'
};

paths['distAppDev']  = paths.distDev + config.URLBASE;
paths['distAppProd'] = paths.distProd + config.URLBASE;

// Run node in debug mode in developpement mode ?
var nodeopts = config.DEBUG !== undefined ? '--debug='+config.DEBUG : ''; 

// == PIPE SEGMENTS ========
var pipes = {};

pipes.orderedVendorScripts = function() {
    return plugins.order(['jquery.js', 'angular.js']);
};

pipes.orderedAppScripts = function() {
    return plugins.angularFilesort();
};

pipes.minifiedFileName = function() {
    return plugins.rename(function (path) {
        path.extname = '.min' + path.extname;
    });
};

pipes.validatedAppScripts = function() {
    return gulp.src(paths.scripts)
        .pipe(plugins.replace('@@APPNAME@@', config.APPNAME))
        .pipe(plugins.jshint())
        .pipe(plugins.jshint.reporter('jshint-stylish'));
};

pipes.builtAppScriptsDev = function() {
    return pipes.validatedAppScripts()
        .pipe(gulp.dest(paths.distAppDev));
};

pipes.builtAppScriptsProd = function() {
    var scriptedPartials = pipes.scriptedPartials();
    var validatedAppScripts = pipes.validatedAppScripts();

    return es.merge(scriptedPartials, validatedAppScripts)
        .pipe(plugins.ngAnnotate())
        .pipe(pipes.orderedAppScripts())
        .pipe(plugins.sourcemaps.init())
        .pipe(plugins.concat(config.APPNAME+'.min.js'))
        .pipe(plugins.uglify({compress: {drop_console: true}}))
        .pipe(plugins.sourcemaps.write())
        .pipe(gulp.dest(paths.distAppProd));
};

pipes.builtVendorScriptsDev = function() {
    return gulp.src(bowerFiles())
        .pipe(gulp.dest( paths.distDev +'/bower_components'));
};

pipes.builtVendorScriptsProd = function() {
    return gulp.src(bowerFiles('**/*.js'))
        .pipe(pipes.orderedVendorScripts())
        .pipe(plugins.concat('vendor.min.js'))
        .pipe(plugins.uglify())
        .pipe(gulp.dest(paths.distProd+ '/bower_components'));
};


pipes.validatedPartials = function() {
    return gulp.src(paths.partials)
        .pipe(plugins.htmlhint({'doctype-first': false}))
        .pipe(router({path: paths.application+'/etc/routes.js', root: paths.application}))
        .pipe(plugins.htmlhint.reporter());
};

pipes.builtPartialsDev = function() {
    return pipes.validatedPartials()
        .pipe(gulp.dest(paths.distAppDev));
};

pipes.scriptedPartials = function() {
    return pipes.validatedPartials()
        .pipe(plugins.htmlhint.failReporter())
        .pipe(plugins.htmlmin({collapseWhitespace: true, removeComments: true}))
        .pipe(plugins.ngHtml2js({
            moduleName: config.APPNAME,
            template: "(function() {"
               + "angular.module('<%= moduleName %>').run(['$templateCache', function($templateCache) {"
               + "$templateCache.put('<%= template.url %>',\n    '<%= template.escapedContent %>');"
               + "}]);\n"
               + "})();\n"
        }));    
};

pipes.builtAppStylesDev = function() {
    return gulp.src(paths.appStyles)
        .pipe(plugins.sass({includePaths: paths.sass}))
        .pipe(gulp.dest(paths.distAppDev + '/styles'));
};

pipes.builtglobalStylesDev = function() {
    return gulp.src(paths.globalStyles)
        .pipe(plugins.sass({includePaths: paths.sass}))
        .pipe(gulp.dest(paths.distDev  + '/global_styles'));
};

pipes.builtAppStylesProd = function() {
    return gulp.src(paths.appStyles)
        .pipe(plugins.sourcemaps.init())
        .pipe(plugins.sass({includePaths: frontend + '/styles'}))
        // .pipe(debug({title: '***** appStyle:'}))
        .pipe(plugins.minifyCss())
        .pipe(plugins.concat(config.APPNAME+'.css'))
        .pipe(plugins.sourcemaps.write())
        .pipe(pipes.minifiedFileName())
        .pipe(gulp.dest(paths.distAppProd));
};

pipes.builtglobalStylesProd = function() {
    return gulp.src(paths.globalStyles)
        .pipe(plugins.sourcemaps.init())
        .pipe(plugins.sass({includePaths: paths.sass}))
        .pipe(plugins.minifyCss())
        .pipe(plugins.sourcemaps.write())
        .pipe(pipes.minifiedFileName())
        .pipe(rename(function (path) {path.dirname="";return path;}))
        .pipe(gulp.dest(paths.distProd + '/global_styles'));
};

pipes.processedFontsDev = function() {
    return gulp.src(paths.fonts)
        .pipe(rename(function (path) {path.dirname="";return path;}))
        .pipe(gulp.dest(paths.distDev+'/bower_components'));
};

pipes.processedFontsProd = function() {
    return gulp.src(paths.fonts)
        .pipe(rename(function (path) {path.dirname="";return path;}))
        .pipe(gulp.dest(paths.distProd+'/bower_components'));
};


pipes.processedImagesDev = function() {
    return gulp.src(paths.images)
        .pipe(gulp.dest(paths.distAppDev));
};

pipes.processedFaviconDev = function() {
    return gulp.src(paths.favicon)
        .pipe(gulp.dest(paths.distDev));
};

pipes.processedImagesProd = function() {
    return gulp.src(paths.images)
       .pipe(imagemin({
            progressive: true,
            svgoPlugins: [{removeViewBox: false}],
            use: [pngquant()]
        }))
        .pipe(gulp.dest(paths.distAppProd));
};

pipes.processedFaviconProd = function() {
    return gulp.src(paths.favicon)
        .pipe(gulp.dest(paths.distProd));
};

// Create an Symlink when config.URLBASE exist
pipes.createDevSymLink = function() {
    return gulp.src(paths.distDev).pipe(symlink(paths.distDev+config.URLBASE, {force: true}));
};

pipes.createProdSymLink = function() {
    return gulp.src(paths.distProd).pipe(symlink(paths.distDev+config.URLBASE,{force: true}));
};

pipes.validatedIndex = function() {
    return gulp.src(paths.index)       
        .pipe(plugins.replace('@@APPNAME@@', config.APPNAME))
        .pipe(plugins.replace('@@URLBASE@@', config.URLBASE))
        .pipe(plugins.htmlhint())
        .pipe(plugins.htmlhint.reporter());
};

pipes.builtIndexDev = function() {

    var orderedVendorScripts = pipes.builtVendorScriptsDev()
        .pipe(pipes.orderedVendorScripts());

    var orderedAppScripts = pipes.builtAppScriptsDev()
        .pipe(pipes.orderedAppScripts());

    var appStyles    = pipes.builtAppStylesDev();
    var globalStyles = pipes.builtglobalStylesDev();

    return pipes.validatedIndex()
         // Vendor and Global should have absolute path to rootdir application one are relative to BaseURL
        .pipe(plugins.inject(orderedVendorScripts, {relative: false, ignorePath: "/dist.dev", name: 'bower'}))
        .pipe(plugins.inject(globalStyles, {relative: false, ignorePath: "/dist.dev", name:'vendor'}))
        .pipe(gulp.dest(paths.distAppDev)) // write first to get relative path for inject
        .pipe(plugins.inject(orderedAppScripts, {relative: true}))
        .pipe(plugins.inject(appStyles, {relative: true, name: 'appli'}))
        .pipe(gulp.dest(paths.distAppDev));
};

pipes.builtIndexProd = function() {

    var vendorScripts= pipes.builtVendorScriptsProd();
    var appScripts   = pipes.builtAppScriptsProd();
    var appStyles    = pipes.builtAppStylesProd();
    var globalStyles = pipes.builtglobalStylesProd();

    return pipes.validatedIndex()
         // Vendor and Global should have absolute path to rootdir application one are relative to BaseURL
        .pipe(plugins.inject(vendorScripts, {relative: false, ignorePath: "/dist.prod", name: 'bower'}))
        .pipe(plugins.inject(globalStyles, {relative: false, ignorePath: "/dist.prod", name:'vendor'}))
        .pipe(gulp.dest(paths.distAppProd)) // write first to get relative path for inject
        .pipe(plugins.inject(appScripts, {relative: true}))
        .pipe(plugins.inject(appStyles, {relative: true, name:'appli'}))
        .pipe(plugins.htmlmin({collapseWhitespace: true, removeComments: true}))
        .pipe(gulp.dest(paths.distAppProd));
};

pipes.builtAppDev = function() {
    return es.merge(pipes.builtIndexDev(), pipes.builtPartialsDev(), pipes.processedFaviconDev(), pipes.processedImagesDev(), pipes.processedFontsDev() );
};

pipes.builtAppProd = function() {
    return es.merge(pipes.builtIndexProd(), pipes.processedFaviconProd(), pipes.processedImagesProd(), pipes.processedFontsProd());
};


// == TASKS ========

// Add a task to render the output 
gulp.task('help', taskListing.withFilters(/-/));
   
// clean, build of production environement
gulp.task('build', ['clean-build-app-prod']);

// removes all compiled dev files
gulp.task('clean-dev', function() {
    var deferred = Q.defer();
    del(paths.distDev, function() {
        deferred.resolve();
    });
    return deferred.promise;
});

// removes all compiled production files
gulp.task('clean-prod', function() {
    var deferred = Q.defer();
    del(paths.distProd, function() {
        deferred.resolve();
    });
    return deferred.promise;
});

// checks html source files for syntax errors
gulp.task('validate-partials', pipes.validatedPartials);

// checks index.html for syntax errors
gulp.task('validate-index', pipes.validatedIndex);

// moves html source files into the dev environment
gulp.task('build-partials-dev', pipes.builtPartialsDev);

// converts partials to javascript using html2js
gulp.task('convert-partials-to-js', pipes.scriptedPartials);

// runs jshint on the app scripts
gulp.task('validate-app-scripts', pipes.validatedAppScripts);

// moves app scripts into the dev environment
gulp.task('build-app-scripts-dev', pipes.builtAppScriptsDev);

// concatenates, uglifies, and moves app scripts and partials into the prod environment
gulp.task('build-app-scripts-prod', pipes.builtAppScriptsProd);

// compiles app sass and moves to the dev environment
gulp.task('build-app-styles-dev', pipes.builtAppStylesDev);

// compiles and minifies app sass to css and moves to the prod environment
gulp.task('build-app-styles-prod', pipes.builtAppStylesProd);

// moves vendor scripts into the dev environment
gulp.task('build-vendor-scripts-dev', pipes.builtVendorScriptsDev);

// concatenates, uglifies, and moves vendor scripts into the prod environment
gulp.task('build-vendor-scripts-prod', pipes.builtVendorScriptsProd);

// validates and injects sources into index.html and moves it to the dev environment
gulp.task('build-index-dev', pipes.builtIndexDev);

// validates and injects sources into index.html, minifies and moves it to the dev environment
gulp.task('build-index-prod', pipes.builtIndexProd);

// builds a complete dev environment
gulp.task('build-app-dev', pipes.builtAppDev);

// builds a complete prod environment
gulp.task('build-app-prod', pipes.builtAppProd);

// cleans and builds a complete dev environment
gulp.task('clean-build-app-dev', ['clean-dev'], pipes.builtAppDev);

// cleans and builds a complete prod environment
gulp.task('clean-build-app-prod', ['clean-prod'], pipes.builtAppProd);

// clean, build, and watch live changes to the dev environment
gulp.task('watch-dev', ['clean-build-app-dev'], function() {

    // watch app scripts
    gulp.watch(paths.scripts, function() {
        return pipes.builtAppScriptsDev()
            .pipe(plugins.livereload());
    });

    // watch html partials
    gulp.watch(paths.partials, function() {
        return pipes.builtPartialsDev()
            .pipe(plugins.livereload());
    });
    
    // watch Images
    gulp.watch(paths.images, function() {
        return pipes.processedImagesDev()
            .pipe(plugins.livereload());
    });

    // watch styles
    gulp.watch(paths.appStyles, function() {
        return pipes.builtAppStylesDev()
            .pipe(plugins.livereload());
    });

});

// clean, build, and watch live changes to the prod environment
gulp.task('watch-prod', ['clean-build-app-prod'], function() {

    // watch index
    gulp.watch(paths.index, function() {
        return pipes.builtIndexProd()
            .pipe(plugins.livereload());
    });

    // watch app scripts
    gulp.watch(paths.scripts, function() {
        return pipes.builtAppScriptsProd()
            .pipe(plugins.livereload());
    });

    // watch hhtml partials
    gulp.watch(paths.partials, function() {
        return pipes.builtAppScriptsProd()
            .pipe(plugins.livereload());
    });
    
    // watch Images
    gulp.watch(paths.images, function() {
        return pipes.processedImagesProd()
            .pipe(plugins.livereload());
    });

    // watch styles
    gulp.watch(paths.appStyles, function() {
        return pipes.builtAppStylesProd()
            .pipe(plugins.livereload());
    });
    
});

// default task builds for prod
gulp.task('default', ['clean-build-app-prod']);
"o">->signature_ptr->node_address)); node_ptr->internal_infos.available = 0x01U; Rtm_StartRoutingTimer(self); ret_val = UCS_RET_SUCCESS; } } else { if (node_ptr->internal_infos.available == 0x01U) { TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Node with Addr {%X} is not available", 1U, node_ptr->signature_ptr->node_address)); node_ptr->internal_infos.available = 0x00U; Rtm_ReleaseSuspendedRoutes(self, node_ptr); Epm_ReportInvalidDevice (self->epm_ptr, node_ptr->signature_ptr->node_address); ret_val = UCS_RET_SUCCESS; } } } } return ret_val; } /*! \brief Retrieves the "available" flag of the given node. * \param self The routing instance pointer * \param node_ptr Reference to the node to be looked for. * \return The "available" flag of the node. */ bool Rtm_GetNodeAvailable(CRouteManagement * self, Ucs_Rm_Node_t *node_ptr) { bool ret_val = false; MISC_UNUSED (self); if (node_ptr != NULL) { ret_val = (node_ptr->internal_infos.available == 0x01U) ? true:false; } return ret_val; } /*! \brief Retrieves currently references of all routes attached to the given endpoint and stores It into an external routes table provided by user application. * Thus, User application should provide an external reference to an empty routes table where the potential routes will be stored. * That is, user application is responsible to allocate enough space to store the found routes. Otherwise, the max routes found will * equal the list size. * \param self The routing instance pointer * \param ep_inst Reference to the endpoint to be looked for. * \param ext_routes_list External empty table allocated by user application * \param size_list Size of the provided list * \return Possible return values are shown in the table below. * Value | Description * --------------------------- | --------------------------------------------------------------------- * UCS_RET_SUCCESS | No error * UCS_RET_ERR_PARAM | At least one parameter is NULL. */ Ucs_Return_t Rtm_GetAttachedRoutes(CRouteManagement * self, Ucs_Rm_EndPoint_t * ep_inst, Ucs_Rm_Route_t * ext_routes_list[], uint16_t size_list) { Ucs_Return_t ret_val = UCS_RET_ERR_PARAM; MISC_UNUSED (self); if ((ep_inst != NULL) && (ext_routes_list != NULL) && (size_list > 0U)) { bool curr_index_empty = true; uint8_t k = 0U, num_attached_routes = Sub_GetNumObservers(&ep_inst->internal_infos.subject_obj); CDlNode *n_tmp = (&(ep_inst->internal_infos.subject_obj))->list.head; Ucs_Rm_Route_t * tmp_rt = NULL; ret_val = UCS_RET_SUCCESS; for (; ((k < size_list) && (num_attached_routes > 0U) && (n_tmp != NULL)); k++) { ext_routes_list[k] = NULL; do { CObserver *o_tmp = (CObserver *)n_tmp->data_ptr; tmp_rt = (Ucs_Rm_Route_t *)o_tmp->inst_ptr; if ((tmp_rt != NULL) && ((tmp_rt->internal_infos.route_state == UCS_RM_ROUTE_BUILT) || (tmp_rt->internal_infos.route_state == UCS_RM_ROUTE_CONSTRUCTION) || (tmp_rt->internal_infos.route_state == UCS_RM_ROUTE_DESTRUCTION))) { curr_index_empty = false; ext_routes_list[k] = tmp_rt; } n_tmp = n_tmp->next; num_attached_routes--; } while ((curr_index_empty) && (num_attached_routes > 0U)); curr_index_empty = true; } if (k < size_list) { ext_routes_list[k] = NULL; } } return ret_val; } /*! \brief Retrieves the \c ConnectionLabel of the given route. * \param self The routing instance pointer * \param route_ptr Reference to the route to be looked for. * \return The "ConnectionLabel" of this route. */ uint16_t Rtm_GetConnectionLabel (CRouteManagement * self, Ucs_Rm_Route_t * route_ptr) { uint16_t conn_label = 0U; if ((self != NULL) && (route_ptr != NULL) && (route_ptr->internal_infos.route_state == UCS_RM_ROUTE_BUILT)) { conn_label = Epm_GetConnectionLabel(self->epm_ptr, route_ptr->source_endpoint_ptr); } return conn_label; } /*------------------------------------------------------------------------------------------------*/ /* Private Methods */ /*------------------------------------------------------------------------------------------------*/ /*! \brief Service function of the Sync management. * \param self Instance pointer */ static void Rtm_Service(void *self) { CRouteManagement *self_ = (CRouteManagement *)self; Srv_Event_t event_mask; Srv_GetEvent(&self_->rtm_srv, &event_mask); /* Event to process list of routes */ if((event_mask & RTM_EVENT_HANDLE_NEXTROUTE) == RTM_EVENT_HANDLE_NEXTROUTE) { Srv_ClearEvent(&self_->rtm_srv, RTM_EVENT_HANDLE_NEXTROUTE); Rtm_HandleNextRoute(self_); } /* Event to pause processing of routes list */ if ((event_mask & RTM_EVENT_PROCESS_PAUSE) == RTM_EVENT_PROCESS_PAUSE) { Srv_ClearEvent(&self_->rtm_srv, RTM_EVENT_PROCESS_PAUSE); Rtm_StopRoutesHandling(self_); } } /*! \brief This function starts the routing timer. * * Whenever this function is called the routing management process will resume in case it has been paused. * \param self Instance pointer */ static void Rtm_StartRoutingTimer (CRouteManagement * self) { if ((NULL != self) && (NULL != self->routes_list_ptr) && (0U < self->routes_list_size)) { Rtm_StartTmr4HandlingRoutes(self); } } /*! \brief Handles the next route in the list. * \param self Instance pointer */ static void Rtm_HandleNextRoute(CRouteManagement * self) { Ucs_Rm_Route_t * tmp_route; self->curr_route_ptr = Rtm_GetNextRoute(self); tmp_route = self->curr_route_ptr; switch (tmp_route->internal_infos.route_state) { case UCS_RM_ROUTE_IDLE: if (Rtm_IsRouteBuildable(self) == true) { Rtm_BuildRoute(self); } break; case UCS_RM_ROUTE_CONSTRUCTION: Rtm_BuildRoute(self); break; case UCS_RM_ROUTE_DETERIORATED: Rtm_HandleRoutingError(self, tmp_route); break; case UCS_RM_ROUTE_DESTRUCTION: Rtm_DestroyRoute(self); break; case UCS_RM_ROUTE_SUSPENDED: case UCS_RM_ROUTE_BUILT: if (tmp_route->active == false) { Rtm_DestroyRoute(self); } break; default: break; } } /*! \brief Checks whether the given route is buildable. * \param self Instance pointer * \return \c true if the route is buildable, otherwise \c false. */ static bool Rtm_IsRouteBuildable(CRouteManagement * self) { bool result_check = false; if (self->curr_route_ptr != NULL) { if ((self->curr_route_ptr->internal_infos.route_state == UCS_RM_ROUTE_IDLE) && (self->curr_route_ptr->active == true) && (self->curr_route_ptr->source_endpoint_ptr != NULL) && (self->curr_route_ptr->sink_endpoint_ptr != NULL)) { result_check = true; } } return result_check; } /*! \brief Checks whether the given route is destructible. * \param self Instance pointer * \param route_ptr Reference route to be checked * \return \c true if the route is destructible, otherwise \c false. */ static bool Rtm_IsRouteDestructible(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr) { bool result_check = false; MISC_UNUSED (self); if ((route_ptr != NULL) && (route_ptr->active == 0x01U) && ((route_ptr->internal_infos.route_state == UCS_RM_ROUTE_BUILT) || (route_ptr->internal_infos.route_state == UCS_RM_ROUTE_SUSPENDED))) { result_check = true; } return result_check; } /*! \brief Checks whether the given route can be activated. * \param self Instance pointer * \param route_ptr Reference route to be checked * \return \c true if the route is destructible, otherwise \c false. */ static bool Rtm_IsRouteActivatable(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr) { bool result_check = false; MISC_UNUSED (self); if ((route_ptr != NULL) && (route_ptr->internal_infos.route_state == UCS_RM_ROUTE_IDLE) && (route_ptr->active == 0x0U)) { result_check = true; } return result_check; } /*! \brief Deactivates the given route reference. * \param self Instance pointer * \param route_ptr Reference route to be deactivated */ static void Rtm_DisableRoute(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr) { MISC_UNUSED (self); if (route_ptr != NULL) { route_ptr->active = false; } } /*! \brief Activates the given route reference. * \param self Instance pointer * \param route_ptr Reference route to be activated */ static void Rtm_EnableRoute(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr) { MISC_UNUSED (self); if (route_ptr != NULL) { route_ptr->active = true; } } /*! \brief Builds the current Route. * \param self Instance pointer */ static void Rtm_BuildRoute(CRouteManagement * self) { bool result_critical = false; Ucs_Rm_EndPointState_t ep_state = Epm_GetState(self->epm_ptr, self->curr_route_ptr->source_endpoint_ptr); switch (ep_state) { case UCS_RM_EP_IDLE: result_critical = Rtm_CheckEpResultSeverity(self, self->curr_route_ptr, self->curr_route_ptr->source_endpoint_ptr); if (!result_critical) { if (self->curr_route_ptr->internal_infos.src_obsvr_initialized == 0U) { self->curr_route_ptr->internal_infos.src_obsvr_initialized = 1U; Epm_DelObserver(self->curr_route_ptr->source_endpoint_ptr, &self->curr_route_ptr->internal_infos.source_ep_observer); Obs_Ctor(&self->curr_route_ptr->internal_infos.source_ep_observer, self->curr_route_ptr, &Rtm_EndPointDeterioredCb); /* Initializes source endpoint internal data */ Epm_InitInternalInfos (self->epm_ptr, self->curr_route_ptr->source_endpoint_ptr); } (void)Rtm_BuildEndPoint(self, self->curr_route_ptr->source_endpoint_ptr); } break; case UCS_RM_EP_BUILT: /* In case of shared source endpoint by another route */ if (self->curr_route_ptr->internal_infos.src_obsvr_initialized == 0U) { self->curr_route_ptr->internal_infos.src_obsvr_initialized = 1U; Epm_DelObserver(self->curr_route_ptr->source_endpoint_ptr, &self->curr_route_ptr->internal_infos.source_ep_observer); Obs_Ctor(&self->curr_route_ptr->internal_infos.source_ep_observer, self->curr_route_ptr, &Rtm_EndPointDeterioredCb); Epm_AddObserver(self->curr_route_ptr->source_endpoint_ptr, &self->curr_route_ptr->internal_infos.source_ep_observer); } ep_state = Epm_GetState(self->epm_ptr, self->curr_route_ptr->sink_endpoint_ptr); switch(ep_state) { case UCS_RM_EP_IDLE: result_critical = Rtm_CheckEpResultSeverity(self, self->curr_route_ptr, self->curr_route_ptr->sink_endpoint_ptr); if (!result_critical) { if (self->curr_route_ptr->internal_infos.sink_obsvr_initialized == 0U) { self->curr_route_ptr->internal_infos.sink_obsvr_initialized = 1U; Obs_Ctor(&self->curr_route_ptr->internal_infos.sink_ep_observer, self->curr_route_ptr, &Rtm_EndPointDeterioredCb); /* Initializes sink endpoint internal data */ Epm_InitInternalInfos (self->epm_ptr, self->curr_route_ptr->sink_endpoint_ptr); } Epm_SetConnectionLabel(self->epm_ptr, self->curr_route_ptr->sink_endpoint_ptr, Epm_GetConnectionLabel(self->epm_ptr, self->curr_route_ptr->source_endpoint_ptr)); (void)Rtm_BuildEndPoint(self, self->curr_route_ptr->sink_endpoint_ptr); } break; case UCS_RM_EP_BUILT: TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Route id {%X} is built", 1U, self->curr_route_ptr->route_id)); self->curr_route_ptr->internal_infos.route_state = UCS_RM_ROUTE_BUILT; if (self->report_fptr != NULL) { self->report_fptr(self->curr_route_ptr, UCS_RM_ROUTE_INFOS_BUILT, self->base_ptr->ucs_user_ptr); } break; case UCS_RM_EP_XRMPROCESSING: default: result_critical = Rtm_UnlockPossibleBlockings(self, self->curr_route_ptr, self->curr_route_ptr->sink_endpoint_ptr); break; } break; case UCS_RM_EP_XRMPROCESSING: default: result_critical = Rtm_UnlockPossibleBlockings(self, self->curr_route_ptr, self->curr_route_ptr->source_endpoint_ptr); break; } if (result_critical) { self->curr_route_ptr->internal_infos.route_state = UCS_RM_ROUTE_DETERIORATED; } } /*! \brief Destroys the current Route. * \param self Instance pointer */ static void Rtm_DestroyRoute(CRouteManagement * self) { bool result_critical = false; bool destruction_completed = false; Ucs_Rm_EndPointState_t ep_state = Epm_GetState(self->epm_ptr, self->curr_route_ptr->sink_endpoint_ptr); switch (ep_state) { case UCS_RM_EP_BUILT: (void)Rtm_DeactivateRouteEndPoint(self, self->curr_route_ptr->sink_endpoint_ptr); break; case UCS_RM_EP_IDLE: ep_state = Epm_GetState(self->epm_ptr, self->curr_route_ptr->source_endpoint_ptr); switch(ep_state) { case UCS_RM_EP_BUILT: /* if source endpoint cannot be built since it's used in another route(s), however consider that the route is destroyed. */ if (Rtm_DeactivateRouteEndPoint(self, self->curr_route_ptr->source_endpoint_ptr) == UCS_RET_ERR_INVALID_SHADOW) { destruction_completed = true; } break; case UCS_RM_EP_IDLE: destruction_completed = true; break; case UCS_RM_EP_XRMPROCESSING: default: result_critical = Rtm_UnlockPossibleBlockings(self, self->curr_route_ptr, self->curr_route_ptr->source_endpoint_ptr); break; } break; case UCS_RM_EP_XRMPROCESSING: default: result_critical = Rtm_UnlockPossibleBlockings(self, self->curr_route_ptr, self->curr_route_ptr->sink_endpoint_ptr); break; } if (result_critical) { self->curr_route_ptr->internal_infos.route_state = UCS_RM_ROUTE_DETERIORATED; } else if (destruction_completed) { TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Route id {%X} has been destroyed", 1U, self->curr_route_ptr->route_id)); self->curr_route_ptr->internal_infos.route_state = UCS_RM_ROUTE_IDLE; self->curr_route_ptr->internal_infos.src_obsvr_initialized = 0U; if (self->report_fptr != NULL) { self->report_fptr(self->curr_route_ptr, UCS_RM_ROUTE_INFOS_DESTROYED, self->base_ptr->ucs_user_ptr); } } } /*! \brief Builds the given endpoint. * \param self Instance pointer * \param endpoint_ptr Reference to the endpoint to be looked for * \return Possible return values are * - \c UCS_RET_ERR_API_LOCKED the API is locked. Endpoint is currently being processed. * - \c UCS_RET_SUCCESS the build process was set successfully * - \c UCS_RET_ERR_PARAM NULL pointer detected in the parameter list * - \c UCS_RET_ERR_ALREADY_SET the endpoint has already been set */ static Ucs_Return_t Rtm_BuildEndPoint(CRouteManagement * self, Ucs_Rm_EndPoint_t * endpoint_ptr) { Ucs_Return_t result = UCS_RET_ERR_PARAM; if ((self != NULL) && (endpoint_ptr != NULL)) { result = Epm_SetBuildProcess(self->epm_ptr, endpoint_ptr); if (result == UCS_RET_SUCCESS) { Epm_AddObserver (endpoint_ptr, (endpoint_ptr->endpoint_type == UCS_RM_EP_SOURCE) ? &self->curr_route_ptr->internal_infos.source_ep_observer: &self->curr_route_ptr->internal_infos.sink_ep_observer); self->curr_route_ptr->internal_infos.route_state = UCS_RM_ROUTE_CONSTRUCTION; TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Start Building Endpoint {%X} of type %s for route id %X", 3U, endpoint_ptr, (endpoint_ptr->endpoint_type == UCS_RM_EP_SOURCE) ? "Source":"Sink", self->curr_route_ptr->route_id)); } else if (result == UCS_RET_ERR_ALREADY_SET) { TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Endpoint {%X} of type %s for route id %X has already been built", 3U, endpoint_ptr, (endpoint_ptr->endpoint_type == UCS_RM_EP_SOURCE) ? "Source":"Sink", self->curr_route_ptr->route_id)); } } return result; } /*! \brief Destroys the given endpoint. * \param self Instance pointer * \param endpoint_ptr Reference to the endpoint to be looked for * \return Possible return values are * - \c UCS_RET_ERR_API_LOCKED the API is locked. Endpoint is currently being processed. * - \c UCS_RET_SUCCESS the build process was set successfully * - \c UCS_RET_ERR_PARAM NULL pointer detected in the parameter list * - \c UCS_RET_ERR_ALREADY_SET the endpoint has already been set * - \c UCS_RET_ERR_NOT_AVAILABLE the endpoint is no more available. * - \c UCS_RET_ERR_INVALID_SHADOW the endpoint cannot be destroyed since it's still in use by another routes. */ static Ucs_Return_t Rtm_DeactivateRouteEndPoint(CRouteManagement * self, Ucs_Rm_EndPoint_t * endpoint_ptr) { Ucs_Return_t result = UCS_RET_ERR_PARAM; if ((self != NULL) && (endpoint_ptr != NULL) && (endpoint_ptr->node_obj_ptr != NULL) && (endpoint_ptr->node_obj_ptr->signature_ptr != NULL)) { if ((endpoint_ptr->node_obj_ptr->internal_infos.available == 1U) || (endpoint_ptr->node_obj_ptr->signature_ptr->node_address == UCS_ADDR_LOCAL_DEV)) { result = Epm_SetDestroyProcess(self->epm_ptr, endpoint_ptr); if (result == UCS_RET_SUCCESS) { self->curr_route_ptr->internal_infos.route_state = UCS_RM_ROUTE_DESTRUCTION; TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Start Destroying Endpoint {%X} of type %s for route id %X", 3U, endpoint_ptr, (endpoint_ptr->endpoint_type == UCS_RM_EP_SOURCE) ? "Source":"Sink", self->curr_route_ptr->route_id)); } else if (result == UCS_RET_ERR_ALREADY_SET) { TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Endpoint {%X} of type %s for route id %X has already been destroyed", 3U, endpoint_ptr, (endpoint_ptr->endpoint_type == UCS_RM_EP_SOURCE) ? "Source":"Sink", self->curr_route_ptr->route_id)); } else if (result == UCS_RET_ERR_INVALID_SHADOW) { TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Endpoint {%X} of type %s for route id %X cannot be destroyed since it's still used", 3U, endpoint_ptr, (endpoint_ptr->endpoint_type == UCS_RM_EP_SOURCE) ? "Source":"Sink", self->curr_route_ptr->route_id)); } else if (result == UCS_RET_ERR_NOT_AVAILABLE) { TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Endpoint {%X} of type %s for route id %X is no more available", 3U, endpoint_ptr, (endpoint_ptr->endpoint_type == UCS_RM_EP_SOURCE) ? "Source" : "Sink", self->curr_route_ptr->route_id)); } } else { /* Completed */ Epm_ResetState(self->epm_ptr, endpoint_ptr); } } return result; } /*! \brief Classifies and sets the corresponding route error and then informs user about the new state. * \param self Instance pointer * \param route_ptr Reference to the route to be looked for */ static void Rtm_HandleRoutingError(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr) { Ucs_Rm_Route_t * tmp_route = route_ptr; Ucs_Rm_RouteInfos_t result_route = UCS_RM_ROUTE_INFOS_DESTROYED; Ucs_Rm_RouteResult_t res_rt = tmp_route->internal_infos.last_route_result; tmp_route->internal_infos.route_state = UCS_RM_ROUTE_IDLE; tmp_route->internal_infos.last_route_result = UCS_RM_ROUTE_NOERROR; if (res_rt != UCS_RM_ROUTE_CRITICAL) { if (tmp_route->source_endpoint_ptr->internal_infos.endpoint_state == UCS_RM_EP_IDLE) { if (Rtm_CheckEpResultSeverity(self, tmp_route, tmp_route->source_endpoint_ptr)) { Epm_ResetState(self->epm_ptr, tmp_route->source_endpoint_ptr); tmp_route->internal_infos.route_state = UCS_RM_ROUTE_SUSPENDED; result_route = UCS_RM_ROUTE_INFOS_SUSPENDED; TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Route id {%X} is suspended", 1U, tmp_route->route_id)); } } else if (tmp_route->sink_endpoint_ptr->internal_infos.endpoint_state == UCS_RM_EP_IDLE) { if (Rtm_CheckEpResultSeverity(self, tmp_route, tmp_route->sink_endpoint_ptr)) { Epm_ResetState(self->epm_ptr, tmp_route->sink_endpoint_ptr); tmp_route->internal_infos.route_state = UCS_RM_ROUTE_SUSPENDED; result_route = UCS_RM_ROUTE_INFOS_SUSPENDED; TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Route id {%X} is suspended", 1U, tmp_route->route_id)); } } else { TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Route id {%X} is destroyed", 1U, tmp_route->route_id)); } } else { Epm_ResetState(self->epm_ptr, tmp_route->source_endpoint_ptr); Epm_ResetState(self->epm_ptr, tmp_route->sink_endpoint_ptr); tmp_route->internal_infos.route_state = UCS_RM_ROUTE_SUSPENDED; result_route = UCS_RM_ROUTE_INFOS_SUSPENDED; TR_INFO((self->base_ptr->ucs_user_ptr, "[RTM]", "Route id {%X} is suspended", 1U, tmp_route->route_id)); } if (self->report_fptr != NULL) { self->report_fptr(tmp_route, result_route, self->base_ptr->ucs_user_ptr); } } /*! \brief Checks whether the endpoint's result is critical or not and stores the result into the target route. * \param self Instance pointer * \param tgt_route_ptr Reference to the route that contains the endpoint to be looked for * \param endpoint_ptr Reference to the endpoint to be looked for * \return \c true if the endpoint result is critical, otherwise \c false. */ static bool Rtm_CheckEpResultSeverity(CRouteManagement * self, Ucs_Rm_Route_t * tgt_route_ptr, Ucs_Rm_EndPoint_t * endpoint_ptr) { bool result_check = false; Ucs_Rm_RouteResult_t result = UCS_RM_ROUTE_NOERROR; /*! \brief Maximum number of retries allowed in error situation */ uint8_t RTM_MAX_NUM_RETRIES_IN_ERR = 0xFFU; if ((endpoint_ptr != NULL) && (tgt_route_ptr != NULL)) { switch (endpoint_ptr->internal_infos.xrm_result.code) { case UCS_XRM_RES_ERR_BUILD: case UCS_XRM_RES_ERR_DESTROY: case UCS_XRM_RES_ERR_SYNC: switch (endpoint_ptr->internal_infos.xrm_result.details.result_type) { case UCS_XRM_RESULT_TYPE_TX: if ((UCS_MSG_STAT_ERROR_CFG_NO_RCVR == endpoint_ptr->internal_infos.xrm_result.details.tx_result) || (UCS_MSG_STAT_ERROR_FATAL_OA == endpoint_ptr->internal_infos.xrm_result.details.tx_result) || (endpoint_ptr->internal_infos.num_retries == RTM_MAX_NUM_RETRIES_IN_ERR)) { result = UCS_RM_ROUTE_CRITICAL; TR_ERROR((self->base_ptr->ucs_user_ptr, "[RTM]", "Critical error occurred on route id {%X} due to the transmission error code {Ucs_MsgTxStatus_t:0x%02X} observed in XRM.", 2U, tgt_route_ptr->route_id, endpoint_ptr->internal_infos.xrm_result.details.tx_result)); } else if ((UCS_MSG_STAT_ERROR_UNKNOWN == endpoint_ptr->internal_infos.xrm_result.details.tx_result) || (UCS_MSG_STAT_ERROR_FATAL_WT == endpoint_ptr->internal_infos.xrm_result.details.tx_result) || (UCS_MSG_STAT_ERROR_TIMEOUT == endpoint_ptr->internal_infos.xrm_result.details.tx_result) || (UCS_MSG_STAT_ERROR_BF == endpoint_ptr->internal_infos.xrm_result.details.tx_result) || (UCS_MSG_STAT_ERROR_CRC == endpoint_ptr->internal_infos.xrm_result.details.tx_result) || (UCS_MSG_STAT_ERROR_NA_TRANS == endpoint_ptr->internal_infos.xrm_result.details.tx_result) || (UCS_MSG_STAT_ERROR_ACK == endpoint_ptr->internal_infos.xrm_result.details.tx_result) || (UCS_MSG_STAT_ERROR_ID == endpoint_ptr->internal_infos.xrm_result.details.tx_result)) { endpoint_ptr->internal_infos.num_retries++; result = UCS_RM_ROUTE_UNCRITICAL; } break; case UCS_XRM_RESULT_TYPE_TGT: if ((UCS_RES_ERR_CONFIGURATION == endpoint_ptr->internal_infos.xrm_result.details.inic_result.code) || (UCS_RES_ERR_MOST_STANDARD == endpoint_ptr->internal_infos.xrm_result.details.inic_result.code) || (UCS_RES_ERR_SYSTEM == endpoint_ptr->internal_infos.xrm_result.details.inic_result.code) || (endpoint_ptr->internal_infos.num_retries == RTM_MAX_NUM_RETRIES_IN_ERR)) { result = UCS_RM_ROUTE_CRITICAL; TR_ERROR((self->base_ptr->ucs_user_ptr, "[RTM]", "Critical error occurred on route id {%X} due to the INIC result code {Ucs_Result_t:0x%02X} observed in XRM.", 2U, tgt_route_ptr->route_id, endpoint_ptr->internal_infos.xrm_result.details.inic_result.code)); } else if ((UCS_RES_ERR_BUSY == endpoint_ptr->internal_infos.xrm_result.details.inic_result.code) || (UCS_RES_ERR_TIMEOUT == endpoint_ptr->internal_infos.xrm_result.details.inic_result.code) || (UCS_RES_ERR_PROCESSING == endpoint_ptr->internal_infos.xrm_result.details.inic_result.code)) { endpoint_ptr->internal_infos.num_retries++; result = UCS_RM_ROUTE_UNCRITICAL; } break; case UCS_XRM_RESULT_TYPE_INT: if ((endpoint_ptr->internal_infos.xrm_result.details.int_result == UCS_RET_ERR_NOT_AVAILABLE) || (endpoint_ptr->internal_infos.xrm_result.details.int_result == UCS_RET_ERR_NOT_SUPPORTED) || (endpoint_ptr->internal_infos.xrm_result.details.int_result == UCS_RET_ERR_PARAM) || (endpoint_ptr->internal_infos.xrm_result.details.int_result == UCS_RET_ERR_NOT_INITIALIZED) || (endpoint_ptr->internal_infos.num_retries == RTM_MAX_NUM_RETRIES_IN_ERR)) { result = UCS_RM_ROUTE_CRITICAL; TR_ERROR((self->base_ptr->ucs_user_ptr, "[RTM]", "Critical error occurred on route id {%X} due to the internal error code {Ucs_Return_t:0x%02X} observed in XRM.", 2U, tgt_route_ptr->route_id, endpoint_ptr->internal_infos.xrm_result.details.int_result)); } else if ((endpoint_ptr->internal_infos.xrm_result.details.int_result == UCS_RET_ERR_BUFFER_OVERFLOW) || (endpoint_ptr->internal_infos.xrm_result.details.int_result == UCS_RET_ERR_API_LOCKED) || (endpoint_ptr->internal_infos.xrm_result.details.int_result == UCS_RET_ERR_INVALID_SHADOW)) { endpoint_ptr->internal_infos.num_retries++; result = UCS_RM_ROUTE_UNCRITICAL; } break; default: break; } break; case UCS_XRM_RES_ERR_CONFIG: result = UCS_RM_ROUTE_CRITICAL; break; case UCS_XRM_RES_SUCCESS_BUILD: case UCS_XRM_RES_SUCCESS_DESTROY: endpoint_ptr->internal_infos.num_retries = 0U; break; default: break; } /* Sets route result */ tgt_route_ptr->internal_infos.last_route_result = result; if (result == UCS_RM_ROUTE_CRITICAL) { result_check = true; } } MISC_UNUSED(self); return result_check; } /*! \brief Sets curr_route_ptr to the next route. * \param self Instance pointer * \return \c true if the endpoint result is critical, otherwise \c false. */ static bool Rtm_SetNextRouteIndex(CRouteManagement * self) { bool found = false; if ((self->routes_list_size > 0U) && (self->nw_available)) { uint16_t tmp_idx; self->curr_route_index++; self->curr_route_index = self->curr_route_index%self->routes_list_size; tmp_idx = self->curr_route_index; do { if (((self->routes_list_ptr[self->curr_route_index].internal_infos.route_state == UCS_RM_ROUTE_SUSPENDED) && (self->routes_list_ptr[self->curr_route_index].active == true)) || ((self->routes_list_ptr[self->curr_route_index].active == true) && (self->routes_list_ptr[self->curr_route_index].internal_infos.route_state == UCS_RM_ROUTE_BUILT)) || ((self->routes_list_ptr[self->curr_route_index].active == false) && (self->routes_list_ptr[self->curr_route_index].internal_infos.route_state == UCS_RM_ROUTE_IDLE)) || ((Rtm_AreRouteNodesAvailable(self, &self->routes_list_ptr[self->curr_route_index]) == false) && (self->routes_list_ptr[self->curr_route_index].internal_infos.route_state == UCS_RM_ROUTE_IDLE))) { self->curr_route_index++; self->curr_route_index = self->curr_route_index%self->routes_list_size; } else { found = true; } } while ((tmp_idx != self->curr_route_index) && (found == false)); } return found; } /*! \brief Starts the timer for handling routes. * \param self Instance pointer */ static void Rtm_StartTmr4HandlingRoutes(CRouteManagement * self) { if((T_IsTimerInUse(&self->route_check) == false) && (!self->ucs_is_stopping)) { Tm_SetTimer(self->tm_ptr, &self->route_check, &Rtm_ExecRoutesHandling, self, RTM_JOB_CHECK_INTERVAL, RTM_JOB_CHECK_INTERVAL); } } /*! \brief Gets the next route. * \param self Instance pointer * \return the next route to be handled */ static Ucs_Rm_Route_t * Rtm_GetNextRoute(CRouteManagement * self) { self->routes_list_ptr[self->curr_route_index].internal_infos.rtm_inst = (Rtm_Inst_t *)(void *)self; return &self->routes_list_ptr[self->curr_route_index]; } /*! \brief Checks if the API is locked. * \param self Instance pointer * \return \c true if the API is not locked and the UCS are initialized, otherwise \c false. */ static bool Rtm_IsApiFree(CRouteManagement *self) { return (self->lock_api == false); } /*! \brief Locks/Unlocks the RTM API. * \param self Instance pointer * \param status Locking status. \c true = Lock, \c false = Unlock */ static void Rtm_ApiLocking(CRouteManagement *self, bool status) { self->lock_api = status; } /*! \brief Checks whether the nodes (source and sink) of the current route is available. * \param self Instance pointer * \param route_ptr Reference to the Route to be looked for * \return \c true if the source endpoint's node is available, otherwise \c false. */ static bool Rtm_AreRouteNodesAvailable(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr) { bool result = false; MISC_UNUSED (self); if ((route_ptr->source_endpoint_ptr != NULL) && (route_ptr->sink_endpoint_ptr != NULL)) { if ((route_ptr->source_endpoint_ptr->node_obj_ptr != NULL) && (route_ptr->source_endpoint_ptr->node_obj_ptr->signature_ptr != NULL) && (route_ptr->sink_endpoint_ptr->node_obj_ptr != NULL) && (route_ptr->sink_endpoint_ptr->node_obj_ptr->signature_ptr != NULL)) { if (((1U == route_ptr->source_endpoint_ptr->node_obj_ptr->internal_infos.available) || (route_ptr->source_endpoint_ptr->node_obj_ptr->signature_ptr->node_address == UCS_ADDR_LOCAL_DEV) || (Net_IsOwnAddress(self->net_ptr, route_ptr->source_endpoint_ptr->node_obj_ptr->signature_ptr->node_address) == NET_IS_OWN_ADDR_NODE)) && ((Net_IsOwnAddress(self->net_ptr, route_ptr->sink_endpoint_ptr->node_obj_ptr->signature_ptr->node_address) == NET_IS_OWN_ADDR_NODE) || (route_ptr->sink_endpoint_ptr->node_obj_ptr->signature_ptr->node_address == UCS_ADDR_LOCAL_DEV) || (1U == route_ptr->sink_endpoint_ptr->node_obj_ptr->internal_infos.available))) { result = true; } } } else { TR_ERROR((self->base_ptr->ucs_user_ptr, "[RTM]", "ERROR PARAMETER on route id {%X}: At least one endpoint is NULL.", 1U, route_ptr->route_id)); } return result; } /*! \brief Checks if we encountered a deadlock situation with the given route and if we do, resolves It by resetting the endpoint concerned. * * Since we can encounter the situation that the construction of an endpoint fails and the routing management is not aware of that (synchronous vs asynchronous response) * and still consider that the route is processing. In such a case the RTM process will never get a response and will wait in vain for It. * Therefore, the role of this function is to release the blocking situation in resetting the concerned endpoint. * \param self Instance pointer * \param tgt_route_ptr Reference to the route that contains the endpoint to be looked for * \param endpoint_ptr Reference to the endpoint to be looked for * \return \c true if the endpoint's result is critical, otherwise \c false */ static bool Rtm_UnlockPossibleBlockings(CRouteManagement * self, Ucs_Rm_Route_t * tgt_route_ptr, Ucs_Rm_EndPoint_t * endpoint_ptr) { bool result_critical = Rtm_CheckEpResultSeverity(self, tgt_route_ptr, endpoint_ptr); if (!result_critical) { if (UCS_RM_ROUTE_UNCRITICAL == self->curr_route_ptr->internal_infos.last_route_result) { Epm_ResetState(self->epm_ptr, endpoint_ptr); } } return result_critical; } /*! \brief Stops routes handling. * \param self Instance pointer */ static void Rtm_StopRoutesHandling(CRouteManagement * self) { Tm_ClearTimer(self->tm_ptr, &self->route_check); } /*! \brief Releases all routes endpoints and notifies that the process is terminated for all "active" routes, which are not built or suspended. * \param self Instance pointer */ static void Rtm_HandleProcessTermination(CRouteManagement * self) { if ((self->routes_list_ptr != NULL) && (self->routes_list_size > 0U)) { uint8_t k = 0U; for (; k < self->routes_list_size; k++) { Epm_ClearIntInfos(self->epm_ptr, self->routes_list_ptr[k].source_endpoint_ptr); Epm_ClearIntInfos(self->epm_ptr, self->routes_list_ptr[k].sink_endpoint_ptr); if ((self->routes_list_ptr[k].active == 1U) && (self->routes_list_ptr[k].internal_infos.notify_termination == 0U) && (self->routes_list_ptr[k].internal_infos.route_state != UCS_RM_ROUTE_BUILT) && (self->routes_list_ptr[k].internal_infos.route_state != UCS_RM_ROUTE_SUSPENDED)) { if ((self->routes_list_ptr[k].internal_infos.route_state == UCS_RM_ROUTE_CONSTRUCTION) || (self->routes_list_ptr[k].internal_infos.route_state == UCS_RM_ROUTE_DESTRUCTION)) { self->routes_list_ptr[k].internal_infos.route_state = UCS_RM_ROUTE_IDLE; } self->routes_list_ptr[k].internal_infos.notify_termination = 0x01U; if (self->report_fptr != NULL) { self->report_fptr(&self->routes_list_ptr[k], UCS_RM_ROUTE_INFOS_PROCESS_STOP, self->base_ptr->ucs_user_ptr); } } } } } /*! \brief Resets the availability flag of all nodes involved in routing process. * \param self Instance pointer */ static void Rtm_ResetNodesAvailable(CRouteManagement * self) { uint8_t k = 0U; if ((self->routes_list_ptr != NULL) && (self->routes_list_size > 0U)) { for (; k < self->routes_list_size; k++) { if ((self->routes_list_ptr[k].sink_endpoint_ptr != NULL) && (self->routes_list_ptr[k].sink_endpoint_ptr->node_obj_ptr != NULL)) { self->routes_list_ptr[k].sink_endpoint_ptr->node_obj_ptr->internal_infos.available = 0U; } if ((self->routes_list_ptr[k].source_endpoint_ptr != NULL) && (self->routes_list_ptr[k].source_endpoint_ptr->node_obj_ptr != NULL)) { self->routes_list_ptr[k].source_endpoint_ptr->node_obj_ptr->internal_infos.available = 0U; } } } } /*! \brief Releases all suspended routes of the given node. * \details This function should only be called when the provided node, on which the suspended routes are, * is set to "not available". * \param self Instance pointer * \param node_ptr Reference to the node to be looked for */ static void Rtm_ReleaseSuspendedRoutes(CRouteManagement * self, Ucs_Rm_Node_t *node_ptr) { uint8_t k = 0U; bool is_ep_result_critical = false; if ((self != NULL) && (self->routes_list_ptr != NULL) && (self->routes_list_size > 0U) && (node_ptr != NULL)) { for (; k < self->routes_list_size; k++) { is_ep_result_critical = Rtm_CheckEpResultSeverity(self, &self->routes_list_ptr[k], self->routes_list_ptr[k].sink_endpoint_ptr); if ((self->routes_list_ptr[k].internal_infos.route_state == UCS_RM_ROUTE_SUSPENDED) || ((self->routes_list_ptr[k].internal_infos.route_state == UCS_RM_ROUTE_DETERIORATED) && (self->routes_list_ptr[k].internal_infos.last_route_result == UCS_RM_ROUTE_CRITICAL)) || ((self->routes_list_ptr[k].internal_infos.route_state == UCS_RM_ROUTE_CONSTRUCTION) && (is_ep_result_critical))) { if (((self->routes_list_ptr[k].source_endpoint_ptr != NULL) && (self->routes_list_ptr[k].source_endpoint_ptr->node_obj_ptr == node_ptr)) || ((self->routes_list_ptr[k].sink_endpoint_ptr != NULL) && (self->routes_list_ptr[k].sink_endpoint_ptr->node_obj_ptr == node_ptr))) { Rtm_ForcesRouteToIdle(self, &self->routes_list_ptr[k]); } } } } } /*! \brief Sets the given routes to the "Idle" state and resets its internal variables. * \details This function is risky and should only be used in Rtm_ReleaseSuspendedRoutes(). Because it forces a route's state to "Idle" * without any external events. * \param self Instance pointer * \param route_ptr Reference to the route to be set */ static void Rtm_ForcesRouteToIdle(CRouteManagement * self, Ucs_Rm_Route_t * route_ptr) { if ((self != NULL) && (route_ptr != NULL)) { route_ptr->internal_infos.route_state = UCS_RM_ROUTE_IDLE; route_ptr->internal_infos.last_route_result = UCS_RM_ROUTE_NOERROR; if (route_ptr->source_endpoint_ptr != NULL) { if (Rtm_CheckEpResultSeverity(self, route_ptr, route_ptr->source_endpoint_ptr)) { Epm_ResetState(self->epm_ptr, route_ptr->source_endpoint_ptr); } } if (route_ptr->sink_endpoint_ptr != NULL) { if (Rtm_CheckEpResultSeverity(self, route_ptr, route_ptr->sink_endpoint_ptr)) { Epm_ResetState(self->epm_ptr, route_ptr->sink_endpoint_ptr); } } } } /*------------------------------------------------------------------------------------------------*/ /* Callback Functions */ /*------------------------------------------------------------------------------------------------*/ /*! \brief Called if UCS initialization has been succeeded. * \param self Instance pointer * \param event_ptr Reference to reported event */ static void Rtm_UcsInitSucceededCb(void *self, void *event_ptr) { CRouteManagement *self_ = (CRouteManagement *)self; MISC_UNUSED(event_ptr); /* Remove ucsinit_observer */ Eh_DelObsrvInternalEvent(&self_->base_ptr->eh, &self_->ucsinit_observer); /* Add network status observer */ Mobs_Ctor(&self_->nwstatus_observer, self, RTM_MASK_NETWORK_AVAILABILITY, &Rtm_MnsNwStatusInfosCb); Net_AddObserverNetworkStatus(self_->net_ptr, &self_->nwstatus_observer); } /*! \brief Handle internal errors and un-initialize RTM service. * \param self Instance pointer * \param error_code_ptr Reference to internal error code */ static void Rtm_UninitializeService(void *self, void *error_code_ptr) { CRouteManagement *self_ = (CRouteManagement *)self; MISC_UNUSED(error_code_ptr); self_->ucs_is_stopping = true; /* Notify destruction of current routes */ Rtm_HandleProcessTermination(self_); /* Remove RTM service from schedulers list */ (void)Scd_RemoveService(&self_->base_ptr->scd, &self_->rtm_srv); /* Remove error/event observers */ Eh_DelObsrvInternalEvent(&self_->base_ptr->eh, &self_->ucstermination_observer); Net_DelObserverNetworkStatus(self_->net_ptr, &self_->nwstatus_observer); /* Unlock API */ Rtm_ApiLocking(self_, false); } /*! \brief Event Callback function for the network status. * \param self Instance pointer * \param event_ptr Reference to the events */ static void Rtm_MnsNwStatusInfosCb(void *self, void *event_ptr) { CRouteManagement *self_ = (CRouteManagement *)self; Net_NetworkStatusParam_t *result_ptr_ = (Net_NetworkStatusParam_t *)event_ptr; if (RTM_MASK_NETWORK_AVAILABILITY == (RTM_MASK_NETWORK_AVAILABILITY & result_ptr_->change_mask)) { if (UCS_NW_NOT_AVAILABLE == result_ptr_->availability) { self_->nw_available = false; /* Resets Nodes availability flag */ Rtm_ResetNodesAvailable(self_); /* Reports Network Status "NotAvailabe" */ Epm_ReportShutDown(self_->epm_ptr); } else { self_->nw_available = true; /* Check whether there are routes to be processed */ Rtm_StartRoutingTimer (self_); } } } /*! \brief Event Callback function that signals that an endpoint is unavailable. * \param self Instance pointer * \param result_ptr Reference to the results */ static void Rtm_EndPointDeterioredCb(void *self, void *result_ptr) { Ucs_Rm_Route_t * route_ptr = (Ucs_Rm_Route_t *)self; Ucs_Rm_EndPoint_t * ep_ptr = (Ucs_Rm_EndPoint_t *)result_ptr; if ((route_ptr->source_endpoint_ptr == ep_ptr) || (route_ptr->sink_endpoint_ptr == ep_ptr)) { if (route_ptr->internal_infos.route_state == UCS_RM_ROUTE_BUILT) { TR_INFO((((CRouteManagement *)(void *)route_ptr->internal_infos.rtm_inst)->base_ptr->ucs_user_ptr, "[RTM]", "Route id %X is deteriorated", 1U, route_ptr->route_id)); if (ep_ptr->endpoint_type == UCS_RM_EP_SOURCE) { route_ptr->internal_infos.src_obsvr_initialized = 0U; } Rtm_HandleRoutingError((CRouteManagement *)(void *)route_ptr->internal_infos.rtm_inst, route_ptr); if ((((CRouteManagement *)(void *)route_ptr->internal_infos.rtm_inst)->nw_available) && (!((CRouteManagement *)(void *)route_ptr->internal_infos.rtm_inst)->ucs_is_stopping)) { Rtm_StartTmr4HandlingRoutes((CRouteManagement *)(void *)route_ptr->internal_infos.rtm_inst); } else if (((CRouteManagement *)(void *)route_ptr->internal_infos.rtm_inst)->ucs_is_stopping) { Rtm_HandleProcessTermination((CRouteManagement *)(void *)route_ptr->internal_infos.rtm_inst); } } } else { TR_ERROR((((CRouteManagement *)(void *)route_ptr->internal_infos.rtm_inst)->base_ptr->ucs_user_ptr, "[RTM]", "Wrong endpoint {%X} of type %s on route id {%X}.", 3U, ep_ptr, (ep_ptr->endpoint_type == UCS_RM_EP_SOURCE) ? "Source":"Sink", route_ptr->route_id)); } } /*! \brief Processes the handling of all routes. This method is the callback function of the routing timer * \c route_chek. * \param self Instance pointer */ static void Rtm_ExecRoutesHandling(void* self) { CRouteManagement *self_ = (CRouteManagement *)self; if (!self_->ucs_is_stopping) { bool index_set = Rtm_SetNextRouteIndex(self_); if (index_set) { Srv_SetEvent(&self_->rtm_srv, RTM_EVENT_HANDLE_NEXTROUTE); } else { Srv_SetEvent(&self_->rtm_srv, RTM_EVENT_PROCESS_PAUSE); TR_INFO((self_->base_ptr->ucs_user_ptr, "[RTM]", "Handling process of routes is paused", 0U)); } } else { Rtm_HandleProcessTermination(self_); } } /*! * @} * \endcond */ /*------------------------------------------------------------------------------------------------*/ /* End of file */ /*------------------------------------------------------------------------------------------------*/