summaryrefslogtreecommitdiffstats
path: root/mnsl/mnsl.c
blob: 46165a4a960a939d65065b65d197deaebb43e457 (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
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
/*
 * MOST NetServices "Light" V3.2.7.0.1796 MultiInstance Patch
 *
 * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * You may also obtain this software under a propriety license from Microchip.
 * Please contact Microchip for further information.
 *
 */

/* parasoft suppress item * reason "not part of MOST NetServices delivery" */

/*!
 * \file
 * \brief Implementation of MOST NetServices Light
 */

/*------------------------------------------------------------------------------------------------*/
/* Includes                                                                                       */
/*------------------------------------------------------------------------------------------------*/
#include "mns_types_cfg.h"
#include "mnsl.h"
#include "mns_base.h"
#include "mns_misc.h"
#include "mns_pmchannel.h"
#include "mns_ams.h"
#include "mns_transceiver.h"
#include "mns_pmfifos.h"

#include <assert.h> //TKU

/*------------------------------------------------------------------------------------------------*/
/* Internal prototypes                                                                            */
/*------------------------------------------------------------------------------------------------*/
static void Mnsl_OnPmsEvent(void *self, void *event_code);
static void Mnsl_OnServiceRequest(void *self, void *data_ptr);
static void Mnsl_OnGetTickCount(void *self, void *tick_count_value_ptr);
static void Mnsl_OnSetApplicationTimer(void *self, void *new_time_value_ptr);

/*------------------------------------------------------------------------------------------------*/
/* Implementation of class CMnsl                                                                  */
/*------------------------------------------------------------------------------------------------*/
/*! \brief   Assigns default values to a provided MNSL init structure
 *  \param   init_ptr         Reference to MNSL init structure.
 *  \param   enable_watchdog  Set to \c true for normal use. Set to \c false to disable the watchdog 
 *                            supervision for debugging purpose only.
 */
extern void Mnsl_SetDefaultConfig(Mnsl_InitData_t *init_ptr, bool enable_watchdog)
{
    MISC_MEM_SET(init_ptr, 0, sizeof(Mnsl_InitData_t));

    init_ptr->pms.active_fifos = MNSL_FIFOS_MCM_ICM;
    init_ptr->pms.compressed = false;
    
    init_ptr->pms.icm_config.fifo_id = PMP_FIFO_ID_ICM;
    init_ptr->pms.icm_config.tx_wd_timeout = 0U;
    init_ptr->pms.icm_config.tx_wd_timer_value = 0U;
    init_ptr->pms.icm_config.rx_ack_timeout = 10U;
    init_ptr->pms.icm_config.rx_busy_allowed = 0xFU;
    init_ptr->pms.icm_config.rx_credits = PMCH_FIFO_CREDITS;
    init_ptr->pms.icm_config.rx_threshold = PMCH_FIFO_THRESHOLD;

    init_ptr->pms.rcm_config.fifo_id = PMP_FIFO_ID_RCM;
    init_ptr->pms.rcm_config.tx_wd_timeout = 10U;       /* watchdog timeout: 1s */
    init_ptr->pms.rcm_config.tx_wd_timer_value = 600U;  /* watchdog trigger every 600 ms */
    init_ptr->pms.rcm_config.rx_ack_timeout = 10U;
    init_ptr->pms.rcm_config.rx_busy_allowed = 0xFU;
    init_ptr->pms.rcm_config.rx_credits = PMCH_FIFO_CREDITS;
    init_ptr->pms.rcm_config.rx_threshold = PMCH_FIFO_THRESHOLD;

    init_ptr->pms.mcm_config.fifo_id = PMP_FIFO_ID_MCM;
    init_ptr->pms.mcm_config.tx_wd_timeout = 10U;       /* watchdog timeout: 1s */
    init_ptr->pms.mcm_config.tx_wd_timer_value = 600U;  /* watchdog trigger every 600 ms */
    init_ptr->pms.mcm_config.rx_ack_timeout = 10U;
    init_ptr->pms.mcm_config.rx_busy_allowed = 0xFU;
    init_ptr->pms.mcm_config.rx_credits = PMCH_MCM_CREDITS;
    init_ptr->pms.mcm_config.rx_threshold = PMCH_MCM_THRESHOLD;
                                                          
    if (enable_watchdog == false)
    {
        init_ptr->pms.icm_config.rx_ack_timeout = 0U;   /* acknowledge timeout: 0 -> infinite */
        init_ptr->pms.rcm_config.tx_wd_timeout = 0U;    /* watchdog timeout:    0 -> infinite */
        init_ptr->pms.rcm_config.tx_wd_timer_value = 0U;/* watchdog timer:      0 -> no timer */
        init_ptr->pms.rcm_config.rx_ack_timeout = 0U;   /* acknowledge timeout: 0 -> infinite */
        init_ptr->pms.mcm_config.tx_wd_timeout = 0U;    /* watchdog timeout:    0 -> infinite */
        init_ptr->pms.mcm_config.tx_wd_timer_value = 0U;/* watchdog timer:      0 -> no timer */
        init_ptr->pms.mcm_config.rx_ack_timeout = 0U;   /* acknowledge timeout: 0 -> infinite */
    }
}

/*! \brief  Initialize MNS Light class
 *  \param  init_ptr    Reference to the MNSL init structure.
 *                      The memory of the init structure can be freed after the function returns.
 */
void Mnsl_Init(CMnsl *mnsl, Mnsl_InitData_t *init_ptr, void *inst_ptr)
{
    assert(NULL != mnsl);
    CSingleObserver *srv_request_obs_ptr = NULL;
    CSingleObserver *app_timer_obs_ptr = NULL;
    Base_InitData_t base_init_data;
    Pmch_InitData_t pmch_init_data;
    CPmFifo *icm_ptr = NULL;
    CPmFifo *rcm_ptr = NULL;
    CPmFifo *mcm_ptr = NULL;
    CTransceiver *trcv_mcm_ptr = NULL;
    CTransceiver *trcv_rcm_ptr = NULL;

    MISC_MEM_SET(mnsl, 0, sizeof(mnsl));
    MISC_MEM_SET(&base_init_data, 0, sizeof(base_init_data));

    mnsl->inst_ptr = inst_ptr; //TKU
    mnsl->inst_id = 1U;
    mnsl->get_tick_count_fptr = init_ptr->general.get_tickcount_fptr;
    mnsl->srv_request_fptr = init_ptr->general.request_service_fptr;
    mnsl->set_app_timer_fptr = init_ptr->general.set_app_timer_fptr;

    if(mnsl->srv_request_fptr != NULL)
    {
        Sobs_Ctor(&mnsl->srv_request_obs, mnsl, &Mnsl_OnServiceRequest);
        srv_request_obs_ptr = &mnsl->srv_request_obs;
    }
    if (mnsl->set_app_timer_fptr != NULL)
    {
        Sobs_Ctor(&mnsl->set_app_timer_obs, mnsl, &Mnsl_OnSetApplicationTimer);
        app_timer_obs_ptr = &mnsl->set_app_timer_obs;
    }

    base_init_data.mns_inst_id = 1U;
    base_init_data.tm.mns_inst_id = 1U;
    base_init_data.scd.mns_inst_id = 1U;

    Sobs_Ctor(&mnsl->get_tick_count_obs, mnsl, &Mnsl_OnGetTickCount);
    base_init_data.tm.get_tick_count_obs_ptr = &mnsl->get_tick_count_obs;
    base_init_data.scd.service_request_obs_ptr = srv_request_obs_ptr;
    base_init_data.tm.set_application_timer_obs_ptr = app_timer_obs_ptr;

    Base_Ctor(&mnsl->base, &base_init_data);
    
    /* Initialize port message service */
    pmch_init_data.mns_inst_id = 1U;
    pmch_init_data.tx_release_fptr = &Fifo_TxOnRelease;
    pmch_init_data.lld_iface = init_ptr->lld;
    Pmch_Ctor(&mnsl->pm_channel, &pmch_init_data, inst_ptr);

    if((init_ptr->pms.active_fifos & MNSL_FIFOS_ICM) == MNSL_FIFOS_ICM)
    {
        Fifo_InitData_t icm_init;

        icm_init.base_ptr = &mnsl->base;
        icm_init.channel_ptr = &mnsl->pm_channel;
        icm_init.rx_cb_fptr = &Trcv_RxOnMsgComplete;
        icm_init.rx_cb_inst = &mnsl->icm_transceiver;

        if (init_ptr->pms.compressed)
        {
            icm_init.tx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_80);
            icm_init.rx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_80);
        }
        else
        {
            icm_init.tx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_00);
            icm_init.rx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_00);
        }

        Fifo_Ctor(&mnsl->icm_fifo, &icm_init, &init_ptr->pms.icm_config);
        Trcv_Ctor(&mnsl->icm_transceiver, &mnsl->icm_fifo, MSG_ADDR_EHC_CFG, base_init_data.mns_inst_id, PMP_FIFO_ID_ICM);/* initialize ICM transceiver and set link to PMS instance */

        icm_ptr = &mnsl->icm_fifo;
    }

    if((init_ptr->pms.active_fifos & MNSL_FIFOS_RCM) == MNSL_FIFOS_RCM)
        {
        Fifo_InitData_t rcm_init;

        rcm_init.base_ptr = &mnsl->base;
        rcm_init.channel_ptr = &mnsl->pm_channel;
        rcm_init.rx_cb_fptr = &Trcv_RxOnMsgComplete;
        rcm_init.rx_cb_inst = &mnsl->rcm_transceiver;
        rcm_init.tx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_00);
        rcm_init.rx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_00);
        /* Note: RCM compressed data format is not supported */

        Fifo_Ctor(&mnsl->rcm_fifo, &rcm_init, &init_ptr->pms.rcm_config);
        Trcv_Ctor(&mnsl->rcm_transceiver, &mnsl->rcm_fifo, MSG_ADDR_EHC_CFG, base_init_data.mns_inst_id, PMP_FIFO_ID_RCM);/* initialize ICM transceiver and set link to PMS instance */

        rcm_ptr = &mnsl->rcm_fifo;
        trcv_rcm_ptr = &mnsl->rcm_transceiver;
    }

    if((init_ptr->pms.active_fifos & MNSL_FIFOS_MCM) == MNSL_FIFOS_MCM)
    {
        Fifo_InitData_t mcm_init;

        mcm_init.base_ptr = &mnsl->base;
        mcm_init.channel_ptr = &mnsl->pm_channel;
        mcm_init.rx_cb_fptr = &Trcv_RxOnMsgComplete;
        mcm_init.rx_cb_inst = &mnsl->mcm_transceiver;

        if (init_ptr->pms.compressed)
        {
            mcm_init.tx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_81);
            mcm_init.rx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_80);
        }
        else
        {
            mcm_init.tx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_00);
            mcm_init.rx_encoder_ptr = Enc_GetEncoder(ENC_CONTENT_00);
        }

        Fifo_Ctor(&mnsl->mcm_fifo, &mcm_init, &init_ptr->pms.mcm_config);
        Trcv_Ctor(&mnsl->mcm_transceiver, &mnsl->mcm_fifo, MSG_ADDR_EHC_APP, base_init_data.mns_inst_id, PMP_FIFO_ID_MCM);/* initialize ICM transceiver and set link to PMS instance */

        mcm_ptr = &mnsl->mcm_fifo;
        trcv_mcm_ptr = &mnsl->mcm_transceiver;
        }

    if ((trcv_mcm_ptr != NULL) || (trcv_rcm_ptr != NULL))       /* initialize AMS if MCM or RCM is active */
    {
        mnsl->ams_allocator.alloc_fptr = init_ptr->ams.rx_alloc_mem_fptr;
        mnsl->ams_allocator.free_fptr = init_ptr->ams.rx_free_mem_fptr;
        Amsp_Ctor(&mnsl->ams_pool, &mnsl->ams_allocator, mnsl->base.mns_inst_id);
        Ams_Ctor(&mnsl->ams, &mnsl->base, trcv_mcm_ptr, trcv_rcm_ptr, &mnsl->ams_pool, AMS_RX_DEF_SIZE_PAYLOAD);
    }

    /* initialize FIFO handler */
    Fifos_Ctor(&mnsl->fifos, &mnsl->base, &mnsl->pm_channel, icm_ptr, mcm_ptr, rcm_ptr);

    /* register event callback */
    mnsl->event_fptr = init_ptr->general.event_fptr;
    Obs_Ctor(&mnsl->pms_observer, mnsl, &Mnsl_OnPmsEvent);
    Fifos_AddEventObserver(&mnsl->fifos, &mnsl->pms_observer);
}

