MeshX 0.3
This repository provides an implementation for Bluetooth Low Energy (BLE) Mesh network nodes. The project allows you to create BLE mesh nodes that can communicate with each other, enabling the development of smart home solutions or other IoT-based applications.
Loading...
Searching...
No Matches
meshx.c File Reference

meshX application file for ESP BLE Mesh node. More...

#include "meshx.h"
Include dependency graph for meshx.c:

Go to the source code of this file.

Macros

#define ROOT_ELEMENT_IDX   0
 Defines the index for the root element.
 
#define FRESHBOOT_TIMEOUT_MS   1500
 Defines the timeout duration in milliseconds for a fresh boot.
 

Functions

size_t get_root_sig_models_count (void)
 Returns the count of the root models.
 
size_t get_root_ven_models_count (void)
 Returns the count of the vendor root models.
 
meshx_ptr_t get_root_sig_models (void)
 Returns the root models for BLE Mesh elements.
 
meshx_ptr_t get_root_ven_models (void)
 Returns the root models for BLE Mesh elements.
 
meshx_err_t meshx_create_element_composition (dev_struct_t *p_dev, meshx_config_t const *config)
 Creates the BLE Mesh element composition.
 
static meshx_err_t meshx_element_init (dev_struct_t *p_dev, meshx_config_t const *config)
 Initializes BLE Mesh elements.
 
static meshx_err_t meshx_tasks_init (dev_struct_t *pdev)
 Initializes application tasks.
 
static meshx_err_t meshx_dev_restore (dev_struct_t *pdev, meshx_config_t const *config)
 Restore the device state from the NVS.
 
static meshx_err_t meshx_ble_mesh_init (meshx_config_t *config)
 Initializes the BLE Mesh subsystem.
 
meshx_err_t meshx_init (meshx_config_t const *config)
 MeshX initialisation function.
 

Variables

static const char meshX_banner []
 
static dev_struct_t g_dev
 
static meshx_config_t g_config
 
meshx_prov_params_t g_prov_cfg
 

Detailed Description

meshX application file for ESP BLE Mesh node.

This file contains initialization routines for BLE Mesh provisioning, configuration, and light control servers, as well as the main application entry point.

Author
Pranjal Chanda

Definition in file meshx.c.

Macro Definition Documentation

◆ FRESHBOOT_TIMEOUT_MS

#define FRESHBOOT_TIMEOUT_MS   1500

Defines the timeout duration in milliseconds for a fresh boot.

Definition at line 25 of file meshx.c.

◆ ROOT_ELEMENT_IDX

#define ROOT_ELEMENT_IDX   0

Defines the index for the root element.

Definition at line 19 of file meshx.c.

Function Documentation

◆ get_root_sig_models()

meshx_ptr_t get_root_sig_models ( void )
extern

Returns the root models for BLE Mesh elements.

Returns
Pointer to the root models.

Definition at line 89 of file composition.c.

90{
91 meshx_err_t err;
92 static MESHX_MODEL temp_model;
94 {
96 if(meshx_sig_root_model_arr == NULL)
97 {
98 MESHX_LOGE(MODULE_ID_COMMON, "Failed to allocate memory for root models");
99 return NULL;
100 }
102
103 for(uint16_t i = 0; i < meshx_sig_root_model_arr_len; i++)
104 {
105 if(meshx_sig_root_model_getfn[i] == NULL)
106 {
107 continue;
108 }
109 err = meshx_sig_root_model_getfn[i]((void**)&temp_model);
110 if (err != MESHX_SUCCESS)
111 {
112 MESHX_LOGE(MODULE_ID_COMMON, "Failed to get root model (%p) (%d)", meshx_sig_root_model_getfn[i], err);
113 return NULL;
114 }
115 memcpy(&meshx_sig_root_model_arr[i], &temp_model, sizeof(MESHX_MODEL));
116 }
117 }
119}
static root_model_getfn_t meshx_sig_root_model_getfn[]
Definition composition.c:70
static uint16_t meshx_sig_root_model_arr_len
Definition composition.c:81
static MESHX_MODEL * meshx_sig_root_model_arr
Definition composition.c:64
meshx_err_t
MeshX Error Codes.
Definition meshx_err.h:39
@ MESHX_SUCCESS
Definition meshx_err.h:40
#define MESHX_MALLOC
Definition meshx_err.h:24
#define MESHX_LOGE(module_id, format,...)
Definition meshx_log.h:73
#define MESHX_MODEL
@ MODULE_ID_COMMON
Definition module_id.h:32
Here is the caller graph for this function:

◆ get_root_sig_models_count()

size_t get_root_sig_models_count ( void )
extern

Returns the count of the root models.

Returns
Size of the root models.

Definition at line 156 of file composition.c.

157{
159}
Here is the caller graph for this function:

◆ get_root_ven_models()

meshx_ptr_t get_root_ven_models ( void )
extern

Returns the root models for BLE Mesh elements.

Returns
Pointer to the root models.

Definition at line 126 of file composition.c.

127{
128 static MESHX_MODEL temp_model;
130 {
132 if(meshx_ven_root_model_arr == NULL)
133 {
134 MESHX_LOGE(MODULE_ID_COMMON, "Failed to allocate memory for root models");
135 return NULL;
136 }
138
139 for(uint16_t i = 0; i < meshx_ven_root_model_arr_len; i++)
140 {
141 if(meshx_ven_root_model_getfn[i] == NULL)
142 {
143 continue;
144 }
145 meshx_ven_root_model_getfn[i]((void**)&temp_model);
146 memcpy(&meshx_ven_root_model_arr[i], &temp_model, sizeof(MESHX_MODEL));
147 }
148 }
150}
static uint16_t meshx_ven_root_model_arr_len
Definition composition.c:82
static MESHX_MODEL * meshx_ven_root_model_arr
Definition composition.c:65
static root_model_getfn_t meshx_ven_root_model_getfn[]
Definition composition.c:79

◆ get_root_ven_models_count()

size_t get_root_ven_models_count ( void )
extern

Returns the count of the vendor root models.

Returns
Size of the vendor root models.

Definition at line 166 of file composition.c.

167{
169}
Here is the caller graph for this function:

◆ meshx_ble_mesh_init()

static meshx_err_t meshx_ble_mesh_init ( meshx_config_t * config)
static

Initializes the BLE Mesh subsystem.

This function sets up provisioning, configuration servers, and BLE Mesh stack initialization.

Returns
MESHX_SUCCESS on success, error code otherwise.

Definition at line 194 of file meshx.c.

195{
196 if(config == NULL || config->product_name == NULL)
197 return MESHX_INVALID_ARG;
198
199 meshx_err_t err;
200 g_prov_cfg.node_name = (uint8_t *)config->product_name;
201
203 MESHX_ERR_PRINT_RET("Platform BT init failed", err);
204
205 g_prov_cfg.uuid = config->meshx_uuid_addr;
206 g_prov_cfg.freshboot_timeout_ms = FRESHBOOT_TIMEOUT_MS;
207
208 meshx_dev_restore(&g_dev, config);
209
210 err = meshx_element_init(&g_dev, config);
211 MESHX_ERR_PRINT_RET("Failed to initialize BLE Elements", err);
212
214 MESHX_ERR_PRINT_RET("Failed to initialize provisioning", err);
215
216 err = meshx_plat_ble_mesh_init(&g_prov_cfg, g_dev.composition);
217 MESHX_ERR_PRINT_RET("Failed to initialize BLE Mesh stack", err);
218
219 return MESHX_SUCCESS;
220}
static meshx_err_t meshx_element_init(dev_struct_t *p_dev, meshx_config_t const *config)
Initializes BLE Mesh elements.
Definition meshx.c:78
meshx_prov_params_t g_prov_cfg
Definition meshx.c:59
static meshx_err_t meshx_dev_restore(dev_struct_t *pdev, meshx_config_t const *config)
Restore the device state from the NVS.
Definition meshx.c:174
#define FRESHBOOT_TIMEOUT_MS
Defines the timeout duration in milliseconds for a fresh boot.
Definition meshx.c:25
static dev_struct_t g_dev
Definition meshx.c:55
#define MESHX_ERR_PRINT_RET(_e_str, _err)
Print and return error message if an error occurs.
Definition meshx.h:37
meshx_err_t meshx_platform_bt_init(meshx_uuid_addr_t uuid)
Initializes the Bluetooth subsystem of the MeshX platform.
meshx_err_t meshx_plat_ble_mesh_init(const meshx_prov_params_t *prov_cfg, meshx_ptr_t comp)
Initializes the BLE Mesh stack with the given provisioning parameters.
@ MESHX_INVALID_ARG
Definition meshx_err.h:42
meshx_err_t meshx_init_prov(dev_struct_t *p_dev, const meshx_prov_params_t *prov_cfg)
Initialize provisioning parameters.
meshx_uuid_addr_t meshx_uuid_addr
Definition meshx.h:71
char * product_name
Definition meshx.h:64
Here is the call graph for this function:
Here is the caller graph for this function:

◆ meshx_create_element_composition()

meshx_err_t meshx_create_element_composition ( dev_struct_t * p_dev,
meshx_config_t const * config )
extern

Creates the BLE Mesh element composition.

Initializes the BLE Mesh elements for different configurations like relay servers, relay clients, and CWWW (Cool White and Warm White) servers.

Parameters
[in]p_devPointer to the device structure containing element information.
[in]configPointer to the meshx configuration.
Returns
MESHX_SUCCESS on success, or an error code on failure.

Definition at line 182 of file composition.c.

183{
184#if CONFIG_MAX_ELEMENT_COUNT > 0
185 meshx_err_t err;
186#if CONFIG_SECTION_ENABLE_ELEMENT_TABLE
188#endif /* CONFIG_SECTION_ENABLE_ELEMENT_TABLE */
189 if(!p_dev || !config || !config->element_comp_arr_len || !config->element_comp_arr)
190 return MESHX_INVALID_ARG;
191
193 MESHX_ERR_PRINT_RET("Failed to initialize config server", err);
194 for(uint16_t element_id = 0; element_id < config->element_comp_arr_len; element_id++)
195 {
196#if !CONFIG_SECTION_ENABLE_ELEMENT_TABLE
197 if(config->element_comp_arr[element_id].element_cnt != 0
198 && element_comp_fn[config->element_comp_arr[element_id].type] != NULL)
199 {
200 err = element_comp_fn[config->element_comp_arr[element_id].type](p_dev, config->element_comp_arr[element_id].element_cnt);
201 if(err)
202 {
203 MESHX_LOGE(MODULE_ID_COMMON, "Element composition failed: (%d)", err);
204 return err;
205 }
206 }
207#else
208 element_comp_table = &MESHX_ELEMENT_COMP_TABLE_START;
209 while(element_comp_table < &MESHX_ELEMENT_COMP_TABLE_STOP)
210 {
211 if(element_comp_table->idx == element_id && config->element_comp_arr[element_id].element_cnt != 0)
212 {
213 err = element_comp_table->element_comp_fn(p_dev, config->element_comp_arr[element_id].element_cnt);
214 if(err)
215 {
216 MESHX_LOGE(MODULE_ID_COMMON, "Element composition failed: (%d)", err);
217 return err;
218 }
219 }
221 }
222#endif /* CONFIG_SECTION_ENABLE_ELEMENT_TABLE */
223 }
224#endif /* CONFIG_MAX_ELEMENT_COUNT */
225 return err;
226}
element_comp_fn_t element_comp_fn[MESHX_ELEMENT_TYPE_MAX]
Definition composition.c:46
struct element_comp_table element_comp_table_t
meshx_err_t meshx_init_config_server(void)
Initialize the meshxuction configuration server.
Structure to store element composition functions.
element_comp_fn_t element_comp_fn
Here is the call graph for this function:
Here is the caller graph for this function:

◆ meshx_dev_restore()

static meshx_err_t meshx_dev_restore ( dev_struct_t * pdev,
meshx_config_t const * config )
static

Restore the device state from the NVS.

Parameters
[in]pdevPointer to the device structure.
[in]configPointer to the meshX configuration.
Returns
MESHX_SUCCESS on success, error code otherwise.

Definition at line 174 of file meshx.c.

175{
177
178 err = meshx_nvs_open(config->cid, config->pid, config->meshx_nvs_save_period);
179 MESHX_ERR_PRINT_RET("MeshX NVS Open failed", err);
180
182 MESHX_ERR_PRINT_RET("Failed to restore meshx device state", err);
183
184 return err;
185}
#define MESHX_NVS_STORE
struct meshx_app_store meshx_app_store_t
Structure to store mesh application data.
meshx_err_t meshx_nvs_open(uint16_t cid, uint16_t pid, uint32_t commit_timeout_ms)
Open the NVS with a timeout.
Definition meshx_nvs.c:165
meshx_err_t meshx_nvs_get(char const *key, void *blob, uint16_t blob_size)
Get a value from the NVS.
Definition meshx_nvs.c:346
meshx_app_store_t meshx_store
Here is the call graph for this function:
Here is the caller graph for this function:

◆ meshx_element_init()

static meshx_err_t meshx_element_init ( dev_struct_t * p_dev,
meshx_config_t const * config )
static

Initializes BLE Mesh elements.

Parameters
[in]p_devPointer to the device structure.
[in]configPointer to the meshX configuration.
Returns
MESHX_SUCCESS on success, error code otherwise.

Initialise the root element

Note
We initialise the root element later as root element's models needs to be choosen based on the composition of the other elements

Definition at line 78 of file meshx.c.

79{
80 if (!p_dev)
82
86
88 if (err)
89 {
90 MESHX_LOGE(MODULE_ID_COMMON, "Failed to create platform composition: (%d)", err);
91 return err;
92 }
93
94 /* Start with element index 1 as 0 is root element */
95 p_dev->element_idx = 1;
96
97 err = meshx_create_element_composition(p_dev, config);
98 if(err)
99 {
100 MESHX_LOGE(MODULE_ID_COMMON, "Failed to create BLE Mesh Element Composition: (%d)", err);
101 return err;
102 }
104 p_dev->composition,
105 p_dev->elements,
106 config->cid,
107 config->pid,
108 (uint16_t)p_dev->element_idx
109 );
110 if(err)
111 {
112 MESHX_LOGE(MODULE_ID_COMMON, "Failed to initialise MeshX Composition: (%d)", err);
113 return err;
114 }
115
117 if(meshx_sig_root_model_arr == NULL)
118 {
119 MESHX_LOGE(MODULE_ID_COMMON, "Failed to get root SIG models");
120 return MESHX_FAIL;
121 }
122
130 p_dev->elements,
133 (uint8_t) get_root_sig_models_count(),
134 (uint8_t) get_root_ven_models_count()
135 );
136 if(err)
137 {
138 MESHX_LOGE(MODULE_ID_COMMON, "Failed to add element to composition: (%d)", err);
139 return err;
140 }
141 return MESHX_SUCCESS;
142}
size_t get_root_sig_models_count(void)
Returns the count of the root models.
size_t get_root_ven_models_count(void)
Returns the count of the vendor root models.
#define ROOT_ELEMENT_IDX
Defines the index for the root element.
Definition meshx.c:19
meshx_ptr_t get_root_sig_models(void)
Returns the root models for BLE Mesh elements.
Definition composition.c:89
meshx_err_t meshx_create_element_composition(dev_struct_t *p_dev, meshx_config_t const *config)
Creates the BLE Mesh element composition.
meshx_err_t meshx_plat_add_element_to_composition(uint16_t index, meshx_ptr_t p_element_list, meshx_ptr_t p_sig_models, meshx_ptr_t p_ven_models, uint8_t sig_cnt, uint8_t ven_cnt)
Adds an element to the BLE Mesh composition.
meshx_err_t meshx_create_plat_composition(meshx_ptr_t *p_comp)
Creates a platform-specific BLE Mesh composition object.
meshx_err_t meshx_plat_composition_init(meshx_ptr_t p_composition, meshx_ptr_t p_elements, uint16_t cid, uint16_t pid, uint16_t element_idx)
Initializes a platform-specific BLE Mesh composition.
void * meshx_ptr_t
@ MESHX_FAIL
Definition meshx_err.h:41
@ MESHX_INVALID_STATE
Definition meshx_err.h:45
void * composition
size_t element_idx
MESHX_ELEMENT elements[MAX_ELE_CNT]
Here is the call graph for this function:
Here is the caller graph for this function:

