This page shows how to add the MtFmt library to your project.

1 Download

A simple way to download source files is that click here. It will download the zip file from the main branch of the GitHub repository. The other way is to install git and run the following command in your terminal, which is suitable for the professional developer.

git clone --depth=1 git@github.com:MtFmT-Lib/mtfmt.git
# or: https://github.com/MtFmT-Lib/mtfmt.git if you have not ssh key

You can add it to the git submodule also.

git submodule add git@github.com:MtFmT-Lib/mtfmt.git

2 Add to project

The two folders should be included in the archive file. The src folder including C source files is all implementations. And, the inc folder includes C header files and C++ wrapper header files. A reasonable approach is to create a new folder to contain the inc and the src directories and copy that into your project directory.

2.1 Keil IDE

Using the middleware package is an easy way to add to the Keil IDE. You can find them here. Alternatively, you can manually add the sources and configure the including path.

2.1.1 Using the package

The middleware package was auto-generated by GitHub action. Found that and make sure the branch is master. In your IDE, open the package installer.

Figure 2.1: Click this button to open the package installerFigure 2.1: Click this button to open the package installer

Then import the download files manually. The package file has the .pack extension name.

Figure 2.2: Import package fileFigure 2.2: Import package file

After that, we can find the mtfmt package in the package list.

Figure 2.3: The package itemFigure 2.3: The package item

Now open your project and click the "Manage Run-time Environment" button.

Figure 2.4: The options managerFigure 2.4: The options manager

And found the mtfmt package in the Utility item. Click the check box and you add the library succeeded. Go to the next section to see how to customize the library.

Figure 2.5: The envorimentFigure 2.5: The envoriment

2.1.2 Add sources manually

Firstly, download the library sources and select the "Add existing file to Source Group" option like in Figure 2.6.

Figure 2.6: Add existing file menu itemFigure 2.6: Add existing file menu item

Then, add all files in the folder src into your project.

Figure 2.7: Add existing file to source groupFigure 2.7: Add existing file to source group

Now you add all source files succeeded. The next step is that add the including directory. The preprocessor must know where the file locates in that the preprocessor of the C compiler will copy the header into the source file simply. To add that to the project, click the "Options for Target" button in the toolbar.

Figure 2.8: The project options button Figure 2.8: The project options button

Then find the "C/C++" tab and click the "..." button on the right side of the edit box.

Figure 2.9: Including path in keilFigure 2.9: Including path in keil

And select the inc folder in the dialog.

Figure 2.10: Add an including path itemFigure 2.10: Add an including path item

Finally, we must set the C99 standard.

Figure 2.11: Select C99 standardFigure 2.11: Select C99 standard

Now you completed this section! Click the "Build" button or press the F7 key to build your project and check the output has not any errors. Then, you can go to the next section!

2.2 CMake

The archive includes the CMake file. Using the git submodule is a good choice if you use that version control system. Section 1 shows how to add the library by git submodule. Otherwise, copy the file to a suitable directory first.

Then, append the following to your CMakeLists.txt. That adds the library directory to the build. See more details in the CMake document

# assume that you copy all files into "./mtfmt"
add_subdirectory(mtfmt)

Finally, add the including path manually because the add_​subdirectory command only appends a subdirectory to the build.

target_include_directories(your_target PRIVATE "./mtfmt/inc")

Now you completed this section. Go to the next section!

2.3 Others

TODO

3 Customization

The microcontroller has a different instruction set such as ARM v6m or ARM v7m. The instruction set includes different data processing instructions and architecture memory models. And for the microprocessor unit, or MPU that runs an operating system usually. The MtFmt library provides a series of macros for conditional compilation, that makes it possible to control the final generated instructions, control memory allocators, and so on.

3.1 Optional features

The following table 3.1 shows all available macros.

Table 3.1 available macros

Macros Default Description
_​MSTR_​USE_​HARDWARE_​DIV 0 Enable to use hardware divider operator.
_​MSTR_​USE_​MALLOC 0 Enable to use malloc instead build-in heap manager.
_​MSTR_​RUNTIME_​HEAP_​ALIGN 4 Specify the alignment of build-in heap manager.
_​MSTR_​USE_​STD_​IO 0 Enable to use stdout support.
_​MSTR_​USE_​UTF_​8 1 Enable the UTF-8 support.

Define the macro equal to 1 to enable it. Otherwise, the value is not equal to 1 or the macro is undefined means disabling it.

Notes: UTF-8 Encoding

In the C and the C++ programming language, the UTF-8 literal string includes the prefix u8 such as u8"UTF-8". The minimum support version is C11 and C++11. The literal string such as "中文" or "😊" is not a UTF-8 encoding string. Normally, the string encoding will follow your system. For example, the Chinese string will be compiled into GB-2312 encoding and it will cause an MStr_​Err_​UnicodeEncodingError when you enable UTF-8 support.

3.2 Usage examples