/*! \brief   Synchronizes the PMS
 *  \details Accordingly MNSL_EVENT_SYNC_COMPLETE or MNSL_EVENT_SYNC_FAILED will be notified.
 */
void Mnsl_Synchronize(CMnsl *mnsl)
{
    assert(NULL != mnsl);
    /* initializes the port message service & LLD interface  */
    Fifos_ConfigureSyncParams(&mnsl->fifos, FIFOS_SYNC_RETRIES, FIFOS_SYNC_TIMEOUT);
    Fifos_Synchronize(&mnsl->fifos, true, true);
}

/*! \brief   Un-synchronizes the PMS
 *  \details Accordingly MNSL_EVENT_UNSYNC_COMPLETE or MNSL_EVENT_UNSYNC_FAILED will be notified.
 *           Calling this function if MNSL is already un-synced will report MNSL_EVENT_UNSYNC_FAILED,
 *           since the low-level driver interface is not active.
 *  \param   initial    MNSL is able to trigger un-synchronization in advance of the initial
 *                      synchronization. In this case, timeouts and retries behave like a synchronization
 *                      and on MNSL_EVENT_UNSYNC_COMPLETE the LLD interface will stay running.
 *                      I.e. if set to \c true the un-synchronization behaves like MNS initial un-synchronization.
 *                      If set to \c false, the un-synchronization behaves like MNS final un-synchronization.
 */