◆ meshx_init()

meshx_err_t meshx_init ( meshx_config_t const * config)

MeshX initialisation function.

This function initialises the MeshX stack with the given configuration.

Parameters
[in]configPointer to the configuration structure
Returns
MESHX_SUCCESS, Success

Definition at line 231 of file meshx.c.

232{
233 /* Check if the configuration is valid */
234 if(!config)
235 return MESHX_INVALID_ARG;
236
238
239 /* Copy the configuration to the global config structure */
240 memcpy(&g_config, config, sizeof(meshx_config_t));
241
242 meshx_logging_t logging_cfg;
243
244 logging_cfg.def_log_level = config->meshx_log_level == MESHX_LOG_VERBOSE ?
245 CONFIG_MESHX_DEFAULT_LOG_LEVEL : config->meshx_log_level;
246
247 err = meshx_logging_init(&logging_cfg);
248 MESHX_ERR_PRINT_RET("Logging init failed", err);
249
250 /* Initialise Platform deps */
251 err = meshx_platform_init();
252 MESHX_ERR_PRINT_RET("Platform init failed", err);
253
254 /* Initialize OS timer */
255 err = meshx_os_timer_init();
256 MESHX_ERR_PRINT_RET("OS Timer Init failed", err);
257
258 /* Initialize MeshX NVS */
259 err = meshx_nvs_init();
260 MESHX_ERR_PRINT_RET("MeshX NVS Init failed", err);
261
262 /* Initialize application tasks */
263 err = meshx_tasks_init(&g_dev);
264 MESHX_ERR_PRINT_RET("Tasks initialization failed", err);
265
266 /* Register application element callback */
267 err = meshx_app_reg_element_callback(g_config.app_element_cb);
268 MESHX_ERR_PRINT_RET("Failed to register app element callback", err);
269
270 /* Register application control callback */
272 MESHX_ERR_PRINT_RET("Failed to register app control callback", err);
273
274 /* Initialize the Bluetooth Mesh Subsystem */
276 MESHX_ERR_PRINT_RET("Bluetooth mesh init failed", err);
277
278 /* Print the MeshX banner */
279 CONFIG_MESHX_LOG_PRINTF(LOG_ANSI_COLOR_REGULAR(LOG_ANSI_COLOR_CYAN) "%s" LOG_ANSI_COLOR_RESET, meshX_banner);
280
281#if CONFIG_ENABLE_UNIT_TEST
282 /* Register unit test command */
283 err = register_ut_command();
284 MESHX_ERR_PRINT_RET("Failed to register unit test command", err);
285
286 /* Initialize unit test console */
288 MESHX_ERR_PRINT_RET("Failed to initialize production console", err);
289#endif /* CONFIG_ENABLE_UNIT_TEST */
290
291 return err;
292}
static meshx_config_t g_config
Definition meshx.c:57
static const char meshX_banner[]
Definition meshx.c:34
static meshx_err_t meshx_tasks_init(dev_struct_t *pdev)
Initializes application tasks.
Definition meshx.c:151
static meshx_err_t meshx_ble_mesh_init(meshx_config_t *config)
Initializes the BLE Mesh subsystem.
Definition meshx.c:194
struct meshx_config meshx_config_t
meshx_err_t meshx_app_reg_element_callback(meshx_app_data_cb_t cb)
Registers the BLE Mesh application callback.
Definition meshx_api.c:148
meshx_err_t meshx_app_reg_system_events_callback(meshx_app_ctrl_cb_t cb)
Registers the BLE Mesh application control callback.
Definition meshx_api.c:176
meshx_err_t meshx_logging_init(const meshx_logging_t *config)
Initializes the MeshX logging system with the provided configuration.
Definition meshx_log.c:61
#define MESHX_LOG_VERBOSE
Definition meshx_log.h:39
#define CONFIG_MESHX_DEFAULT_LOG_LEVEL
Definition meshx_log.h:23
struct meshx_logging meshx_logging_t
#define CONFIG_MESHX_LOG_PRINTF
Macro to define printf function.
Definition meshx_log.h:19
meshx_err_t meshx_nvs_init(void)
MeshX NVS Initialisation.
Definition meshx_nvs.c:135
meshx_err_t meshx_os_timer_init(void)
Initialize the OS timer module.
meshx_err_t meshx_platform_init(void)
Initializes the MeshX platform.
unsigned def_log_level
Definition meshx_log.h:53
meshx_err_t register_ut_command()
Registers the unit test (ut) command with the ESP console.
Definition unit_test.c:81
meshx_err_t init_unit_test_console()
Initialize the production console.
Definition unit_test.c:100
Here is the call graph for this function:
Here is the caller graph for this function:

◆ meshx_tasks_init()

static meshx_err_t meshx_tasks_init ( dev_struct_t * pdev)
static

Initializes application tasks.

Parameters
[in]pdevPointer to the device structure.
Returns
MESHX_SUCCESS on success, error code otherwise.

Definition at line 151 of file meshx.c.

152{
153 meshx_err_t err;
154
155 err = create_control_task(pdev);
156 MESHX_ERR_PRINT_RET("Failed to create control task", err);
157
158#if CONFIG_TXCM_ENABLE
159 err = meshx_txcm_init(pdev);
160 MESHX_ERR_PRINT_RET("Failed to create Tx Control Module", err);
161#endif /* CONFIG_TXCM_ENABLE */
162 return err;
163}
meshx_err_t create_control_task(dev_struct_t *pdev)
Create the control task.
meshx_err_t meshx_txcm_init(dev_struct_t *pdev)
Initializes the MeshX Tx Control Module.
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ g_config

meshx_config_t g_config
static

Definition at line 57 of file meshx.c.

◆ g_dev

dev_struct_t g_dev
static

Definition at line 55 of file meshx.c.

◆ g_prov_cfg

meshx_prov_params_t g_prov_cfg
Initial value:
= {
.uuid = MESHX_UUID_EMPTY,
.node_name = NULL
}
#define MESHX_UUID_EMPTY

Definition at line 59 of file meshx.c.

59 {
60 .uuid = MESHX_UUID_EMPTY,
61 .node_name = NULL
62};

◆ meshX_banner

