RKH
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Shared
rkh_bunner.jpg


Prev: Cross-platform examples

This application deals with the shared resource problem in active object systems. Showing one of the biggest benefit of using active objects: resource encapsulation. The encapsulation naturally designates the owner of the resource as the ultimate arbiter in resolving any contention and potential conflicts for the resource. The shared application is relatively simple and can be tested only with a couple of LEDs on your target board. Still, Shared contains five (5) concurrent active objects that exchange events via direct event posting mechanism. The application uses four timers, as well as dynamic and static events. On the other hand, this application could be used in either preemptive or cooperative enviroment. Aditionally, the Shared could be used to verify a new RKH port.

The platform-independent Shared source code (in C) is located in the <rkh>\demo\cross\shared\ directory, where <rkh> stands for the installation directory chosed to install the accompanying software and client.h, server.h, shared.h, client.c, main.c and server.c are the platform-independent files. Thus, the code is actually identical in all Shared versions, such as the Windows version, S08 version, and so on.


Sequence diagram

The sequence diagram in Figure 1 shows the most representative event exchanges among three Clients (cli0, cli1, cli2) and the Server (svr) active objects.

The server shares their resource with clients. A client does not share any of its resources, but requests a server's content or service function. Clients therefore initiate communication sessions with the server which await incoming requests. The server selectively shares its resource; and a client initiates contact with the server in order to make use of the resource. Clients and server exchange messages in a request-response messaging pattern: The client sends a request, and the server returns a response.

As an additional feature, the Clients can be paused for an arbitrary period of time. During this paused period, the Clients don't get permissions to request. After the pause period, the Clients should resume normal operation.

rkh_shared_sd.png
Figure 1 - Sequence diagram of the Shared application

State machines

Figure 2(a) shows the state machine associated with Client active object, which clearly shows the life cycle consisting of states "cli_idle", "svr_paused", "svr_waiting", and "cli_using". See Client state-machine implementation section.

rkh_shared_svr.png
Figure 2(a) - Server (svr) state machine

Figure 2(b) shows the state machine associated with the Server active object, with "svr_idle", "svr_paused", and "svr_busy" states. See Server state-machine implementation section.

rkh_shared_cli.png
Figure 2b - Client (cli) state machine
Note
The notation of UML Statecharts is not purely visual. Any nontrivial state machine requires a large amount of textual information (e.g., the specification of actions and guards). The exact syntax of action and guard expressions isn’t defined in the UML specification, so many people use either structured English or, more formally, expressions in an implementation language such as C [Douglass]. In practice, this means that UML Statechart notation depends heavily on the specific programming language.

Client state-machine implementation

The client.c file implements the state machine of Client active object, which illustrates some aspects of implementing state machines with RKH framework. Please correlate this implementation with the state diagram shown above. On the other hand, the header file client.h contains the definitions of object structures related to the state machine. See the following sections:

"client.c" - Client active object implementation