void Mnsl_Unsynchronize(CMnsl *mnsl, bool initial)
{    
    assert(NULL != mnsl);
    if (initial == false)
    {
        Fifos_ConfigureSyncParams(&mnsl->fifos, FIFOS_UNSYNC_RETRIES, FIFOS_UNSYNC_TIMEOUT); /* final sync */
    }
    else
    {
        Fifos_ConfigureSyncParams(&mnsl->fifos, FIFOS_SYNC_RETRIES, FIFOS_SYNC_TIMEOUT); /* initial sync */
    }
    
    Fifos_Unsynchronize(&mnsl->fifos, true, initial);
}

/*! \brief  Handles PMS event and notifies MNSL registered event callback
 *  \param  self         Reference to instance
 *  \param  event_code  Event notified by the PMS
 */
static void Mnsl_OnPmsEvent(void *self, void *event_code)
{
    assert(NULL != self);
    Fifos_Event_t *code = (Fifos_Event_t*)event_code;
    CMnsl *mnsl = (CMnsl *)self;    

    if (mnsl->event_fptr != NULL)
    {
        switch (*code)
        {
            case FIFOS_EV_SYNC_LOST:
                Eh_ReportEvent(&mnsl->base.eh, EH_E_SYNC_LOST);        /* event is necessary for AMS cleanup */
                mnsl->event_fptr(MNSL_EVENT_SYNC_LOST, mnsl->inst_ptr);
                break;
            case FIFOS_EV_SYNC_ESTABLISHED:
                mnsl->event_fptr(MNSL_EVENT_SYNC_COMPLETE, mnsl->inst_ptr);
                break;
            case FIFOS_EV_SYNC_FAILED:
                mnsl->event_fptr(MNSL_EVENT_SYNC_FAILED, mnsl->inst_ptr);
                break;
            case FIFOS_EV_UNSYNC_COMPLETE:
                mnsl->event_fptr(MNSL_EVENT_UNSYNC_COMPLETE, mnsl->inst_ptr);
                Eh_ReportEvent(&mnsl->base.eh, EH_E_UNSYNC_COMPLETE);   /* event is necessary for AMS cleanup */
                break;
            case FIFOS_EV_UNSYNC_FAILED:
                mnsl->event_fptr(MNSL_EVENT_UNSYNC_FAILED, mnsl->inst_ptr);
                Eh_ReportEvent(&mnsl->base.eh, EH_E_UNSYNC_FAILED);    /* event is necessary for AMS cleanup */
                break;
            default:
                break;
        }
    }
}

