The Bundle sample demonstrates how to create and manipulate key-value data objects. In this application, a bundle object use example is shown for data exchange through a message port.
The following figure illustrates the main screens of the application.
Figure: Bundle application screens
The sample application provides a user interface for:
- Creating a bundle object: 1 bundle object is created and filled with user-defined key-value pairs.
- Sending a bundle object: the created bundle object is sent through a message port.
The structure of the user interface is depicted in the following figures. EDJE layout scripts are used in the UI.
Figure: Bundle UI layout structure of the data source view
Figure: Bundle UI layout structure of the data sink view
The application workflow can be divided into the following logical pipelines:
- Bundle application startup
- Bundle data creation
- Bundle object sending
- Bundle object receiving
The following figure describes the workflow.
Figure: Bundle application workflow
Implementation
Type Definitions
The main data structure is used as a placeholder for the model and view data:
typedef struct appdata { // View module data viewdata_s view; // Model module data modeldata_s model; } appdata_s;
The viewdata_s structure contains references to all component objects created by the View module:
typedef struct { // The main window object Evas_Object* win; // The conformant object Evas_Object* conform; // The main window's layout object (embedded into the conform component) Evas_Object* layout_main_panel; // The toolbar object (embedded into the PART_MAIN_TOOLBAR part of // the layout_main_panel object) Evas_Object* main_toolbar; // The data source item of the main_toolbar component Elm_Object_Item *main_toolbar_item_data_source; // The data sink item of the main_toolbar component Elm_Object_Item *main_toolbar_item_data_sink; // The data source view layout (embedded into the PART_MAIN_CONTENT part // of the layout_main_panel object) Evas_Object* layout_data_source; // The data source edit panel layout (embedded into the PART_MAIN_CONTENT // part of the layout_main_panel object) Evas_Object* layout_data_source_edit; // The key name entry component (embedded into the PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL_ENTRY // part of the layout_data_source_edit object) Evas_Object* data_source_key_entry; // The value entry component (embedded into the PART_DATA_SOURCE_EDIT_PANEL_VALUE_PANEL_ENTRY // part of the layout_data_source_edit object) Evas_Object* data_source_value_entry; // The value type selector component (embedded into the PART_DATA_SOURCE_EDIT_PANEL_TYPE_PANEL_ENTRY // part of the layout_data_source_edit object) Evas_Object* data_source_type_selector; // The data source list panel layout (embedded into the PART_DATA_SOURCE_LIST_PANEL // part of the layout_data_source object) Evas_Object* layout_data_source_list; // The header inclusion check component (embedded into the PART_DATA_SOURCE_LIST_PANEL_CHECKBOX // part of the layout_data_source_list object) Evas_Object* data_source_checkbox; // The list component (embedded into the PART_DATA_SOURCE_LIST_PANEL_LIST part of the // layout_data_source_list object) Evas_Object* data_source_list; // The data source buttons panel layout (embedded into the PART_DATA_SOURCE_BUTTONS_PANEL // part of the layout_data_source object) Evas_Object* layout_data_source_buttons; // The "Send" button component (embedded into the PART_DATA_SOURCE_BUTTONS_PANEL_SEND // part of the layout_data_source_buttons object) Evas_Object* data_source_button_send; // The "Add" button component (embedded into the PART_DATA_SOURCE_BUTTONS_PANEL_ADD // part of the layout_data_source_buttons object) Evas_Object* data_source_button_add; // The data sink view layout (embedded into the PART_MAIN_CONTENT part of the // layout_main_panel object) Evas_Object* layout_data_sink; // The message entry component (embedded into the PART_DATA_SINK_ENTRY part of the // layout_data_sink object) Evas_Object* sink_entry; } viewdata_s;
The modeldata_s structure contains a list of bundledata_s items, where each of the bundledata_s structures contains data to be included in the bundle object. Additionally, the identifier of the message port for data receiving is declared.
typedef struct _modeldata { // The list that consists of bundledata_s(user input data: key name, value, value type) Eina_List *items_list; // The identifier of the local message port int msg_port_rcv_id; } modeldata_s;
The bundledata_s structure is used as a list item of the modeldata_s->items_list structure:
typedef struct _bundledata { // The key name provided by the user char *key; // The value provided by the user void *value; // The value type selected by the user bundle_value_type_t type; } bundledata_s;
The bundle_value_type_t is an enumeration type:
typedef enum { // Value type of the byte BUNDLE_VALUE_TYPE_BYTE, // Value type of the string BUNDLE_VALUE_TYPE_STRING, // Points to the end of the enumeration type BUNDLE_VALUE_TYPE_MAX } bundle_value_type_t;
Application Initialization
The entire application life-cycle is implemented in the main.c file, using the common Tizen application structure:
int main(int argc, char *argv[]) { appdata_s ad = {{0,},}; // Declare and initialize the variables event_callback.create = app_create; event_callback.terminate = app_terminate; event_callback.pause = app_pause; event_callback.resume = app_resume; event_callback.app_control = app_control; // Assign the event handlers ret = ui_app_main(argc, argv, &event_callback, &ad); // Error handling return ret; }
The Bundle sample application is implemented using the MVC design pattern. Its initialization is done within the app_create() callback function where the controller_initialization() function is responsible for the application initialization. On the application termination, the app_terminate() callback function is called, and all the allocated resources are freed. For reference and more details, see Controller.
static bool app_create(void *data) { // Assign the variables appdata_s *ad = (appdata_s*)data; return controller_initialization(&d->view, &ad->model); } static void app_terminate(void *data) { appdata_s *ad = (appdata_s*)data; controller_terminate(&ad->view, &ad->model); }
View
The entire application layout is implemented using EDJE scripts. All top level swallows are designed for EFL Elementary component embedding. The following EDJE swallow - EFL Elementary component relations and assigned functionalities are used:
- PART_MAIN_TOOLBAR-elm_toolbar: Switches the view between the data source and the data sink.
- PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL_ENTRY-elm_entry: Key name edit field.
- PART_DATA_SOURCE_EDIT_PANEL_VALUE_PANEL_ENTRY-elm_entry: Value edit field.
- PART_DATA_SOURCE_EDIT_PANEL_TYPE_PANEL_ENTRY-elm_spinner: Sets the value type.
- PART_DATA_SOURCE_LIST_PANEL_CHECKBOX-elm_check: Prepends a custom header to the bundle object.
- PART_DATA_SOURCE_LIST_PANEL_LIST-elm_genlist: Displays the list of all key-value pairs to be added to the bundle object.
The list item consists of:
- Key name and value displayed as key: value
- Type of the value displayed as type: type-name
- PART_DATA_SOURCE_BUTTONS_PANEL_ADD-elm_button: Adds a key-value pair to the list.
- PART_DATA_SOURCE_BUTTONS_PANEL_SEND-elm_button: Creates a bundle object and sends it to the data sink.
- PART_DATA_SINK_ENTRY-elm_entry: Displays the received data.
For more information, see also the Bundle UI data source layout structure and Bundle UI data sink layout structure figures.
The following code snippets create the application layout.
Code snippet | Figure |
---|---|
The main layout is defined in the main.edc file. | |
collections { group { name: GROUP_MAIN; parts { // The background part occupies the entire window part { name: PART_MAIN_BACKGROUND; type: RECT; } // The part is positioned in relation to PART_MAIN_BACKGROUND // The spacer occupies the entire area of PART_MAIN_BACKGROUND // with a small margin all around part { name: PART_MAIN_PANEL; type: SPACER; } // The part is positioned in relation to PART_MAIN_PANEL // The swallow occupies 6% of PART_MAIN_PANEL height // It is designed to hold the elm_toolbar component part { name: PART_MAIN_TOOLBAR; type: SWALLOW; } // The part is positioned in relation to PART_MAIN_PANEL // The swallow occupies 93% of PART_MAIN_PANEL height // It is designed to hold the data source/data sink layout part { name: PART_MAIN_CONTENT; type: SWALLOW; } } } } |
|
The PART_MAIN_CONTENT swallow is used as a container for:
The data source and data sink layouts are switched by the toolbar item selection. |
|
collections { group { name: GROUP_DATA_SOURCE; parts { // The part is positioned in relation to PART_MAIN_CONTENT // from the main.edc file // The rect plays a role of the background for the edit panel // and occupies the entire area // of the PART_MAIN_CONTENT part { name: PART_DATA_SOURCE_BACKGROUND; type: RECT; } // The part is positioned in relation to // PART_DATA_SOURCE_BACKGROUND // The swallow part occupies 40% height and 100% width of the // PART_DATA_SOURCE_BACKGROUND // It is designed to hold the data source edit layout defined in // data_source_edit_panel.edc part { name: PART_DATA_SOURCE_EDIT_PANEL; type: SWALLOW; } // The part is positioned in relation to // PART_DATA_SOURCE_BACKGROUND // The swallow part occupies 50% height and 100% width of the // PART_DATA_SOURCE_BACKGROUND // It is designed to hold the data source list layout defined in // data_source_list_panel.edc part { name: PART_DATA_SOURCE_LIST_PANEL; type: SWALLOW; } // The part is positioned in relation to the // PART_DATA_SOURCE_BACKGROUND // The swallow part occupies 10% height and 100% width of the // PART_DATA_SOURCE_BACKGROUND // It is designed to hold the data source buttons layout defined in // data_source_buttons_panel.edc part { name: PART_DATA_SOURCE_BUTTONS_PANEL; type: SWALLOW; } } } } |
|
The PART_DATA_SOURCE_EDIT_PANEL swallow is used as a container for data edit (input) layout defined in the data_source_edit_panel.edc file (for more information, see Data source panel layout). | |
collections { group { name: GROUP_DATA_SOURCE_EDIT_PANEL; parts { // The part is positioned in relation to // PART_DATA_SOURCE_EDIT_PANEL from the data_source.edc file // The rect plays a role of the background for the edit panel // and occupies the entire area // of the PART_DATA_SOURCE_EDIT_PANEL part { name: PART_DATA_SOURCE_EDIT_PANEL_BACKGROUND; type: RECT; } // ----------=============== KEY NAME INPUT PANEL ===============---------- // The part is positioned in relation to // PART_DATA_SOURCE_EDIT_PANEL_BACKGROUND // The swallow part occupies 33% height and 100% width of the // PART_DATA_SOURCE_EDIT_PANEL_BACKGROUND. It is designed to // organize the key name editing area part { name: PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL; type: SPACER; } // The part is positioned in relation to // PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL // The text part occupies 100% height and 33% width of the // PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL // This part is responsible for static text label display // only ("Key name") part { name: "data_source_edit_panel_key_panel_label"; type: TEXT; } // The part is positioned in relation to // PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL // The rect plays a role of a background for the elm_entry // component. Its size is set to // 70% width and 70% height of the // PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL. // This part is vertically aligned part { name: PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL_ENTRY_BACKGROUND; type: RECT; } // The part is positioned in relation to // PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL_ENTRY_BACKGROUND // The swallow part occupies the entire area of the // PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL_ENTRY_BACKGROUND // It is designed to hold elm_entry component for key name input part { name: PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL_ENTRY; type: SWALLOW; } // ----------=============== VALUE INPUT PANEL ===============---------- // The layout of the PART_DATA_SOURCE_EDIT_PANEL_VALUE_PANEL // part is exactly the same as the layout of the // PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL part // The only difference is that its vertical location is set // to the 33% of PART_DATA_SOURCE_EDIT_PANEL_BACKGROUND height // For this reason, the source code is not listed here // ----------=============== VALUE TYPE INPUT PANEL ===============---------- // The layout of the PART_DATA_SOURCE_EDIT_PANEL_TYPE_PANEL part // is exactly the same as the layout of the // PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL part // There are only 2 differences: // 1. Its height is set to 34% of the // PART_DATA_SOURCE_EDIT_PANEL_BACKGROUND height // 2. Its vertical location is set to the 66% of the // PART_DATA_SOURCE_EDIT_PANEL_BACKGROUND height // For this reason, the source code is not listed here } } } |
|
The PART_DATA_SOURCE_LIST_PANEL swallow is used as a container for the data source list layout defined in the data_source_list_panel.edc file (for more information, see Data source panel layout). | |
collections { group { name: GROUP_DATA_SOURCE_LIST_PANEL; parts { // The part is positioned in relation to // PART_DATA_SOURCE_LIST_PANEL from the data_source.edc file // The rect plays a role of the background for the list panel // and occupies the entire area of the // PART_DATA_SOURCE_LIST_PANEL part { name: PART_DATA_SOURCE_LIST_PANEL_BACKGROUND; type: RECT; } // The part is positioned in relation to // PART_DATA_SOURCE_LIST_PANEL_BACKGROUND // The spacer part occupies 15% height and 100% width of the // PART_DATA_SOURCE_LIST_PANEL_BACKGROUND // It is designed to organize bundle header inclusion checkbox area part { name: PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_PANEL; type: SPACER; } // The part is positioned in relation to // PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_PANEL // The rect plays a role of a background for the elm_check component // Its size is set to 9,7% width and 80% height of the // PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_PANEL // This part is vertically aligned. Its horizontal position is // set to 60% width of the // PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_PANEL part { name: PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_BACKGROUND; type: RECT; } // The part is positioned in relation to the // PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_PANEL // The text part occupies 80% height and 60% width of the // PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_PANEL // This part is vertically aligned and is responsible for static // text label display only ("Include bundle header") part { name: PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_LABEL; type: TEXT; } // The part is positioned in relation to // PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_PANEL. // The swallow part occupies 80% height and 40% width of the // PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_PANEL // It is aligned next to the right border of the // PART_DATA_SOURCE_LIST_PANEL_CHECKBOX_LABEL and designed // to hold the elm_check component for bundle header inclusion part { name: PART_DATA_SOURCE_LIST_PANEL_CHECKBOX; type: SWALLOW; } // The part is positioned in relation to // PART_DATA_SOURCE_LIST_PANEL_BACKGROUND // The swallow part occupies 100% width and 85% height of the // PART_DATA_SOURCE_LIST_PANEL_BACKGROUND. It is aligned to the // bottom border of the related part. It is designed to hold // the elm_genlist component for input data display part { name: PART_DATA_SOURCE_LIST_PANEL_LIST; type: SWALLOW; } } } } |
|
The PART_DATA_SOURCE_BUTTONS_PANEL swallow is used as a container for the data source buttons layout defined in the data_source_buttons_panel.edc file (for more information, see Data source panel layout). | |
collections { group { name: GROUP_DATA_SOURCE_BUTTONS_PANEL; parts { // The part is positioned in relation to // PART_DATA_SOURCE_BUTTONS_PANEL from data_source.edc file // The rect plays a role of the background for the buttons // panel and occupies the entire area of the // PART_DATA_SOURCE_BUTTONS_PANEL part { name: PART_DATA_SOURCE_BUTTONS_PANEL_BACKGROUND; type: RECT; } // The part is positioned in relation to // PART_DATA_SOURCE_BUTTONS_PANEL_BACKGROUND // The swallow part occupies 80% height and 46% width of the // PART_DATA_SOURCE_BUTTONS_PANEL_BACKGROUND // Its left border is set to 2% width of related container // Vertically, the swallow is centered // This part is designed to hold the elm_button component for input data // addition to the data list part { name: PART_DATA_SOURCE_BUTTONS_PANEL_ADD; type: SWALLOW; } // The part relations and sizing are the same as described // above, for PART_DATA_SOURCE_BUTTONS_PANEL_ADD part // The only difference is the left border positioning, // which is set to 52% width of the // PART_DATA_SOURCE_BUTTONS_PANEL_BACKGROUND part // This part is designed to hold the elm_button component for bundle // sending part { name: PART_DATA_SOURCE_BUTTONS_PANEL_SEND; type: SWALLOW; } } } } |
|
The PART_MAIN_CONTENT swallow is used as a container for the data sink layout defined in the data_sink.edc file (for more information, see Main panel layout). | |
collections { group { name: GROUP_DATA_SINK; parts { // The part is positioned in relation to PART_MAIN_CONTENT // from main.edc file // The rect plays a role of the background for the entry panel // and occupies the entire area of the PART_MAIN_CONTENT part { name: PART_DATA_SINK_BACKGROUND; type: RECT; } // The part is positioned in relation to // PART_DATA_SINK_BACKGROUND // The swallow part occupies the entire area of // PART_DATA_SINK_BACKGROUND // This part is designed to hold the elm_entry component for // received data display part { name: PART_DATA_SINK_ENTRY; type: SWALLOW; } } } } |
|
Based on the layout defined with EDJE scripts, the application interface is created with the view_base_gui_create() function. The function takes 1 parameter, a pointer to the structure containing the view data. The view_base_gui_create() function is invoked in the controller_initialization() function called from the app_create() callback function. For the call stack details, see Application Initialization. The following code snippet presents the general steps in the user interface creation.
bool view_base_gui_create(viewdata_s *vd) { // The pointer to the viewdata_s structure is stored for future use // The variable viewdata is declared globally in the scope of view.c file viewdata = vd; // Main panel view creation (window, conformant, main layout, toolbar) if (!view_main_panel_create(vd)) { // Error handling } // Data source view creation if (!view_data_source_content_create(vd)) { // Error handling } // Data sink view creation. if (!view_data_sink_content_create(vd)) { // Error handling } // The data source layout object is assigned to the data field of the // "Data source" toolbar's item // This layout object is used in view_toolbar_item_selected_cb() callback // function to switch between the layouts depending on toolbar's item selection elm_object_item_data_set(vd->main_toolbar_item_data_source, (void*)vd->layout_data_source); elm_object_item_data_set(vd->main_toolbar_item_data_sink, (void*)vd->layout_data_sink); // "Data source" tab is marked as selected (the view_toolbar_item_selected_cb() // callback function is not called automatically) elm_toolbar_item_selected_set(vd->main_toolbar_item_data_source, EINA_TRUE); // Set the vd->layout_data_source object as the content of viewdata->layout_main_panel // layout because the view_toolbar_item_selected_cb() callback function is not called // when elm_toolbar_item_selected_set() is invoked elm_object_part_content_set(viewdata->layout_main_panel, PART_MAIN_CONTENT, vd->layout_data_source); evas_object_show(vd->win); return true; }
The entire application view creation is triggered by the view_base_gui_create() function described above. The result of the succeeding subfunction invocations is depicted in the following table.
Description | Code snippet | Figure |
---|---|---|
view_main_panel_create(): The main window and descendant conformant (vd->win and vd->conform respectively) are created and used as a placeholder for the main layout (vd->layout_main_panel). The main layout is created with the view_generic_layout_create_set() function by loading the main group from the EDJE layout (main.edj file), then it is embedded into the vd->layout_main_panel container. Finally, the view_layout_back_cb() callback function is attached to the vd->layout_main_panel for the hardware Back button handling. When the EDJE layout is successfully loaded, the elm_toolbar component can be created as a descendant of the main layout vd->layout_main_panel. At the end, 2 items are appended to the newly created elm_toolbar component with the view_toolbar_item_selected_cb() callback function attached: The view_toolbar_item_selected_cb() callback function is responsible for switching between the layout objects embedded to the PART_MAIN_CONTENT swallow of the vd->layout_main_panel. Those layouts are defined in the data_source.edc and data_sink.edc files. |
static bool view_main_panel_create(viewdata_s *vd) { vd->win = view_generic_window_create(view_win_delete_request_cb); // Error handling vd->conform = view_generic_conformant_create(vd->win); // Error handling vd->layout_main_panel = view_generic_layout_create_set(vd->conform, EDJ_MAIN_FILE_NAME, GROUP_MAIN, NULL); // Error handling eext_object_event_callback_add(vd->layout_main_panel, EEXT_CALLBACK_BACK, view_layout_back_cb, (void*)vd); vd->main_toolbar = view_generic_toolbar_create(vd->layout_main_panel, PART_MAIN_TOOLBAR); // Error handling vd->main_toolbar_item_data_source = elm_toolbar_item_append(vd->main_toolbar, NULL, "Data source", view_toolbar_item_selected_cb, NULL); // Error handling vd->main_toolbar_item_data_sink = elm_toolbar_item_append(vd->main_toolbar, NULL, "Data sink", view_toolbar_item_selected_cb, NULL); // Error handling return true; } |
|
view_data_source_content_create(): The entire data source view is created by the data source layout loading from the data_source.edj file. After the layout is loaded, the following subviews are created:
The final layout is not inserted into the PART_MAIN_CONTENT as this operation is performed later, depending on toolbar item selection. The side figure depicts the vd->layout_data_source layout only. |
static bool view_data_source_content_create(viewdata_s *vd) { vd->layout_data_source = view_generic_layout_create(vd->layout_main_panel, EDJ_DATA_SOURCE_FILE_NAME, GROUP_DATA_SOURCE); // Error handling if (!view_data_source_edit_create(vd)) { return false; } if (!view_data_source_list_create(vd)) { return false; } if (!view_data_source_buttons_create(vd)) { return false; } return true; } |
|
view_data_source_edit_create():
The vd->layout_data_source_edit layout is created based on data_source_edit_panel.edc. The resulting layout is embedded into the PART_DATA_SOURCE_PANEL. The elm_entry and elm_spinner components are created next and inserted into the vd->layout_data_source_edit layout. The newly created components are used for the bundle key name input (value and type, respectively). The elm_spinner component is then filled with the values reflecting all the available types of the key's value. |
static bool view_data_source_edit_create(viewdata_s *vd) { // Error handling vd->layout_data_source_edit = view_generic_layout_create_set(vd->layout_data_source, EDJ_DATA_SOURCE_EDIT_PANEL_FILE_NAME, GROUP_DATA_SOURCE_EDIT_PANEL, PART_DATA_SOURCE_EDIT_PANEL); // Error handling vd->data_source_key_entry = view_generic_entry_create(vd->layout_data_source_edit, PART_DATA_SOURCE_EDIT_PANEL_KEY_PANEL_ENTRY); // Error handling vd->data_source_value_entry = view_generic_entry_create(vd->layout_data_source_edit, PART_DATA_SOURCE_EDIT_PANEL_VALUE_PANEL_ENTRY); // Error handling vd->data_source_type_selector = view_generic_spinner_create(vd->layout_data_source_edit, PART_DATA_SOURCE_EDIT_PANEL_TYPE_PANEL_ENTRY); // Error handling elm_spinner_min_max_set(vd->data_source_type_selector, 0, (int)BUNDLE_VALUE_TYPE_MAX-1); int i; for (i = 0; i < BUNDLE_VALUE_TYPE_MAX; i++) { elm_spinner_special_value_add(vd->data_source_type_selector, i, bundletypes[i].caption); } return true; } |
|
view_data_source_list_create():
The vd->layout_data_source_list layout is created based on data_source_list_panel.edc. The resulting layout is embedded into the PART_DATA_SOURCE_LIST_PANEL. The elm_check and the elm_genlist components are created next and inserted into the vd->layout_data_source_list layout. After the elm_check component is created, the view_checkbox_changed_cb() callback function is assigned to it in order to handle the component's state change event. For the implementation details of the view_checkbox_changed_cb() callback function, see User Interaction. |
static bool view_data_source_list_create(viewdata_s *vd) { // Error handling vd->layout_data_source_list = view_generic_layout_create_set(vd->layout_data_source, EDJ_DATA_SOURCE_LIST_PANEL_FILE_NAME, GROUP_DATA_SOURCE_LIST_PANEL, PART_DATA_SOURCE_LIST_PANEL); // Error handling vd->data_source_checkbox = view_generic_checkbox_create(vd->layout_data_source_list, PART_DATA_SOURCE_LIST_PANEL_CHECKBOX, ""); // Error handling evas_object_smart_callback_add(vd->data_source_checkbox, "changed", view_checkbox_changed_cb, (void*)vd); vd->data_source_list = view_generic_genlist_create(vd->layout_data_source_list, PART_DATA_SOURCE_LIST_PANEL_LIST); // Error handling return true; } |
|
view_data_source_buttons_create():
The vd->layout_data_source_buttons layout is created based on data_source_buttons_panel.edc. The resulting layout is embedded into the PART_DATA_SOURCE_BUTTONS_PANEL. The 2 elm_button components are created next and inserted into the vd->layout_data_source_buttons layout. To each of the buttons created (vd->data_source_button_add, vd->data_source_button_send), the relevant callback function is attached for handling the click event:
For the implementation details of the callback functions, see User Interaction. |
static bool view_data_source_buttons_create(viewdata_s *vd) { // Error handling vd->layout_data_source_buttons = view_generic_layout_create_set(vd->layout_data_source, EDJ_DATA_SOURCE_BUTTONS_PANEL_FILE_NAME, GROUP_DATA_SOURCE_BUTTONS_PANEL, PART_DATA_SOURCE_BUTTONS_PANEL); // Error handling vd->data_source_button_add = view_generic_button_create(vd->layout_data_source_buttons, PART_DATA_SOURCE_BUTTONS_PANEL_ADD, "Add", view_button_add_clicked_cb, (void*)vd); // Error handling vd->data_source_button_send = view_generic_button_create(vd->layout_data_source_buttons, PART_DATA_SOURCE_BUTTONS_PANEL_SEND, "Send", view_button_send_clicked_cb, (void*)vd); // Error handling return true; } |
|
view_data_sink_content_create():
The vd->layout_data_sink layout is created based on data_sink.edc. The resulting layout is embedded into the PART_MAIN_CONTENT. The elm_entry component is created next and inserted into the vd->layout_data_sink layout. The elm_entry component plays the role of a non-editable text panel for the received messages display. |
static bool view_data_sink_content_create(viewdata_s *vd) { vd->layout_data_sink = view_generic_layout_create(vd->layout_main_panel, EDJ_DATA_SINK_FILE_NAME, GROUP_DATA_SINK); // Error handling vd->sink_entry = view_generic_entry_create(vd->layout_data_sink, PART_DATA_SINK_ENTRY); // Error handling elm_entry_single_line_set(vd->sink_entry, EINA_FALSE); elm_entry_editable_set(vd->sink_entry, EINA_FALSE); elm_entry_scrollable_set(vd->sink_entry, EINA_TRUE); return true; } |
|
User Interaction
The interaction between the user and the sample application must follow the following scheme:
- Inputting data (key name, key value) and selecting the data type using the provided components.
- Adding input data to the data list using the Add button. This action can be performed multiple times for different sets of input data.
- Optionally selecting the bundle header for inclusion using the provided check component.
- Bundling the data list and sending it to the data sink through a message port using the Send button.
After the message is successfully sent, the user can switch the view from the data source to the data sink, where the received data is printed in a text form.
Inputting Data and Adding to the List
Input data addition is triggered by the Add button click:
- As a result of the button click, the view_button_add_clicked_cb() callback function is invoked.
static void view_button_add_clicked_cb(void *data, Evas_Object *obj, void *event_info) { viewdata_s *vd = (viewdata_s*)data; bundledata_s *bundledata = NULL; // Error handling // Gather the input data and pack it to the bundledata_s structure if (!view_input_data_to_bundledata(vd, &bundledata)) { return; } // If the bundledata is successfully obtained, it is added to the data list model_list_item_add(bundledata); // Append the bundledata content to the elm_genlist component view_genlist_item_append(bundledata); }
- Within the view_button_add_clicked_cb() callback function, the input data provided by the user is gathered from the UI and packed into the bundledata_s structure (view_input_data_to_bundledata()) which is then added to the data list using the model_list_item_add() function.
For the bundledata_s type specification, see Type Definitions.
static bool view_input_data_to_bundledata(viewdata_s *vd, bundledata_s **bundledata) { // Declare the variables if (!view_input_data_get(vd, &key, &str_value, &value_type)) { return false; } if (view_input_data_value_pointer_get(str_value, value_type, &ptr_value, &val_size)) { *bundledata = model_bundledata_create(key, ptr_value, val_size, value_type); } free(key); free(str_value); return (*bundledata != NULL); }
Within the view_input_data_to_bundledata() function, the view_input_data_get() function acquires all necessary data from the user interface and performs its validation:
static bool view_input_data_get(viewdata_s *vd, char **key, char **value, bundle_value_type_t *value_type) { // Variable declaration, initialization, and error handling *key = view_key_string_get(vd); *value = view_value_string_get(vd); *value_type = (bundle_value_type_t)view_type_index_get(vd); // Check whether acquired data are valid in terms of pointers and value type range correctness ret = (*key && *value && *value_type >= BUNDLE_VALUE_TYPE_BYTE && *value_type < BUNDLE_VALUE_TYPE_MAX); if (!ret) { // Free the memory consumed by *key and *value } return ret; }
Within the view_input_data_to_bundledata() function, the view_input_data_value_pointer_get() function's implementation is also omitted. It converts the str_value string to the relevant data type, based on the value_type set by the user, and assigns it to the provided ptr_value of void* type. The size of the data, referenced by the ptr_value, is returned in the val_size parameter. When all the data (key, value reference, and value type) are successfully acquired, the model_bundledata_create() function is called to create the bundledata_s structure (for implementation details, see Model). Otherwise, the view_input_data_to_bundledata() function fails and frees all previously allocated memory.
After the view_input_data_to_bundledata() function successfully returns and the bundledata_s structure is created, the model_list_item_add() function is invoked (refer to the view_button_add_clicked_cb() callback function) to store the structure for future use in a list of bundledata_s items. For the implementation details of the model_list_item_add() function, see Model.
- The obtained input data is appended to the elm_genlist using the view_genlist_item_append() function.
To access the UI components directly, 3 simple functions are used: view_key_string_get(), view_value_string_get(), view_type_index_get(). Due to the implementation simplicity of the mentioned functions, they are not listed here.
static Elm_Object_Item* view_genlist_item_append(bundledata_s *bundledata) { // Error handling Elm_Genlist_Item_Class* itc = view_generic_genlist_item_class_create(view_genlist_item_label_get_cb, view_genlist_item_del_cb); // Error handling Elm_Object_Item *item = elm_genlist_item_append(viewdata->data_source_list, itc, (void*)bundledata, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); // Error handling elm_genlist_item_bring_in(item, ELM_GENLIST_ITEM_SCROLLTO_TOP); return item; }
The view_generic_genlist_item_class_create() function creates the genlist item class representing the visual style of all the items. The callback functions, passed as parameters (view_genlist_item_label_get_cb() and view_genlist_item_del_cb()), are used to control the display and release of the bundledata attached to the itc using the elm_genlist_item_append() function.
Elm_Genlist_Item_Class* view_generic_genlist_item_class_create(Elm_Genlist_Item_Text_Get_Cb on_text_get_cb, Elm_Genlist_Item_Del_Cb on_item_del_cb) { static Elm_Genlist_Item_Class *itc = NULL; if (!itc) { itc = elm_genlist_item_class_new(); // Error handling itc->item_style = "double_label"; itc->func.text_get = on_text_get_cb; // NULL value assignment to unused itc fields itc->func.del = on_item_del_cb; } return itc; }
Within the view_genlist_item_append() function, the itc class together with the previously created bundledata_s structure are passed as parameters to the elm_genlist_item_append() function. As a result, a new item representing the user input data is appended to the elm_genlist component. The elm_genlist is scrolled so the newly appended item becomes visible (elm_genlist_item_bring_in()).
Including the Bundle Header
The user can add 1 additional key-value pair to the bundle, representing the data header (refer to the Bundle object structure depicted in the Bundle application workflow figure). By checking the Include bundle header checkbox, the elm_genlist component is updated with an additional item. The "real" header is added to the bundle object in the bundle creation phase (see Bundling and Sending the Data List). The Include bundle header checkbox state change results in the view_checkbox_changed_cb() callback function invocation.
Bundling and Sending the Data List
When the user clicks Send, the view_button_send_clicked_cb() callback is triggered and creates the bundle object (with respect to the state of the Include bundle header checkbox). Afterwards, the bundle is sent using a message port.
static void view_button_send_clicked_cb(void *data, Evas_Object *obj, void *event_info) { // Error handling viewdata_s *vd = (viewdata_s*)data; // Obtain the state of the Include bundle header checkbox bool include_header = (bool)elm_check_state_get(vd->data_source_checkbox); // Bundle the bundledata_s structures created earlier and send them using a message port controller_data_source_message_send(include_header); }
For the implementation details of the controller_data_source_message_send() function, see Data Source Controller.
Controller
The general Controller module handles the application initialization and termination procedures. For more information on the invocation context of the functions, see Application Initialization.
The controller_initialization() function handles:
- Model data initialization: model_data_create() (see Model).
- User interface creation: view_base_gui_create() (see View).
- Data sink creation and initialization: controller_data_sink_create() (see Data Sink Controller).
If any of the above functions fail, the controller_initialization() function returns a failure status which closes the application.
bool controller_initialization(viewdata_s *vd, modeldata_s *md) { return (model_data_create(md) && view_base_gui_create(vd) && controller_data_sink_create()); }
When the application is terminated, the controller_terminate() function is called. It is responsible for freeing all the allocated memory, deleting the user interface, and releasing the related resources. For more information about the used functions, see Data Sink Controller, View, and Model.
void controller_terminate(viewdata_s *vd, modeldata_s *md) { controller_data_sink_destroy(); view_base_gui_destroy(vd); model_data_destroy(md); }
Data Source Controller
The data source controller module is responsible for data bundling and sending using a message port. The function triggering the entire process (controller_data_source_message_send()) is referenced in Bundling and Sending the Data List.
- All user input data stored in a list is obtained simply by referencing the Eina_List object, declared in the Model module, in the model_data_list_get() function.
- The empty bundle object is created with the model_bundle_create() function (for reference, see Bundle Model).
- The data addition to the bundle object starts with the controller_data_source_bundle_header_create() function call.
The function adds the HEADER key with 0 or 1 value to the bundle_msg bundle object. The 0 or 1 value is assigned depending on the include_header variable value. If the include_header == 1, the additional HEADER_DATA key is added to the bundle_msg bundle object. The value type of the HEADER_DATA key is an array of strings, where all the cells of the array are filled with key names defined by the user during the data input procedure (for reference, see Inputting Data and Adding to the List).
- To finalize the data addition process, all the user-defined key-value pairs are appended to the bundle object with the controller_data_source_bundle_data_add() function.
- Once the bundle object is successfully created and populated with the data, it is sent through the message port using the model_message_port_message_send() function (for reference, see Message Port Model).
- After the bundle_msg is sent, it is not needed anymore, so it can be deleted with the model_bundle_destroy() function (for reference, see Bundle Model).
bool controller_data_source_message_send(bool include_header) { Eina_List *bundle_data_list = NULL; bundle *bundle_msg = NULL; if (!model_data_list_get(&bundle_data_list)) { return false; } if (!model_bundle_create(&bundle_msg)) { return false; } if (!controller_data_source_bundle_header_create(&bundle_msg, include_header)) { model_bundle_destroy(bundle_msg); return false; } if (!controller_data_source_bundle_data_add(bundle_msg, bundle_data_list)) { model_bundle_destroy(bundle_msg); return false; } bool ret = model_message_port_message_send(bundle_msg); model_bundle_destroy(bundle_msg); return ret; }
The following table shows a bundle object structure preview example. Assume that the bundle contains 3 user-defined keys with the following values:
- Key name: "EX-STR-1", value: "exemplary-string-1", type: string
- Key name: "EX-INT-2", value: 1, type: byte
- Key name: "EX-STR-3", value: "exemplary-string-2", type: string
include_header == 0 | include_header == 1 |
---|---|
HEADER : 0 EX-STR-1 : "exemplary-string-1" EX-INT-2 : 1 EX-STR-3 : "exemplary-string-2" |
HEADER : 1 HEADER_DATA [0] : "EX-STR-1" [1] : "EX-INT-2" [2] : "EX-STR-3" EX-STR-1 : "exemplary-string-1" EX-INT-2 : 1 EX-STR-3 : "exemplary-string-2" |
The call-stack order of the function listing is preserved.
static bool controller_data_source_bundle_header_create(bundle **bundle_obj, bool include_header) { // Declare the variables // Error handling // Add the BUNDLE_HEADER_KEY with assigned value of "include_header" to the bundle object if (!model_bundle_byte_add(bundle_obj, BUNDLE_HEADER_KEY, (int)include_header)) { return false; } // If the user did not include the bundle header, the function returns // Otherwise, the header data is appended if (!include_header) { return true; } // Get all the user-defined key-value pairs in the form of a list containing bundledata_s structures if (!model_data_list_get(&bundle_data_list)) { return false; } items_count = eina_list_count(bundle_data_list); if (items_count == 0) { return true; } // Create the array and fill it with the key names defined by the user key_array = (char**)malloc(sizeof(char*) * items_count); // Error handling EINA_LIST_FOREACH(bundle_data_list, tmp, bundledata) { key_array[i] = strdup(bundledata->key); i++; } // Add the created array of user-defined key names to the bundle object bool ret = model_bundle_string_array_add(bundle_obj, BUNDLE_HEADER_DATA_KEY, key_array, items_count); // Free the key_array's content and the array return ret; } static bool controller_data_source_bundle_data_add(bundle *bundle_obj, Eina_List *bundle_data_list) { // Declare the variables // Error handling // Append each list's item of type bundledata_s to the bundle object EINA_LIST_FOREACH(bundle_data_list, tmp, bundledata) { controller_data_source_bundle_data_append(bundle_obj, bundledata); } return true; } static bool controller_data_source_bundle_data_append(bundle *bundle_obj, bundledata_s *bundledata) { // Error handling // Call the appropriate function depending on the key's value type (byte/string) to // add the key-value pair to the bundle object switch (bundledata->type) { case BUNDLE_VALUE_TYPE_BYTE: if (!model_bundle_byte_add(&bundle_obj, bundledata->key, *((int*)bundledata->value))) { return false; } break; case BUNDLE_VALUE_TYPE_STRING: if (!model_bundle_string_add(&bundle_obj, bundledata->key, (char*)bundledata->value)) { return false; } break; default: // Error handling } return true; }
Data Sink Controller
The data sink controller module is responsible for the initialization and finalization of the communication channel using a message port and receiving messages. The data sink initialization function (controller_data_sink_create()) is invoked from the controller_initialization() function contained in the general Controller module. Similarly, the finalization function (controller_data_sink_destroy()) is called from the controller_terminate() function contained in the same general Controller module.
In the message port initialization procedure, a new communication channel is created with the controller_data_sink_message_received_cb() callback function attached. When a new message arrives, the callback function is invoked and the received data passed in the callback.
To create the data sink:
bool controller_data_sink_create(void) { // Check whether the message port already exists if (model_message_port_exists_check()) { return true; } // Create a new message port if it does not exist yet return model_message_port_create(controller_data_sink_message_received_cb); }
To destroy the data sink and release the resources:
bool controller_data_sink_destroy(void) { // If the message port was never created, there is nothing to do if (!model_message_port_exists_check()) { return true; } // Close the communication channel and the message port return model_message_port_destroy(); }
When a new message arrives through the created message port, the controller_data_sink_message_received_cb() callback function is invoked. The general approach of data extraction from the received bundle object is based on the knowledge about its structure (see the bundle object structure depicted in the Bundle application workflow figure). The workflow can be described with the following steps:
- Get the number of bundled items.
- Get the value of BUNDLE_HEADER_KEY:
- If the value of BUNDLE_HEADER_KEY equals 1, the data header is included and must be extracted using the model_bundle_string_array_get() function. As a result, the string array is returned.
- If the value of BUNDLE_HEADER_KEY equals 0, the data header is not included.
- If the bundle data header exists, it is printed to the data sink view.
- Bundle data enumeration is performed using the model_bundle_foreach() function with the controller_data_sink_bundle_foreach_cb() callback function attached.
For the description of all model-related functions, see Bundle Model.
static void controller_data_sink_message_received_cb(int local_port_id, const char *remote_app_id, const char *remote_port, bool trusted_remote_port, bundle *message, void *user_data) { // Declare the variables // Error handling // Print the initial message to the data sink view // Obtain the number of items contained in received bundle object if (model_bundle_count_get(message, &items_count)) { // Format the text message } // Print the number of bundle items to the data sink view // Get the value of BUNDLE_HEADER_KEY to verify the existence of the data header if (!model_bundle_byte_get(message, BUNDLE_HEADER_KEY, &header_value)) { return; } // Print the message to the data sink view if ((bool)header_value) { // If the data header exists, the strings array value attached to the BUNDLE_HEADER_DATA_KEY is obtained if (!model_bundle_string_array_get(message, BUNDLE_HEADER_DATA_KEY, &header_data, &header_size)) { return; } // All strings contained in the header_data and attached to the BUNDLE_HEADER_DATA_KEY // are enumerated and printed to the data sink view } else { // Print the message to the data sink view } // Print the message to the data sink view // Bundled data item enumeration if (!model_bundle_foreach(message, controller_data_sink_bundle_foreach_cb)) { // Print the message to the data sink view } }
Once the data header is decoded and extracted, the enumeration of data items starts (model_bundle_foreach()). For each bundled item, the controller_data_sink_bundle_foreach_cb() callback function is invoked.
static void controller_data_sink_bundle_foreach_cb(const char *key, const int type, const bundle_keyval_t *kv, void *user_data) { // Declare the variables and initialize // If this callback function is invoked for any of the data header related keys // (BUNDLE_HEADER_KEY, BUNDLE_HEADER_DATA_KEY), the function returns if (controller_same_string_check(key, BUNDLE_HEADER_KEY) || controller_same_string_check(key, BUNDLE_HEADER_DATA_KEY)) { return; } // Get the value's type of the enumerated bundle's item if (model_bundle_keyval_type_get(kv, &value_type)) { // The numeric type code is converted into the string name } // Get the value of the enumerated bundle's item if (model_bundle_keyval_basic_val_get(kv, &value)) { // Format the text message } // Print the message to the data sink view }
The following table shows the text printed to the data sink view in the case shown in Data Source Controller.
include_header == 0 | include_header == 1 |
---|---|
---=== MSG RECEIVED ===--- Bundle items count: 4 Header data: - N/A Data: - EX-STR-1 = exemplary-string-1 (string) - EX-INT-2 = 1 (byte) - EX-STR-3 = exemplary-string-2 (string) |
---=== MSG RECEIVED ===--- Bundle items count: 5 Header data: - Key: EX-STR-1 (string) - Key: EX-INT-2 (byte) - Key: EX-STR-3 (string) Data: - EX-STR-1 = exemplary-string-1 (string) - EX-INT-2 = 1 (byte) - EX-STR-3 = exemplary-string-2 (string) |
Model
The general Model module deals directly with the application data. It is responsible for:
- Model initialization and finalization
- User data list handling
In the initialization step, the model_data_create() function is invoked from the controller_initialization() function. The model_data_destroy() function is called in the application termination phase by the controller_terminate() function. For the call stack reference, see Controller.
To create the model:
bool model_data_create(modeldata_s *md) { // Error handling // The pointer to the modeldata_s structure is locally stored modeldata = md; return true; }
To destroy the model and free the resources:
void model_data_destroy(modeldata_s *md) { // Error handling // Free the content of the input data list if (md->items_list) { md->items_list = eina_list_free(md->items_list); } }
The user input data are added to the list with the model_bundledata_create() function referenced from the view_input_data_to_bundledata() function, which is called by the view_button_add_clicked_cb() callback function on the Add button press. For reference, see Inputting Data and Adding to the List.
bundledata_s* model_bundledata_create(char *key, void *ptr_value, int val_size, bundle_value_type_t value_type) { // Error handling bundledata_s *bundledata = (bundledata_s*)malloc(sizeof(bundledata_s)); // Error handling bundledata->key = strdup(key); bundledata->value = (void*)malloc(val_size); memcpy(bundledata->value, ptr_value, val_size); bundledata->type = value_type; return bundledata; }
Once the user input data structure (bundledata_s described in Type Definitions) is created, it can be added to the list with the model_list_item_add() function and accessed with the model_data_list_get() function. The first function is invoked from the view_button_add_clicked_cb() callback function (see Inputting Data and Adding to the List) and the second one is called during the data bundling and sending procedure (controller_data_source_message_send() referenced in Data Source Controller). The implementation of both functions is very simple and limited to proper Eina_List function invocations. For this reason, they are not listed here.
Bundle Model
The Bundle model module provides a set of wrapper functions for the Bundle API used by the Controller module for the bundle management:
- Creating and removing the bundle object:
bool model_bundle_create(bundle **bundle_obj) { // Create the bundle object *bundle_obj = bundle_create(); // Error handling return true; } bool model_bundle_destroy(bundle *bundle_obj) { // Free the bundle object int ret = bundle_free(bundle_obj); // Error handling return true; }
- Extracting the information on bundled data:
- Number of bundled items:
bool model_bundle_count_get(bundle *bundle_obj, int *count) { // The number of bundled items is acquired if the value returned is non-negative // Otherwise, the error code is returned *count = bundle_get_count(bundle_obj); int ret = get_last_result(); // Error handling return true; }
- Value type:
bool model_bundle_type_get(bundle *bundle_obj, const char *key, int *type) { // The type of the bundled item's value, assigned to the given key, is acquired if the value returned is non-negative // Otherwise, the error code is returned *type = bundle_get_type(bundle_obj, key); int ret = get_last_result(); // Error handling return true; }
- Number of bundled items:
- Adding the data to the bundle with respect to its type:
-
String value:
bool model_bundle_string_add(bundle **bundle_obj, const char *key, const char *value) { // The string value assigned to the given key is added to the bundle int ret = bundle_add_str(*bundle_obj, key, value); // Error handling return true; }
-
Array of string values:
bool model_bundle_string_array_add(bundle **bundle_obj, const char *key, char **value, int value_count) { // Error handling // The array of string values assigned to the given key is added to the bundle int ret = bundle_add_str_array(*bundle_obj, key, (const char**)value, value_count); // Error handling return true; }
-
Numerical value:
bool model_bundle_byte_add(bundle **bundle_obj, const char *key, int value) { // The numerical value assigned to the given key is added to the bundle int ret = bundle_add_byte(*bundle_obj, key, &value, sizeof(value)); // Error handling return true; }
-
- Extracting the bundled data with respect to its type:
-
Retrieve a string value:
bool model_bundle_string_get(bundle *bundle_obj, const char *key, char **value) { *value = NULL; // The string value assigned to the given key is acquired from the bundle int ret = bundle_get_str(bundle_obj, key, value); // Error handling return true; }
-
Retrieve string array values:
bool model_bundle_string_array_get(bundle *bundle_obj, const char *key, const char ***value, int *value_len) { *value_len = 0; // The string array value assigned to the given key is acquired from the bundle *value = bundle_get_str_array(bundle_obj, key, value_len); int ret = get_last_result(); // Error handling return true; }
-
Retrieve a numerical value:
bool model_bundle_byte_get(bundle *bundle_obj, const char *key, int *value) { *value = 0; void *byte_val = NULL; size_t size_val = 0; // The numerical value assigned to the given key is acquired from the bundle in a form of void pointer int ret = bundle_get_byte(bundle_obj, key, &byte_val, &size_val); // Error handling // Returned value referenced by the void pointer is copied to the variable of integer type if (size_val > 0 && size_val <= sizeof(int)) { *value = *((int*)byte_val); } return true; }
-
Retrieve the value type:
bool model_bundle_keyval_type_get(const bundle_keyval_t *kv, int *type) { // The type of the bundled item's value is acquired // This function is used within the callback function invoked by the bundle_foreach() function // If the returned value is non-negative, it points to the value type. Otherwise, the error code is returned *type = bundle_keyval_get_type((bundle_keyval_t*)kv); int ret = get_last_result(); // Error handling return true; }
-
Retrieve the bundled value:
bool model_bundle_keyval_basic_val_get(const bundle_keyval_t *kv, void **value) { size_t value_size = 0; // The bundled value is acquired. This function is used within the callback function invoked by the bundle_foreach() function int ret = bundle_keyval_get_basic_val((bundle_keyval_t*)kv, value, &value_size); // Error handling return true; }
-
- Bundled item enumeration:
bool model_bundle_foreach(bundle *bundle_obj, bundle_iterator_t func_cb) { // Error handling // Bundled items are enumerated and the func_cb callback function is called for each item contained in the bundle bundle_foreach(bundle_obj, func_cb, NULL); return true; }
Message Port Model
The message port model module provides a set of wrapper functions for the Message Port API used by the Data Sink Controller and Data Source Controller modules:
- Create and remove the message port:
bool model_message_port_create(message_port_message_cb func_cb) { // The local message port is registered with a func_cb callback function assigned // The func_cb is called whenever a message is received // If the returned value is non-negative, the message port is created successfully // Otherwise, the ret value points to the error code int ret = message_port_register_local_port(MESSAGE_PORT_RCV_NAME, func_cb, NULL); // Error handling // The identifier of a message port is stored model_data_get()->msg_port_rcv_id = ret; return true; } bool model_message_port_destroy(void) { // The message port is unregistered based on its identifier int ret = message_port_unregister_local_port(model_data_get()->msg_port_rcv_id); // Error handling // The identifier of a message port is cleared model_data_get()->msg_port_rcv_id = 0; return true; }
- Check the message port existence:
bool model_message_port_exists_check(void) { // Check whether the message port identifier is non-negative // If so, the message port exists return (model_data_get()->msg_port_rcv_id > 0); }
- Send the bundle object:
bool model_message_port_message_send(bundle *message) { // The bundled message is sent over the message port previously created int ret = message_port_send_message(PACKAGE, MESSAGE_PORT_RCV_NAME, message); // Error handling return true; }