Logo
UNICENS V2.1.0-3491
User Manual and API Reference
Service

Initialization and Service

In order to initialize the UNICENS library the application shall call Ucs_SetDefaultConfig(), modify the initialization structure and call Ucs_Init().

After calling Ucs_Init() the application is allowed to call the Basic API functions of the UNICENS library. The Basic API functions are required to drive the API. It is responsible to update timers and process internal events. The following functions are Basic API functions:

When the Ucs_Init() result callback notifies UCS_INIT_RES_SUCCESS, then the application is allowed to call the Basic API and all other API functions. After the UNICENS API notifies termination the application shall not call any API function but restart from scratch if required.

The following events will terminate the UNICENS API:

Main Loop Service

The most easiest and robust way of driving the UNICENS library is to call Ucs_Init() to initialize the API and call Ucs_Service() as long as the UNICENS library is running. If Ucs_Service() does not require to process internal events it returns and will consume few CPU load.

int main(void)
{
bool running = true;
/* ... <- modify initialization structure here */
Ucs_Init(/*...*/);
while (running)
{
}
return 0;
}
Attention
The initialization function Ucs_Init() must be called before the first execution of Ucs_Service().

The UNICENS library can deal also with delays of 10 milliseconds or more between two calls of Ucs_Service(). Although, the UNICENS library can reach high performance results (for delays <= 10ms). However, depending on the LLD and system design the use of delays between two Ucs_Service() calls will mean that an application may also increase the number of LLD Tx and Rx buffer for the communication with the INIC. It is recommended to run individual tests with high and low message load to find a balanced setup.

A good compromise to balance a system can be the following approach:

Event Driven Service

A more efficient way of driving the UNICENS library is the Event Driven Service. In this mode the UNICENS library signals to the application when the next Service or Timer must be processed. Hence, the application can invoke the UNICENS API only if required. This decreases the CPU usage of UNICENS library to a minimum.

In order to run the Event Driven Service mode of the UNICENS library, the application must assign the following two callback functions in the initialization structure: general.request_service_fptr() and general.set_application_timer_fptr(). It is required that the application assigns both events callback functions. Otherwise, Ucs_Init() will return UCS_RET_ERR_PARAM.

A small example for Event Driven Service is printed below.

static bool event_timeout = false;
static bool event_service = false;
int main(void)
{
bool running = false;
Ucs_InitData_t init_data;
Ucs_SetDefaultConfig(&init_data); /* assign default configuration */
init_data.general.request_service_fptr = &App_OnServiceRequest; /* assign SERVICE event callback functions */
init_data.general.set_application_timer_fptr = &App_OnSetAppTimer; /* assign TIMER event callback function */
init_data.general.get_tick_count_fptr = App_OnGetTickCount; /* tick count requires the same timer
reference/resolution as the application timer
*/
/* .. further initialization .. */
if (Ucs_init(&init_data) == UCS_RET_ERR_SUCCESS)
{
running = true;
}
while (running)
{
Os_WaitForEvent(); /* stop until event occurs */
if (event_timeout != false)
{
event_timeout = false;
}
if(event_service != false)
{
event_service = false;
}
}
return 0;
}

The implementation of the callback function App_OnServiceRequest() should be rather simply. It must wakeup the process and signal that Ucs_Service() must be called.

void App_OnServiceRequest(void)
{
event_service = true;
Os_SignalEvent(); /* wakeup process */
}
Note
During high message load the UNICENS library might also fire a high number of service request events in a short term. Consider that processing UNICENS library events might be at other processes expense. Therefore, balance your system also for high load scenario. During high message load it is acceptable to call Ucs_Service() in lower frequency than the service request event is fired by the UNICENS library.

The implementation of the callback function App_OnSetAppTimer() must consider some particularities.

  • The function is called to start or stop exactly one reference timer. This timer is the smallest timeout value handled by the UNICENS library. During runtime it is possible that internal timers are started or stopped. Hence, it is possible that the UNICENS library stops or restarts the reference timer with a new value before a previously started timer expires.
  • When the function is called and parameter timeout is "0", the application has to stop the reference timer.
  • When the function is called and parameter timeout is ">0", the application has to stop the reference timer and restart it with the new value.
  • It is important that general.set_application_timer_fptr() and general.get_tick_count_fptr() are using the same time reference and precision. Otherwise, a tick count with another precision might induce the UNICENS library to start again a timer with a small difference in timeout.
UINT timer_id = 0U;
void CALLBACK App_TimerCb (UINT uTimerID,
UINT uMsg,
DWORD_PTR dwUser,
DWORD_PTR dw1,
DWORD_PTR dw2)
{
timer_id = 0U; /* mark timer as stopped */
event_timeout = true;
Os_SignalEvent(); /* wakeup process */
}
void App_OnSetAppTimer(uint16_t timeout)
{
if (timer_id != 0U) /* stop reference timer if it is still running */
{
(void)timeKillEvent(timer_id);
timer_id = 0U;
}
if (timeout != 0U) /* start reference timer with the given timeout value */
{
timer_id = timeSetEvent((UINT)timeout,
(UINT)1,
&App_TimerCb,
(DWORD_PTR)0,
(UINT)TIME_ONESHOT);
}
}
uint16_t App_OnGetTickCount(void)
{
return (uint16_t)timeGetTime(); /* retrieve current tick count */
}