/*! \brief  Service function of MNS Light
 */
void Mnsl_Service(CMnsl *mnsl)
{
    assert(NULL != mnsl);
    bool pending_events;

    TR_INFO((mnsl->inst_id, "[API]", "Mnsl_Service()", 0U));
    Scd_Service(&mnsl->base.scd);                                                        /* Run the scheduler */
    pending_events = Scd_AreEventsPending(&mnsl->base.scd);                              /* Check if events are still pending? */

    if (pending_events != false)                                                        /* At least one event is pending? */
    {
        TR_INFO((mnsl->inst_id, "[API]", "Mnsl_Service(): events still pending", 0U));
        Mnsl_OnServiceRequest(mnsl, NULL);
    }
    else                                                                                /* No event is pending */
    {
        TR_INFO((mnsl->inst_id, "[API]", "Mnsl_Service(): calling Tm_CheckForNextService()", 0U));
        mnsl->base.scd.scd_srv_is_running = true;                                        /* prevent continuous service requests if no app timer is provided */
        Tm_CheckForNextService(&mnsl->base.tm);                                          /* If MNS timers are running: What is the next time that the timer management must be */
        mnsl->base.scd.scd_srv_is_running = false;                                       /* serviced again? */
    }
}

/*! \brief  Reports that the application provided timer has expired.
 */