TODO

4 Cooperate with RTOS

Data synchronization is very important in the multi-threading or multi-task system. The built-in memory manager has no data synchronization. That means you cannot use that in those situations. Instead using the OS API to replace the built-in memory manager. It is recommended to follow the following guidelines.

  • NO-OS: using the built-in heap manager. No changes are required.
  • RTOS: using the memory manager API provided by OS. See more details in section 4.2.
  • Others(Linux, Windows, etc.): using the language standard library. See more details in section 4.1.

4.1 Using language supports

The C standard library provides the heap manager function. Enable the macro _​MSTR_​USE_​MALLOC to use the malloc and the free function instead built-in heap manager. Go to the next section!

4.2 Using memory management API

Many RTOS like FreeRTOS or µC/OS provides a thread-safe or task-safe memory manager. To replace the build-in heap manager with that, enable the macro _​MSTR_​USE_​MALLOC first and find ./inc/mm_​cfg.h. The _​MSTR_​MEM_​ALLOC_​FUNCTION macro specifies the allocating memory function and holds the same type $\text{size_t}\rightarrow\text{void}$ of malloc in the C standard library. Likewise, the _​MSTR_​MEM_​FREE_​FUNCTION macro specifies the releasing memory function and holds the same type $\text{void}\rightarrow\text{void}$ of free. By default, those macros will be defined as follows.

#define _MSTR_MEM_ALLOC_FUNCTION(s) malloc(s)
#define _MSTR_MEM_FREE_FUNCTION(s)  free(s)

Adding those macros to the file ./inc/mm_​cfg.h will replace the default implementation.

#if !defined(_INCLUDE_MM_CFG_H_)
#define _INCLUDE_MM_CFG_H_
#include <stdint.h>
// add the macro definitions to here or #include "your_configure.h"
...
#endif // _INCLUDE_MM_CFG_H_

4.2.1 FreeRTOS

The FreeRTOS provides five different memory manager tactics which can be found here. The pvPortMalloc function is the instead version of malloc and the vPortFree function is the instead version of free. They have the same signature as the standard library function. So we can replace the function symbol directly as follows.

// #include "freertos.h"
#define _MSTR_MEM_ALLOC_FUNCTION(s) pvPortMalloc(s)
#define _MSTR_MEM_FREE_FUNCTION(s)  vPortFree(s)

You can go to section 5 to view the demo.

4.2.2 µC/OS

The μC/OS provides API which can be found here is not the same as the standard library function and is a block allocator. That means we must write two helper functions in a standard C source file and then add them into mm_​cfg.h.

The function requires a parameter pmem to specify the list of free memory control blocks. A simple way is that export your free memory control block variable to the global namespace. And then create that with a block size of 64 bytes at least. Finally, create a C source file, the source code may seem like the following.

// #include "ucos.h"
// #include "mm_cfg.h"
// your global memory block
extern OS_MEM* mtfmt_mem;
// create that:
// OS_MEM *mtfmt_mem;
// INT8U  mtfmt_mem_block[8][64];
// INT8U err;
// mtfmt_mem = OSMemCreate(mtfmt_mem_block, 8, 64, &err);
void* wrap_ucos_mget(size_t sz) {
    (void)sz;
    uint8_t err = OS_NO_ERR;
    void* pblock = OSMemGet(mtfmt_mem, &err);
    if (err != OS_NO_ERR) {
        return NULL;
    } else {
        return pblock;
    }
}
void wrap_ucos_mfree(void* pblock) {
    (void)OSMemPut(mtfmt_mem, pblock);
}

Normally, the memory usage is very small for the value formatting. The except situation is string formatting, for the $L$ bytes string formatting the library will use $2L$ bytes memory. Finally, append those macros and two function prototypes into mm_​cfg.h.

extern void* wrap_ucos_mget(size_t sz);
extern void wrap_ucos_mfree(void* pblock);
#define _MSTR_MEM_ALLOC_FUNCTION(s) wrap_ucos_mget(s)
#define _MSTR_MEM_FREE_FUNCTION(s)  wrap_ucos_mfree(s)

You can go to section 5 now.

4.2.3 RT-Thread

The RT-Thread provides API is the same signature as the standard library which can be found here. So we can replace the function symbol directly as follows.

// #include "rtthread.h"
#define _MSTR_MEM_ALLOC_FUNCTION(s) rt_malloc(s)
#define _MSTR_MEM_FREE_FUNCTION(s)  rt_free(s)

You can go to section 5 to view the demo.

4.2.4 Others

For the other operating system, make sure functions have the same signature as the malloc and free functions. If the signature is different, you should implement a wrapper function like section 4.2.2. Finally, append those macros as follows.

#define _MSTR_MEM_ALLOC_FUNCTION(s) your_mem_alloc(s)
#define _MSTR_MEM_FREE_FUNCTION(s)  your_mem_free(s)

5 A simple demo

TODO