Modules

Modules are the building blocks of the firmware image, and where you will be spending the most time. There are a number of Lantronix-provided modules that you can include in your project. This means that your code only needs to take care of what you need to customize, and you don't need to re-create network configuration and management utilities.

The Lantronix modules are provided as binaries in the lantronix/modules directory, while the source examples and your custom modules are in the custom/module directory.

Naming

Directory and file names should not contain spaces or special characters. Do not create or rename a module that conflicts with the name of any Lantronix module. Lantronix modules can be found in lantronix/modules.

Important

Custom module names must not conflict with Lantronix module names.

Don't use these names for custom modules, as they conflict with Lantronix-provided module names:

aes                      azure_iot                ble_beacon_scanner       bluetooth
bridge                   cli                      consoleflow              discovery
gatt_server              lpd                      main                     modbus
modem_emulation          monitor                  mqtt                     mux
ntp                      security                 smtp                     spp
tunnel                   usb_device               usb_host                 user_data
virtual_line             websockets               xnetwork                 xserial

Structure

Modules have the following directory tree and files:

xPortEdge/custom/module/

     > /module_name/
          module_code.c  
          more_module_code.c

          > /bom/
               cfiles.make

          > /includes/
               custom_includes.h

          > /libraries/
               custom_libraries.a

          > /http/help/
               module.module_name.html

The includes, libraries, and http/help directories are optional.

Creating Modules

You have two options when creating modules. You can either copy one of the sample modules and modify it, or you can create a new module from scratch.

Option 1: Copy an existing module

  1. In custom/module, copy a module directory. Take care not to use a name that conflicts with a Lantronix-provided module. See Naming.

  2. Modify the code in the C file(s) or add more C files as needed.

  3. If you change the name of existing C files or add new C files, update the CFILES variable in module_name/bom/cfiles.make to define the C file name(s).

  4. Optionally, create an includes directory. See Includes.

  5. Optionally, create a libraries directory and extend.make. See Libraries.

You should have a File Structure similar to the one outlined above.

Lantronix modules are not designed to work with other Lantronix modules without modification. To use multiple modules correctly, you may need to modify the code.

Option 2: Create a module from scratch

  1. In custom/module, create a directory for the new module. Take care not to use a name that conflicts with a Lantronix-provided module. See Naming.

  2. Create your C file(s) in the new module_name directory.

  3. In module_name, create a bom directory.

  4. In bom, create cfiles.make and define the CFILES variable as the location and name of the C file(s) in module_name.

  5. Optionally, create an includes directory. See Includes.

  6. Optionally, create a libraries directory. See Libraries.

You should have a File Structure similar to the one outlined above.

Registration, Startup, and Shutdown

Each module must provide a registration, startup, and shutdown functions that will be called automatically.

The registration function is module_name_module_registration and should contain all of the module's registration calls.

The startup function is module_name_module_startup. All of the module registration functions are called before any of the startup functions, so at startup all of the registrations from other modules will be visible.

The shutdown function is module_name_module_shutdown. The shutdown function of each module is called just prior to the device powering down.

Includes

There are several Lantronix-provided includes available, and you can create your own. Lantronix includes are located in lantronix/includes. Refer to File List in the Developer Reference for information about includes that are available as part of the SDK.

When creating your own includes, you can either store them within the module that uses them, in custom/module/module_name/includes, or place them in custom/includes to allow multiple modules to make use of the same files.

Required includes

Two includes are required for all modules:

  • module_name_module_defs.h is automatically generated when you run the make command. The name of the include is the module name with "_module_defs.h" appended.

  • ltrx_compile_defines.h is delivered with SDK and is required for all modules.

extend.make

When your module makes use of includes, that module's directory should also include an extend.make file to define where the includes are located. Definemodule_name_INCLUDE_PATHS in the module's extend.make file to specify the paths to the includes used by the module.

Note

Files used in the variable should maintain alphabetical order.

Example:

sample_module_INCLUDE_PATHS := \
$(LANTRONIX_DIRECTORY)/includes/system/sample_feature \

Libraries

There are several Lantronix-provided libraries available, and you can create your own. Lantronix libraries are located in lantronix/libraries. Refer to File List in the Developer Reference for information about libraries that are available as part of the SDK.

When creating your own libraries, you can either store them within the module that uses them, in custom/module/module_name/libraries, or place them in custom/libraries to allow multiple modules to make use of the same files.

extend.make

When your modules make use of libraries, that module's directory should also include an extend.make file to define where libraries are located. Define module_name_LIBRARIES in the module's extend.make file to specify the paths to the libraries used by the module.

Note

Files used in the variable should maintain alphabetical order.

Example:

sample_module_LIBRARIES := $(MY_DIR)/libraries/sample_feature.a \
  $(MY_DIR)/libraries/sample_feature.ThreadX.NetX.ARM_CR4.release.a

Inter-module Communications

The SDK has functionality to allow different modules to communicate via exported functions. To achieve that, one module has to export functions, while another has to import the functions from the exporter.

Note

Modules can both export functions, as well as import functions from another module.

Exporting functions

For a module to export functions, it must define them in the file module_defs.m4d (at the root of the module directory, e.g: <SDK root>/custom/module/<module name>/module_defs.m4d).

The format to export a function is as follows:

define_external_function(
    `output_data',
    `bool',
    `char *data')

Note

  • The opening and closing quotes are different.
  • There must be a newline after the closing parenthesis.
  • The name of the function is the first parameter.
  • The return value of the function is the second parameter.
  • Any parameters passed to the function come third and later.

At compile time, the SDK takes the definitions from module_defs.m4d and creates the function prototypes in a file named <module name>_module_defs.h. For the case above, the exporting module will need to have the following code:

#include "<module name>_module_defs.h"

bool output_data(char *data)
{
  TLOG(TLOG_SEVERITY_LEVEL__INFORMATIONAL, "Sent: %s", data);
  return true;
}

Importing functions

For the module that will be importing functions to call, it must first include the file generated by the SDK named <module name>_module_libs.h. Then, it must populate a pointer named g_<module name>ExternalFunctionEntry_pointer using the ltrx_module_functions_lookup() API. It can then call the functions directly.

If in the example above, the exporting module is named output_tlog, then the importing module will need the following:

#include "output_tlog_module_libs.h"

const struct output_tlog_external_functions *g_output_tlogExternalFunctionEntry_pointer;

g_output_tlogExternalFunctionEntry_pointer = ltrx_module_functions_lookup("output_tlog");

if (g_output_tlogExternalFunctionEntry_pointer == 0)
{
  TLOG(TLOG_SEVERITY_LEVEL__INFORMATIONAL, "Error loading module");
}

Data can be sent by using the following:

output_data(buf);