const char meshX_banner[]
static
Initial value:
= {
"*********************************************************************************************************************\n"
"* MMMMMMMM MMMMMMMM hhhhhhh XXXXXXX XXXXXXX *\n"
"* M:::::::M M:::::::M h:::::h X:::::X X:::::X *\n"
"* M::::::::M M::::::::M h:::::h X:::::X X:::::X *\n"
"* M:::::::::M M:::::::::M h:::::h X::::::X X:::::X *\n"
"* M::::::::::M M::::::::::M eeeeeeeeeeee ssssssssss h:::: hhhhhh XX:::::X X:::::XX *\n"
"* M:::::::::::M M:::::::::::M ee::::::::::::ee ss::::::::::s h::::::::::hhh X:::::X X:::::X *\n"
"* M:::::::M::::M M::::M:::::::M e::::::eeeee:::::eess:::::::::::::s h::::::::::::::hh X:::::X:::::X *\n"
"* M::::::M M::::M M::::M M::::::Me::::::e e:::::es::::::ssss:::::sh:::::::hhh::::::h X:::::::::X *\n"
"* M::::::M M::::M::::M M::::::Me:::::::eeeee::::::e s:::::s ssssss h::::::h h::::::h X:::::::::X *\n"
"* M::::::M M:::::::M M::::::Me:::::::::::::::::e s::::::s h:::::h h:::::h X:::::X:::::X *\n"
"* M::::::M M:::::M M::::::Me::::::eeeeeeeeeee s::::::s h:::::h h:::::h X:::::X X:::::X *\n"
"* M::::::M MMMMM M::::::Me:::::::e ssssss s:::::s h:::::h h:::::h XXX:::::X X:::::XXX *\n"
"* M::::::M M::::::Me::::::::e s:::::ssss::::::sh:::::h h:::::h X::::::X X::::::X *\n"
"* M::::::M M::::::M e::::::::eeeeeeee s::::::::::::::s h:::::h h:::::h X:::::X X:::::X *\n"
"* M::::::M M::::::M ee:::::::::::::e s:::::::::::ss h:::::h h:::::h X:::::X X:::::X *\n"
"* MMMMMMMM MMMMMMMM eeeeeeeeeeeeee sssssssssss hhhhhhh hhhhhhh XXXXXXX XXXXXXX *\n"
"*********************************************************************************************************************\n"
}

A static constant character array that contains the banner information for the MeshX component. This banner is used for display purposes to indicate the presence of the MeshX component in the application.

Definition at line 34 of file meshx.c.

34 {
35"*********************************************************************************************************************\n"
36"* MMMMMMMM MMMMMMMM hhhhhhh XXXXXXX XXXXXXX *\n"
37"* M:::::::M M:::::::M h:::::h X:::::X X:::::X *\n"
38"* M::::::::M M::::::::M h:::::h X:::::X X:::::X *\n"
39"* M:::::::::M M:::::::::M h:::::h X::::::X X:::::X *\n"
40"* M::::::::::M M::::::::::M eeeeeeeeeeee ssssssssss h:::: hhhhhh XX:::::X X:::::XX *\n"
41"* M:::::::::::M M:::::::::::M ee::::::::::::ee ss::::::::::s h::::::::::hhh X:::::X X:::::X *\n"
42"* M:::::::M::::M M::::M:::::::M e::::::eeeee:::::eess:::::::::::::s h::::::::::::::hh X:::::X:::::X *\n"
43"* M::::::M M::::M M::::M M::::::Me::::::e e:::::es::::::ssss:::::sh:::::::hhh::::::h X:::::::::X *\n"
44"* M::::::M M::::M::::M M::::::Me:::::::eeeee::::::e s:::::s ssssss h::::::h h::::::h X:::::::::X *\n"
45"* M::::::M M:::::::M M::::::Me:::::::::::::::::e s::::::s h:::::h h:::::h X:::::X:::::X *\n"
46"* M::::::M M:::::M M::::::Me::::::eeeeeeeeeee s::::::s h:::::h h:::::h X:::::X X:::::X *\n"
47"* M::::::M MMMMM M::::::Me:::::::e ssssss s:::::s h:::::h h:::::h XXX:::::X X:::::XXX *\n"
48"* M::::::M M::::::Me::::::::e s:::::ssss::::::sh:::::h h:::::h X::::::X X::::::X *\n"
49"* M::::::M M::::::M e::::::::eeeeeeee s::::::::::::::s h:::::h h:::::h X:::::X X:::::X *\n"
50"* M::::::M M::::::M ee:::::::::::::e s:::::::::::ss h:::::h h:::::h X:::::X X:::::X *\n"
51"* MMMMMMMM MMMMMMMM eeeeeeeeeeeeee sssssssssss hhhhhhh hhhhhhh XXXXXXX XXXXXXX *\n"
52"*********************************************************************************************************************\n"
53};