/* -------------------------- Development history -------------------------- */
/*
* 2016.03.17 LeFr v1.0.00 Initial version
*/
/* -------------------------------- Authors -------------------------------- */
/*
* LeFr Leandro Francucci francuccilea@gmail.com
*/
/* --------------------------------- Notes --------------------------------- */
/* ----------------------------- Include files ----------------------------- */
#include "rkh.h"
#include "shared.h"
#include "server.h"
#include "client.h"
#include "bsp.h"
/* ----------------------------- Local macros ------------------------------ */
#define CLI_REQ_TIME \
(RKH_TNT_T)RKH_TIME_SEC((bsp_rand() % 5) + 2)
#define CLI_USING_TIME \
(RKH_TNT_T)RKH_TIME_SEC((bsp_rand() % 5) + 1)
/* ......................... Declares active object ........................ */
typedef struct Client Client;
/* ................... Declares states and pseudostates .................... */
RKH_DCLR_BASIC_STATE client_idle, client_waiting, client_using, client_paused;
/* ........................ Declares initial action ........................ */
static void client_init(Client *const me);
/* ........................ Declares effect actions ........................ */
static void client_req(Client *const me, RKH_EVT_T *pe);
static void client_start(Client *const me, RKH_EVT_T *pe);
static void client_end(Client *const me, RKH_EVT_T *pe);
/* ......................... Declares entry actions ........................ */
static void client_delay_req(Client *const me);
static void client_pause(Client *const me);
/* ......................... Declares exit actions ......................... */
static void client_resume(Client *const me);
/* ............................ Declares guards ............................ */
/* ........................ States and pseudostates ........................ */
client_delay_req, NULL, RKH_ROOT, NULL);
RKH_TRREG(TOUT_REQ, NULL, client_req, &client_waiting),
RKH_TRREG(PAUSE, NULL, NULL, &client_paused),
RKH_CREATE_BASIC_STATE(client_waiting, NULL, NULL, RKH_ROOT, NULL);
RKH_CREATE_TRANS_TABLE(client_waiting)
RKH_TRREG(START, NULL, client_start, &client_using),
RKH_CREATE_BASIC_STATE(client_using, NULL, NULL, RKH_ROOT, NULL);
RKH_TRREG(TOUT_USING, NULL, client_end, &client_idle),
RKH_TRREG(PAUSE, NULL, NULL, &client_paused),
RKH_CREATE_BASIC_STATE(client_paused,
client_pause, client_resume, RKH_ROOT, NULL);
RKH_CREATE_TRANS_TABLE(client_paused)
RKH_TRINT(TOUT_USING, NULL, client_end),
RKH_TRREG(PAUSE, NULL, NULL, &client_idle),
/* ............................. Active object ............................. */
struct Client
{
RKH_SMA_T sma; /* base structure */
RKH_TMR_T usageTmr; /* usage time */
RKH_TMR_T waitReqTmr; /* waiting request time */
};
RKH_SMA_CREATE(Client, cli0, CLI_PRIO_0, HCAL, &client_idle, client_init, NULL);
RKH_SMA_CREATE(Client, cli1, CLI_PRIO_1, HCAL, &client_idle, client_init, NULL);
RKH_SMA_CREATE(Client, cli2, CLI_PRIO_2, HCAL, &client_idle, client_init, NULL);
RKH_SMA_CREATE(Client, cli3, CLI_PRIO_3, HCAL, &client_idle, client_init, NULL);
RKH_ARRAY_SMA_CREATE(clis, NUM_CLIENTS)
{
&cli0, &cli1, &cli2, &cli3
};
/* ------------------------------- Constants ------------------------------- */
static RKH_ROM_STATIC_EVENT(evToUse, TOUT_USING);
static RKH_ROM_STATIC_EVENT(evToReq, TOUT_REQ);
static RKH_ROM_STATIC_EVENT(evDone, DONE);
/* ---------------------------- Local data types --------------------------- */
/* ---------------------------- Global variables --------------------------- */
/* ---------------------------- Local variables ---------------------------- */
/* ----------------------- Local function prototypes ----------------------- */
/* ---------------------------- Local functions ---------------------------- */
/* ............................ Initial action ............................. */
static void
client_init(Client *const me)
{
RKH_TR_FWK_STATE(CLI0, &client_idle);
RKH_TR_FWK_STATE(CLI0, &client_waiting);
RKH_TR_FWK_STATE(CLI0, &client_using);
RKH_TR_FWK_STATE(CLI0, &client_paused);
RKH_TMR_INIT(&me->usageTmr, &evToUse, NULL);
RKH_TMR_INIT(&me->waitReqTmr, &evToReq, NULL);
}
/* ............................ Effect actions ............................. */
static void
client_req(Client *const me, RKH_EVT_T *pe)
{
ReqEvt *e_req;
(void)pe;
e_req = RKH_ALLOC_EVT(ReqEvt, REQ);
e_req->clino = RKH_GET_PRIO(me);
RKH_SMA_POST_FIFO(server, RKH_EVT_CAST(e_req), me);
bsp_cli_req(e_req->clino);
}
static void
client_start(Client *const me, RKH_EVT_T *pe)
{
RKH_TNT_T time;
time = CLI_USING_TIME;
RKH_TMR_ONESHOT(&me->usageTmr, RKH_UPCAST(RKH_SMA_T, me), time);
bsp_cli_using(RKH_CAST(StartEvt, pe)->clino,
}
static void
client_end(Client *const me, RKH_EVT_T *pe)
{
(void)pe;
RKH_SMA_POST_FIFO(server, &evDone, me);
bsp_cli_done(RKH_GET_PRIO(me));
}
/* ............................. Entry actions ............................. */
static void
client_pause(Client *const me)
{
rkh_tmr_stop(&me->waitReqTmr);
bsp_cli_paused(RKH_GET_PRIO(me));
}
static void
client_delay_req(Client *const me)
{
RKH_TNT_T time;
time = CLI_REQ_TIME;
RKH_TMR_ONESHOT(&me->waitReqTmr, RKH_UPCAST(RKH_SMA_T, me), time);
bsp_cli_wait_req(RKH_GET_PRIO(me), time / RKH_CFG_FWK_TICK_RATE_HZ);
}
/* ............................. Exit actions .............................. */
static void
client_resume(Client *const me)
{
bsp_cli_resumed(RKH_GET_PRIO(me));
}
/* ................................ Guards ................................. */
/* ---------------------------- Global functions --------------------------- */
/* ------------------------------ End of file ------------------------------ */

Prev: Client state-machine implementation


"client.h" - Client active object specification

/* -------------------------- Development history -------------------------- */
/*
* 2016.03.17 LeFr v1.0.00 Initial version
*/
/* -------------------------------- Authors -------------------------------- */
/*
* LeFr Leandro Francucci francuccilea@gmail.com
*/
/* --------------------------------- Notes --------------------------------- */
/* --------------------------------- Module -------------------------------- */
#ifndef __CLIENT_H__
#define __CLIENT_H__
/* ----------------------------- Include files ----------------------------- */
#include "rkh.h"
#include "shared.h"
/* ---------------------- External C language linkage ---------------------- */
#ifdef __cplusplus
extern "C" {
#endif
/* --------------------------------- Macros -------------------------------- */
#define CLI(clino_) RKH_ARRAY_SMA(clis, clino_)
#define CLI0 CLI(0)
#define CLI1 CLI(1)
#define CLI2 CLI(2)
#define CLI3 CLI(3)
#define CLI_STK_SIZE (512 / sizeof(RKH_THREAD_STK_TYPE))
/* -------------------------------- Constants ------------------------------ */
/* ................................ Signals ................................ */
/* ........................ Declares active object ......................... */
enum
{
CLI_PRIO_0 = 1, CLI_PRIO_1, CLI_PRIO_2, CLI_PRIO_3,
MAX_CLI_PRIO,
NUM_CLIENTS = MAX_CLI_PRIO - 1,
};
RKH_ARRAY_SMA_DCLR(clis, NUM_CLIENTS);
/* ------------------------------- Data types ------------------------------ */
/* -------------------------- External variables --------------------------- */
/* -------------------------- Function prototypes -------------------------- */
/* -------------------- External C language linkage end -------------------- */
#ifdef __cplusplus
}
#endif
/* ------------------------------ Module end ------------------------------- */
#endif
/* ------------------------------ End of file ------------------------------ */

Prev: Client state-machine implementation

Server state-machine implementation

The server.c file implements the state machine of Server active object, which illustrates some aspects of implementing state machines with RKH framework. Please correlate this implementation with the state diagram shown above. On the other hand, the header file svr.h contains the definitions of object structures related to the state machine. See following sections:

  • Server active object implementation - "server.c"
  • Server active object specification - "server.h"

    "server.c" - Server active object implementation
    /* -------------------------- Development history -------------------------- */
    /*
    * 2016.03.17 LeFr v1.0.00 Initial version
    */
    /* -------------------------------- Authors -------------------------------- */
    /*
    * LeFr Leandro Francucci francuccilea@gmail.com
    */
    /* --------------------------------- Notes --------------------------------- */
    /* ----------------------------- Include files ----------------------------- */
    #include "rkh.h"
    #include "bsp.h"
    #include "shared.h"
    #include "server.h"
    /* ----------------------------- Local macros ------------------------------ */
    #define MAX_SIZEOF_QREQ (2 * NUM_CLIENTS)
    /* ......................... Declares active object ........................ */
    typedef struct Server Server;
    /* ................... Declares states and pseudostates .................... */
    RKH_DCLR_BASIC_STATE server_idle, server_busy, server_paused;
    /* ........................ Declares initial action ........................ */
    static void server_init(Server *const me);
    /* ........................ Declares effect actions ........................ */
    static void server_start(Server *const me, RKH_EVT_T *pe);
    static void server_end(Server *const me, RKH_EVT_T *pe);
    static void server_defer(Server *const me, RKH_EVT_T *pe);
    static void server_terminate(Server *const me, RKH_EVT_T *pe);
    /* ......................... Declares entry actions ........................ */
    static void server_pause(Server *const me);
    /* ......................... Declares exit actions ......................... */
    static void server_resume(Server *const me);
    /* ............................ Declares guards ............................ */
    /* ........................ States and pseudostates ........................ */
    RKH_CREATE_BASIC_STATE(server_idle, NULL, NULL, RKH_ROOT, NULL);
    RKH_TRINT(TERM, NULL, server_terminate),
    RKH_TRREG(REQ, NULL, server_start, &server_busy),
    RKH_TRREG(PAUSE, NULL, NULL, &server_paused),
    RKH_CREATE_BASIC_STATE(server_busy, NULL, NULL, RKH_ROOT, NULL);
    RKH_TRINT(REQ, NULL, server_defer),
    RKH_TRINT(TERM, NULL, server_terminate),
    RKH_TRREG(DONE, NULL, server_end, &server_idle),
    RKH_TRREG(PAUSE, NULL, NULL, &server_paused),
    RKH_CREATE_BASIC_STATE(server_paused,
    server_pause, server_resume, RKH_ROOT, NULL);
    RKH_CREATE_TRANS_TABLE(server_paused)
    RKH_TRINT(REQ, NULL, server_defer),
    RKH_TRINT(DONE, NULL, NULL),
    RKH_TRINT(TERM, NULL, server_terminate),
    RKH_TRREG(PAUSE, NULL, NULL, &server_idle),
    /* ............................. Active object ............................. */
    struct Server
    {
    RKH_SMA_T sma; /* base structure */
    rui32_t ntot; /* total number of attended requests */
    /* number of attended requests of every client */
    rui32_t ncr[NUM_CLIENTS];
    };
    RKH_SMA_CREATE(Server, server, 0, HCAL, &server_idle, server_init, NULL);
    /* ------------------------------- Constants ------------------------------- */
    /* ---------------------------- Local data types --------------------------- */
    /* ---------------------------- Global variables --------------------------- */
    /* ---------------------------- Local variables ---------------------------- */
    static RKH_RQ_T queueReq;
    static RKH_EVT_T *queueReqSto[MAX_SIZEOF_QREQ];
    /* ----------------------- Local function prototypes ----------------------- */
    /* ---------------------------- Local functions ---------------------------- */
    /* ............................ Initial action ............................. */
    static void
    server_init(Server *const me)
    {
    rint cn;
    RKH_TR_FWK_AO(server);
    RKH_TR_FWK_STATE(server, &server_idle);
    RKH_TR_FWK_STATE(server, &server_busy);
    RKH_TR_FWK_STATE(server, &server_paused);
    RKH_TR_FWK_SIG(TOUT_USING);
    RKH_TR_FWK_SIG(TOUT_REQ);
    rkh_rq_init(&queueReq, (const void **)queueReqSto, MAX_SIZEOF_QREQ,
    CSMA(0));
    RKH_CAST(Server, me)->ntot = 0;
    for (cn = 0; cn < NUM_CLIENTS; ++cn)
    RKH_CAST(Server, me)->ncr[cn] = 0;
    }
    /* ............................ Effect actions ............................. */
    static void
    server_start(Server *const me, RKH_EVT_T *pe)
    {
    StartEvt *e_start;
    e_start = RKH_ALLOC_EVT(StartEvt, START);
    e_start->clino = RKH_CAST(ReqEvt, pe)->clino;
    RKH_SMA_POST_FIFO(RKH_GET_SMA(RKH_CAST(ReqEvt, pe)->clino),
    RKH_EVT_CAST(e_start), me);
    bsp_svr_start(e_start->clino);
    ++RKH_CAST(Server, me)->ntot;
    ++RKH_CAST(Server, me)->ncr[CLI_ID(e_start->clino)];
    }
    static void
    server_end(Server *const me, RKH_EVT_T *pe)
    {
    ReqEvt *e;
    (void)pe;
    if ((e = (ReqEvt *)rkh_fwk_recall((RKH_SMA_T*)me, &queueReq))
    != (ReqEvt *)0)
    {
    bsp_svr_recall(e->clino);
    }
    bsp_svr_end();
    }
    static void
    server_defer(Server *const me, RKH_EVT_T *pe)
    {
    (void)me;
    rkh_fwk_defer(&queueReq, pe);
    }
    static void
    server_terminate(Server *const me, RKH_EVT_T *pe)
    {
    (void)me;
    (void)pe;
    }
    /* ............................. Entry actions ............................. */
    static void
    server_pause(Server *const me)
    {
    bsp_svr_paused(me->ntot, me->ncr);
    }
    /* ............................. Exit actions .............................. */
    static void
    server_resume(Server *const me)
    {
    ReqEvt *e;
    if ((e = (ReqEvt *)rkh_fwk_recall((RKH_SMA_T*)me, &queueReq))
    != (ReqEvt *)0)
    {
    bsp_svr_recall(e->clino);
    }
    bsp_svr_resume();
    }
    /* ................................ Guards ................................. */
    /* ---------------------------- Global functions --------------------------- */
    /* ------------------------------ End of file ------------------------------ */

Prev: Server state-machine implementation

"server.h" - Server active object specification

/* -------------------------- Development history -------------------------- */
/*
* 2016.03.17 LeFr v1.0.00 Initial version
*/
/* -------------------------------- Authors -------------------------------- */
/*
* LeFr Leandro Francucci francuccilea@gmail.com
*/
/* --------------------------------- Notes --------------------------------- */
/* --------------------------------- Module -------------------------------- */
#ifndef __SERVER_H__
#define __SERVER_H__
/* ----------------------------- Include files ----------------------------- */
#include "rkh.h"
#include "client.h"
/* ---------------------- External C language linkage ---------------------- */
#ifdef __cplusplus
extern "C" {
#endif
/* --------------------------------- Macros -------------------------------- */
#define CLI_ID(cp_) ((cp_) - RKH_GET_PRIO(CLI(0)))
#define SVR_STK_SIZE (512 / sizeof(RKH_THREAD_STK_TYPE))
/* -------------------------------- Constants ------------------------------ */
/* ................................ Signals ................................ */
/* ........................ Declares active object ......................... */
RKH_SMA_DCLR(server);
/* ------------------------------- Data types ------------------------------ */
/* -------------------------- External variables --------------------------- */
/* -------------------------- Function prototypes -------------------------- */
/* -------------------- External C language linkage end -------------------- */
#ifdef __cplusplus
}
#endif
/* ------------------------------ Module end ------------------------------- */
#endif
/* ------------------------------ End of file ------------------------------ */

Prev: Server state-machine implementation


Signals, events, and active objects

In RKH, signals are typically enumerated constants and events with parameters are structures derived from the RKH_EVT_T base structure. The next listing shows signals and events used in the Shared application (shared.h).

"shared.h" - Signals and events

/* -------------------------- Development history -------------------------- */
/*
* 2016.12.15 LeFr v2.4.05 ---
*/
/* -------------------------------- Authors -------------------------------- */
/*
* LeFr Leandro Francucci francuccilea@gmail.com
*/
/* --------------------------------- Notes --------------------------------- */
/* --------------------------------- Module -------------------------------- */
#ifndef __SHARED_H__
#define __SHARED_H__
/* ----------------------------- Include files ----------------------------- */
#include "rkh.h"
/* ---------------------- External C language linkage ---------------------- */
#ifdef __cplusplus
extern "C" {
#endif
/* --------------------------------- Macros -------------------------------- */
/* -------------------------------- Constants ------------------------------ */
/* ------------------------------- Data types ------------------------------ */
/* ................................ Signals ................................ */
typedef enum Signals Signals;
enum Signals
{
REQ, /* client request */
START, /* use server */
DONE, /* release server */
TOUT_REQ, /* timer expired */
TOUT_USING, /* timer expired */
PAUSE, /* press the key 'p' on the keyboard */
TERM /* press the key escape on the keyboard */
};
/* ................................. Events ................................ */
typedef struct
{
rui8_t clino;
} ReqEvt;
typedef struct
{
rui8_t clino;
} StartEvt;
/* -------------------------- External variables --------------------------- */
/* -------------------------- Function prototypes -------------------------- */
/* -------------------- External C language linkage end -------------------- */
#ifdef __cplusplus
}
#endif
/* ------------------------------ Module end ------------------------------- */
#endif
/* ------------------------------ End of file ------------------------------ */



Initializing and starting the application

Most of the system initialization and application startup can be written in a platform-independent way.

"main.c" - main() function

/* -------------------------- Development history -------------------------- */
/*
* 2016.03.17 LeFr v1.0.00 Initial version
*/
/* -------------------------------- Authors -------------------------------- */
/*
* LeFr Leandro Francucci francuccilea@gmail.com
*/
/* --------------------------------- Notes --------------------------------- */
/* ----------------------------- Include files ----------------------------- */
#include "rkh.h"
#include "bsp.h"
#include "server.h"
#include "client.h"
/* ----------------------------- Local macros ------------------------------ */
#define QSTO_SIZE 4
/* ------------------------------- Constants ------------------------------- */
/* ---------------------------- Local data types --------------------------- */
/* ---------------------------- Global variables --------------------------- */
/* ---------------------------- Local variables ---------------------------- */
#if RKH_CFGPORT_SMA_QSTO_EN == RKH_ENABLED
/* Defines the event queue storage for active object 'server' */
static RKH_EVT_T *svr_qsto[QSTO_SIZE];
/* Defines the event queue storage for active object 'client' */
static RKH_EVT_T *cli_qsto[NUM_CLIENTS][QSTO_SIZE];
#else
#define svr_qsto
#define cli_qsto
#endif
#if RKH_CFGPORT_SMA_STK_EN == RKH_ENABLED
/* Defines the task's stack for active object 'server' */
static RKH_THREAD_STK_TYPE svr_stk[SVR_STK_SIZE];
/* Defines the task's stack for active object 'client' */
static RKH_THREAD_STK_TYPE cli_stk[NUM_CLIENTS][CLI_STK_SIZE];
#else
#define svr_stk
#define cli_stk
#endif
/* ----------------------- Local function prototypes ----------------------- */
/* ---------------------------- Local functions ---------------------------- */
/* ---------------------------- Global functions --------------------------- */
int
main(int argc, char *argv[])
{
rint cn;
bsp_init(argc, argv);
RKH_SMA_ACTIVATE(server, svr_qsto, QSTO_SIZE, svr_stk, SVR_STK_SIZE);
for (cn = 0; cn < NUM_CLIENTS; ++cn)
{
RKH_SMA_ACTIVATE(CLI(cn), cli_qsto[cn], QSTO_SIZE, cli_stk[cn],
CLI_STK_SIZE);
}
return 0;
}
/* ------------------------------ End of file ------------------------------ */



Running on various platforms

As said before, the only platform-dependent file is the board support package (BSP) definition. Each of supported platforms defines its own bsp.c and bsp.h files, which are contained in the proper directory, for example, the BSP for the Shared application on Windows 32 (Visual Studio 2008) with a simple cooperative scheduler is located in <rkh>\demo\cross\shared\platform\80x86\win32_st\vc08\

CPU Architecture Manufacturer MCU Evaluation Board Toolchain Comments

Notes

S08 Freescale S08QE128 DEMOQE128 Codewarrior v10.x Native cooperative scheduler

readme

ARM-Cortex Freescale Kinetis K64 FRDM-K64F KDS uC/OS-III on KSDK

readme

Native cooperative scheduler

readme

Kinetis K60 TWR-K60N512 IAR v7.2 uC/OS-III

readme

Native cooperative scheduler

readme

80x86 Visual Studio C++ 2010 Win32 cooperative scheduler simulation

Visual Studio C++ 2010 Win32 multithread

Prev: Cross-platform examples