void Mnsl_ReportTimeout(CMnsl *mnsl)
{
    assert(NULL != mnsl);
    TR_INFO((mnsl->inst_id, "[API]", "Mns_ReportTimeout()", 0U));
    Tm_TriggerService(&mnsl->base.tm);  /* Trigger TM service call */
}

/*! \brief  Callback function which is invoked by the scheduler
 *  \param self                     Parameter not used with single instance API
 *  \param data_ptr                 Currently unused
 */
static void Mnsl_OnServiceRequest(void *self, void *data_ptr)
{
    assert(NULL != self);
    CMnsl *mnsl = (CMnsl *)self;    
    MISC_UNUSED(data_ptr);

    if (mnsl->srv_request_fptr != NULL)
    {
        TR_INFO((mnsl->inst_id, "[API]", "Mnsl_OnServiceRequest(): calling srv_request_fptr()", 0U));
        mnsl->srv_request_fptr(mnsl->inst_ptr);
    }
}

/*! \brief This function is used in combination with the observer \c mns.get_tick_count_obs
 *         which is used to request the current tick count value form the application.
 *  \param self                     Parameter not used with single instance API
 *  \param tick_count_value_ptr     Reference to the requested tick count value. The pointer must 
 *                                  be casted into data type uint16_t.
 */
static void Mnsl_OnGetTickCount(void *self, void *tick_count_value_ptr)
{
    assert(NULL != self);
    CMnsl *mnsl = (CMnsl *)self;    
    *((uint16_t *)tick_count_value_ptr) = mnsl->get_tick_count_fptr();
}

/*! \brief  Callback function which is invoked to start the application timer when the MNSL service
 *          is implemented event driven         
 *  \param  self                The instance
 *  \param  new_time_value_ptr  Reference to the new timer value. The pointer must be casted into 
 *                              data type uint16_t.
 */
static void Mnsl_OnSetApplicationTimer(void *self, void *new_time_value_ptr)
{
    CMnsl *self_ = (CMnsl*)self;
    TR_INFO((mnsl->inst_id, "[API]", "Mnsl_OnSetApplicationTimer(): set_app_timer_fptr(%d)", 1U, *((uint16_t *)new_time_value_ptr)));
    self_->set_app_timer_fptr(*((uint16_t *)new_time_value_ptr), self_->inst_ptr);
}

/*! \brief  Returns the ICM transceiver object
 *  \return Reference to the ICM transceiver 
 */
CTransceiver * Mnsl_GetIcmTransceiver(CMnsl *mnsl)
{
    return &mnsl->icm_transceiver;
}

/*! \brief  Returns the RCM transceiver object
 *  \return Reference to the RCM transceiver 
 */
CTransceiver * Mnsl_GetRcmTransceiver(CMnsl *mnsl)
{
    return &mnsl->rcm_transceiver;
}

/*! \brief  Returns the MCM transceiver object
 *  \return Reference to the MCM transceiver 
 */
CTransceiver * Mnsl_GetMcmTransceiver(CMnsl *mnsl)
{
    return &mnsl->mcm_transceiver;
}

/*! \brief      Returns the AMS transceiver object
 *  \details    It is important not make usage of competing transceivers
 *              AMS, MCM and RCM. Either use AMS exclusively or MCM and RCM.
 *              Important: Do not use AMS in mode \c MNSL_FIFOS_ICM. 
 *  \return     Reference to the AMS
 */
CAms * Mnsl_GetAmsTransceiver(CMnsl *mnsl)
{
    return &mnsl->ams;
}

/*------------------------------------------------------------------------------------------------*/
/* End of file                                                                                    */
/*------------------------------------------------------------------------------------------------*/