Difference between revisions of "Program Examples:Shared Objects"
(Added link to newer compiler for 301.2 and 302) |
|||
(61 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
+ | {{Languages|Program_Examples:Shared_Objects}} | ||
The following example demonstrates how to compile a shared object in Linux and link it with softMC at run-time. | The following example demonstrates how to compile a shared object in Linux and link it with softMC at run-time. | ||
− | + | Below there are 5 example files: A C source file, a C header file, a CPP source file, a CPP header file and a makefile.<br/> The source and header files implement a simple program that is given 2 integers as arguments and returns their sum or difference.<br/> This program DOESN'T include a main function, therefore the program can be compiled only into a library, and not an executable. | |
− | The source and header files implement a simple program that is given 2 integers as arguments and returns their sum. | + | |
− | This program DOESN'T include a main function, therefore the program can be compiled only into a library, and not an executable. | + | == Important == |
+ | |||
+ | *You need to create a ''shared object''. Not an object file. | ||
+ | *Take the example with the Makefile and modify it according to your needs. | ||
+ | *Nohup is deprecated. All log messages and (hopefully) printfs to stdout and stderr are redirected to /var/sys.log | ||
+ | *Shared objects, aka, libraries can’t contain a main() function | ||
+ | *It’s possible to build both C and C++ files in the same makefile. Add a list of sources WITHOUT commas | ||
+ | *Can I access functions and classes in the MC FW from the shared object source files? If not, how do I create an interface between them other than in MC-BASIC? Yes, you need to specify the MC FW function header in the sources. | ||
+ | |||
+ | | ||
+ | |||
+ | == Example Program == | ||
− | |||
C Source file: Example.c | C Source file: Example.c | ||
<syntaxhighlight lang="c"> | <syntaxhighlight lang="c"> | ||
Line 11: | Line 22: | ||
#include "Example.h" | #include "Example.h" | ||
+ | |||
+ | /************************** Linux sys.log Declarations ******************************/ | ||
+ | |||
+ | /* MC Modules */ | ||
+ | #define MODULE_NON 0 | ||
+ | #define MODULE_MOTION 1 | ||
+ | #define MODULE_RTS 2 | ||
+ | #define MODULE_TRANSLAT 3 | ||
+ | #define MODULE_SERCOS 4 | ||
+ | #define MODULE_ROBOT 5 | ||
+ | #define MODULE_TRACER 6 | ||
+ | #define MODULE_SYSTEM 7 | ||
+ | #define MODULE_MEMORY 8 | ||
+ | #define MODULE_FILE_SYSTEM 9 | ||
+ | #define MODULE_CLI 10 | ||
+ | #define MODULE_RBOOTP 11 | ||
+ | #define MODULE_ETHERCAT 12 | ||
+ | #define MODULE_FASTDATA 13 | ||
+ | #define MODULE_UAC 14 | ||
+ | #define MODULE_MC_BASIC 15 | ||
+ | #define MODULE_CANOPEN 16 | ||
+ | |||
+ | |||
+ | /* MC Log Level */ | ||
+ | #define LOG_LEVEL_NON 0 | ||
+ | #define LOG_LEVEL_ERROR 1 | ||
+ | #define LOG_LEVEL_WARNING 2 | ||
+ | #define LOG_LEVEL_NOTE 3 | ||
+ | #define LOG_LEVEL_DEBUG 4 | ||
+ | #define LOG_LEVEL_ALL 5 | ||
+ | |||
+ | extern int sys_log(int sub_system, int _debug_level, const char * fmt, int arg1, int arg2, | ||
+ | int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10); | ||
+ | |||
+ | /******************************************************************************************/ | ||
+ | |||
+ | |||
int SHARED_OBJECT_SUM(int arg1, int arg2) | int SHARED_OBJECT_SUM(int arg1, int arg2) | ||
{ | { | ||
+ | sys_log(MODULE_NON, LOG_LEVEL_ERROR, "%s: arg1 = %d, arg2 = %d\n", (int)__FUNCTION__, arg1, arg2, 0,0,0,0,0,0,0); | ||
print_hello(); | print_hello(); | ||
Line 21: | Line 70: | ||
void print_hello(void) | void print_hello(void) | ||
{ | { | ||
− | + | fprintf(stderr, "Hello! This is just an example\n"); | |
+ | } | ||
+ | /* | ||
+ | * This function is called when module is unloaded: | ||
+ | * 1) at "ounload" | ||
+ | * 2) at "reset all" | ||
+ | */ | ||
+ | __attribute__ ((__destructor__)) | ||
+ | void exit_func(void) | ||
+ | { | ||
+ | /* | ||
+ | * Make cleanup here, kill threads, release resources, etc. | ||
+ | */ | ||
} | } | ||
+ | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 30: | Line 92: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | CPP Source file: CPP_Example.c | ||
+ | <syntaxhighlight lang="c"> | ||
+ | #include <iostream> | ||
− | + | #include "CPP_Example.h" | |
− | |||
− | + | extern "C" { | |
− | |||
− | |||
− | |||
− | The CFLAGS in the example might cause | + | int SHARED_OBJECT_SUB(int arg1, int arg2) |
− | The better option is to fix the compilation errors. | + | { |
+ | print_hello_cpp(); | ||
+ | |||
+ | return arg1 - arg2; | ||
+ | } | ||
+ | |||
+ | } // extern "C" { | ||
+ | |||
+ | void print_hello_cpp(void) | ||
+ | { | ||
+ | std::cerr << "A cpp example" << std::endl; | ||
+ | } | ||
+ | /* | ||
+ | * This function is called when module is unloaded: | ||
+ | * 1) at "ounload" | ||
+ | * 2) at "reset all" | ||
+ | */ | ||
+ | __attribute__ ((__destructor__)) | ||
+ | void exit_func(void) | ||
+ | { | ||
+ | /* | ||
+ | * Make cleanup here, kill threads, release resources, etc. | ||
+ | */ | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | CPP Header file: CPP_Example.h | ||
+ | <syntaxhighlight lang="c"> | ||
+ | void print_hello_cpp(void); | ||
+ | </syntaxhighlight> | ||
+ | {{Note/Important|When declaring function names that will be used from MC-Basic context you must use UPPERCASE letters, as in the example of SHARED_OBJECT_SUM and SHARED_OBJECT_SUB.<br/>User functions must be wrapped with extern "C" to avoid CPP mangled names}}<br/> Output strings of functions like printf and fprintf are usually displayed in the Linux terminal, however in the softMC case the behavior is different.<br/> The outputs of printf and cout are discarded while output strings of fprintf and cerr are directed to an object called 'nohup' and can later be read by the user.<br/> To display the contents of nohup do the following: 1. Connect to the softMC using ssh or serial console.<br/> 2. In the Linux terminal type: <pre>-bash-3.2$ cat /var/home/mc/nohup.out | ||
+ | .... | ||
+ | .... | ||
+ | Hello! This is just an example | ||
+ | A cpp example | ||
+ | </pre> | ||
+ | |||
+ | | ||
+ | |||
+ | == Getting x86 Compiler (softMC702, softMC705) == | ||
+ | |||
+ | The compiler and linker shall be used in order to build the shared object is defined by the CC variable in the makefile.<br/> You would need any linux installation (like Ubuntu) in order to run softMC compiler. | ||
+ | |||
+ | Cut and Paste following commands to Linux command line:<br/> cd ~<br/> wget --no-check-certificate [http://servotronix.com/html/softMC_Tool_Chain/0B-jc7OYLo3AYaGFfN2ZkTUNJdHM.tar http://servotronix.com/html/softMC_Tool_Chain/0B-jc7OYLo3AYaGFfN2ZkTUNJdHM.tar]<br/> tar -zxvf 0B-jc7OYLo3AYaGFfN2ZkTUNJdHM.tar<br/> | ||
+ | |||
+ | Complete softMC tool-chain will be installed into your home directory at ~/OSELAS.Toolchain-2011.03.1 | ||
+ | |||
+ | If you are working on a 64 bits Linux, install the following packages: | ||
+ | |||
+ | sudo apt-get install libc6-i386<br/> sudo apt-get install zlib1g:i386 | ||
+ | |||
+ | == Getting x86 Compiler (softMC703, softMC704, softMC705) == | ||
+ | |||
+ | The compiler and linker shall be used in order to build the shared object is defined by the CC variable in the makefile.<br/> You would need any linux installation (like Ubuntu) in order to run softMC compiler. | ||
+ | |||
+ | Cut and Paste following commands to Linux command line:<br/> cd ~<br/> wget --no-check-certificate [http://www.servotronix.com/html/softMC/tools/yocto/32-bit/poky-glibc-x86_64-core-image-minimal-core2-32-toolchain-2.3.sh http://www.servotronix.com/html/softMC/tools/yocto/32-bit/poky-glibc-x86_64-core-image-minimal-core2-32-toolchain-2.3.sh]<br/> chmod +x [http://www.servotronix.com/html/softMC/tools/yocto/32-bit/poky-glibc-x86_64-core-image-minimal-core2-32-toolchain-2.3.sh poky-glibc-x86_64-core-image-minimal-core2-32-toolchain-2.3.sh]<br/> ./[http://www.servotronix.com/html/softMC/tools/yocto/32-bit/poky-glibc-x86_64-core-image-minimal-core2-32-toolchain-2.3.sh poky-glibc-x86_64-core-image-minimal-core2-32-toolchain-2.3.sh] | ||
+ | |||
+ | install to /opt/poky | ||
+ | |||
+ | If you are working on a 64 bits Linux, install the following packages: | ||
+ | |||
+ | sudo apt-get install libc6-i386<br/> sudo apt-get install zlib1g:i386 | ||
+ | |||
+ | | ||
+ | |||
+ | |||
+ | == Getting ARM Compiler for softMC301 (imx.6 CortexA9), 32-bit x86 Host == | ||
+ | |||
+ | Cut and Paste following commands to Linux command line: | ||
+ | |||
+ | cd ~ | ||
+ | |||
+ | wget --no-check-certificate [http://servotronix.com/html/softMC/tools/poky_eglibc_i686_meta_toolchain_cortexa9hf_vfp_neon_toolchain_1.5_snapshot.sh.zip http://servotronix.com/html/softMC/tools/poky_eglibc_i686_meta_toolchain_cortexa9hf_vfp_neon_toolchain_1.5_snapshot.sh.zip] | ||
+ | |||
+ | unzip poky_eglibc_i686_meta_toolchain_cortexa9hf_vfp_neon_toolchain_1.5_snapshot.sh.zip | ||
+ | |||
+ | | ||
+ | |||
+ | md5sum poky_eglibc_i686_meta_toolchain_cortexa9hf_vfp_neon_toolchain_1.5_snapshot.sh<br/> '''# check that md5 is d5a20658f047811ce25fe77203385212''' | ||
+ | |||
+ | chmod +x ./poky-eglibc-i686-meta-toolchain-cortexa9hf-vfp-neon-toolchain-1.5+snapshot.sh | ||
+ | |||
+ | ./poky-eglibc-i686-meta-toolchain-cortexa9hf-vfp-neon-toolchain-1.5+snapshot.sh | ||
+ | |||
+ | == <br/> Getting ARM Compiler for softMC301, 301.2 302 (imx.6 CortexA9), 32-bit x86 Host, softMC version >= 0.4.20.x == | ||
+ | |||
+ | wget --no-check-certificate [https://servotronix.com/html/softMC/tools/imx.6/301.2-302/poky-glibc-x86_64-core-image-minimal-cortexa9hf-neon-toolchain-2.4.3.sh https://servotronix.com/html/softMC/tools/imx.6/301.2-302/poky-glibc-x86_64-core-image-minimal-cortexa9hf-neon-toolchain-2.4.3.sh] | ||
+ | |||
+ | == Makefile (softMC702, softMC705) == | ||
+ | |||
+ | Please notice that makefle CC variable is assigned with a complete path to gcc compiler. This specific gcc is a part of the tool chain we use to build softMC. When compiling shared objects to be linked with softMC it is advised to use OSELAS.Toolchain-2011.03.1 tool chain.<br/> The CFLAGS and CPPFLAGS variables in the example might cause compilation errors. It is not advised, but you can remove those that prevent a successful compilation. The better option is to fix the compilation errors. | ||
The makefile syntax: | The makefile syntax: | ||
<syntaxhighlight lang="bash"> | <syntaxhighlight lang="bash"> | ||
CC=~/OSELAS.Toolchain-2011.03.1/i586-unknown-linux-gnu/gcc-4.5.2-glibc-2.13-binutils-2.21-kernel-2.6.36-sanitized/bin/i586-unknown-linux-gnu-gcc | CC=~/OSELAS.Toolchain-2011.03.1/i586-unknown-linux-gnu/gcc-4.5.2-glibc-2.13-binutils-2.21-kernel-2.6.36-sanitized/bin/i586-unknown-linux-gnu-gcc | ||
+ | CXX=~/OSELAS.Toolchain-2011.03.1/i586-unknown-linux-gnu/gcc-4.5.2-glibc-2.13-binutils-2.21-kernel-2.6.36-sanitized/bin/i586-unknown-linux-gnu-g++ | ||
CFLAGS=-c -g -ansi -pedantic -Wall -Werror | CFLAGS=-c -g -ansi -pedantic -Wall -Werror | ||
+ | CPPFLAGS=-c -g -ansi -pedantic -Wall -Werror | ||
LD_LIBRARY_PATH := .:$(LD_LIBRARY_PATH) | LD_LIBRARY_PATH := .:$(LD_LIBRARY_PATH) | ||
C_SOURCE=Example.c | C_SOURCE=Example.c | ||
− | + | CPP_SOURCE=CPP_Example.cpp | |
+ | |||
+ | C_OBJECTS=$(C_SOURCE:.c=.o) | ||
+ | CPP_OBJECTS=$(CPP_SOURCE:.cpp=.o) | ||
+ | |||
TARGET=EXAMPLE.O | TARGET=EXAMPLE.O | ||
− | $(TARGET): $( | + | $(TARGET): $(C_OBJECTS) $(CPP_OBJECTS) |
− | $(CC) -shared -o $@ $( | + | $(CC) -shared -o $@ $(C_OBJECTS) $(CPP_OBJECTS) |
− | $( | + | $(C_OBJECTS): $(C_SOURCE) |
$(CC) $(CFLAGS) -c $(C_SOURCE) | $(CC) $(CFLAGS) -c $(C_SOURCE) | ||
+ | |||
+ | $(CPP_OBJECTS): $(CPP_SOURCE) | ||
+ | $(CXX) $(CPPFLAGS) -c $(CPP_SOURCE) | ||
clean: | clean: | ||
− | rm | + | rm $(C_OBJECTS) $(CPP_OBJECTS) $(TARGET) |
</syntaxhighlight> | </syntaxhighlight> | ||
− | In order to adapt the makefile to your needs, please change the assignment of the | + | In order to adapt the makefile to your needs, please change the assignment of the variables 'C_SOURCE' and 'CPP_SOURCE' to the name of the source files in your project, and the assignment of the variable 'TARGET'. |
{{Note/Important|softMC can handle only UPPERCASE file names limited to 8.3 convention, meaning, up to 8 characters, followed by a dot, followed by the extensions PRG, or LIB or O (of course in our case it will be .O)<br/>Bear that in mind when assigning the TARGET variable}} | {{Note/Important|softMC can handle only UPPERCASE file names limited to 8.3 convention, meaning, up to 8 characters, followed by a dot, followed by the extensions PRG, or LIB or O (of course in our case it will be .O)<br/>Bear that in mind when assigning the TARGET variable}} | ||
Line 69: | Line 229: | ||
After a successful compilation you will find in the working directory the file EXAMPLE.O, or whatever string was assigned to the variable 'TARGET'. | After a successful compilation you will find in the working directory the file EXAMPLE.O, or whatever string was assigned to the variable 'TARGET'. | ||
− | == | + | |
− | + | ||
− | + | == Makefile (softMC703, softMC706) == | |
+ | |||
+ | The Gcc used to compile the softMC is a part of the tool chain we use to build softMC | ||
+ | |||
+ | Open a terminal and write: | ||
+ | <div style="background:#eeeeee;border:1px solid #cccccc;padding:5px 10px;"> | ||
+ | source /opt/poky/2.3/environment-setup-core2-32-poky-linux | ||
+ | </div> | ||
+ | Then go to the directory the files are in (from the same terminal) and write make. | ||
+ | |||
+ | The makefile syntax: | ||
+ | <syntaxhighlight lang="bash">LD_LIBRARY_PATH := .:$(LD_LIBRARY_PATH) | ||
+ | |||
+ | C_SOURCE=Example.c | ||
+ | CXX_SOURCE=CPP_Example.cpp | ||
+ | |||
+ | C_OBJECTS=$(C_SOURCE:.c=.o) | ||
+ | CXX_OBJECTS=$(CXX_SOURCE:.cpp=.o) | ||
+ | |||
+ | TARGET=EXAMPLE.O | ||
+ | |||
+ | $(TARGET): $(C_OBJECTS) $(CXX_OBJECTS) | ||
+ | $(CC) -shared -fPIC -o $@ $(C_OBJECTS) $(CXX_OBJECTS) | ||
+ | |||
+ | $(C_OBJECTS): $(C_SOURCE) | ||
+ | $(CC) $(CFLAGS) -fPIC -c $(C_SOURCE) -fPIC | ||
+ | |||
+ | $(CXX_OBJECTS): $(CXX_SOURCE) | ||
+ | $(CXX) $(CXXFLAGS) -fPIC -c $(CXX_SOURCE) -fPIC | ||
+ | |||
+ | clean: | ||
+ | rm $(C_OBJECTS) $(CXX_OBJECTS) $(TARGET) | ||
+ | |||
− | <pre> | + | </syntaxhighlight> |
− | my_user@my_computer:~/working_directory$ scp EXAMPLE.O mc@mc.ip.add.ress:/FFS0/SSMC | + | |
+ | In order to adapt the makefile to your needs, please change the assignment of the variables 'C_SOURCE' and 'CPP_SOURCE' to the name of the source files in your project, and the assignment of the variable 'TARGET'. | ||
+ | |||
+ | {{Note/Important|softMC can handle only UPPERCASE file names limited to 8.3 convention, meaning, up to 8 characters, followed by a dot, followed by the extensions PRG, or LIB or O (of course in our case it will be .O)<br/>Bear that in mind when assigning the TARGET variable}} | ||
+ | |||
+ | After a successful compilation you will find in the working directory the file EXAMPLE.O, or whatever string was assigned to the variable 'TARGET'. | ||
+ | |||
+ | Shared Object x86,32 bit zip: | ||
+ | |||
+ | [http://softmc.servotronix.com/wiki/File:example.tar.gz File:Example Shared Object.zip] | ||
+ | |||
+ | | ||
+ | |||
+ | == copy the shared object to softMC == | ||
+ | |||
+ | You can copy the shared object to softMC in 2 different ways:<br/> 1. Using scp, copy the file directly to softMC.<br/> In the Linux terminal type: | ||
+ | <pre>my_user@my_computer:~/working_directory$ scp EXAMPLE.O mc@mc.ip.add.ress:/FFS0/SSMC | ||
</pre> | </pre> | ||
− | |||
− | 2. Use the ControlStudio's file manager to drag and drop the file EXAMPLE.O to the softMC. | + | Where mc.ip.add.ress is the sfotMC's ip address, for example, 192.168.7.152.<br/> or<br/> 2. Use the ControlStudio's file manager to drag and drop the file EXAMPLE.O to the softMC. |
− | ==Link the shared object with softMC== | + | == Link the shared object with softMC == |
− | The shared object now resides within softMC. Now we want to link softMC with the shared object during run-time, and use it. | + | |
− | Linking the shared object is done with ' | + | The shared object now resides within softMC. Now we want to link softMC with the shared object during run-time, and use it. Linking the shared object is done with 'oload' command in CONFIG.PRG context. Please add to your CONFIG.PRG the line: |
− | Please add to your CONFIG.PRG the line: | + | <pre>oload EXAMPLE.O |
− | <pre> | ||
− | oload EXAMPLE.O | ||
</pre> | </pre> | ||
− | Now we need to declare about the shared object's contents and how to use it. This is done by the PROTO.PRO file. | + | Now we need to declare about the shared object's contents and how to use it. This is done by the PROTO.PRO file. please add the following lines to your PROTO.PRO file: |
− | please add the following | + | <pre>import_c SHARED_OBJECT_SUM(byval as long, byval as long) as long |
− | <pre> | + | import_c SHARED_OBJECT_SUB(byval as long, byval as long) as long |
− | import_c | ||
</pre> | </pre> | ||
− | |||
− | |||
− | + | Of course, 'SHARED_OBJECT_SUM' is a function implemented in Example.c. You will need to specify the prototypes of your own functions.<br/> Using ControlStudio send the edited CONFIG.PRG and PROTO.PRO to softMC and type in the ControlStudio terminal 'reset all'. | |
− | |||
+ | If the process was successful, you are now able to invoke functions from the shared object. Type in the ControlStudio terminal: | ||
+ | |||
+ | | ||
<syntaxhighlight lang="vb"> | <syntaxhighlight lang="vb"> | ||
--> | --> | ||
Line 106: | Line 310: | ||
11 | 11 | ||
--> | --> | ||
+ | --> | ||
+ | -->?SHARED_OBJECT_SUB(5, 6) | ||
+ | -1 | ||
+ | --> | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | | ||
+ | |||
+ | == Passing MC-Basic strings to C functions == | ||
+ | |||
+ | It is possible to send string objects to C functions for parsing purposes, for example. In order to do so you need to include in your code the following declarations: | ||
+ | <syntaxhighlight lang="c"> | ||
+ | typedef int INT32; | ||
+ | typedef unsigned int UINT32; | ||
+ | typedef pthread_mutex_t* SEMM_ID; | ||
+ | typedef int FUNCPTR; /* ptr to func returning int */ | ||
+ | |||
+ | |||
+ | /* defining MC Basic SYS String */ | ||
+ | typedef struct { | ||
+ | INT32 type; /* string type */ | ||
+ | INT32 scope; /* string variable scope */ | ||
+ | INT32 temp; /* memory release flag */ | ||
+ | INT32 alloc_size; /* number of bytes allocated */ | ||
+ | INT32 occup_size; /* number of bytes occupied */ | ||
+ | INT32 num_chars; /* number of characters */ | ||
+ | UINT32 counter; /* assignment counter */ | ||
+ | SEMM_ID mutex; /* mutex */ | ||
+ | unsigned char* data; /* pointer to string */ | ||
+ | FUNCPTR FuncUpdateString; /* pointer to callback function */ | ||
+ | INT32 FuncUpdateStringParam; /* parameter of callback function */ | ||
+ | } SYS_STRING; | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | |||
+ | In the declaration of the C function that receives the string, specify the string argument: | ||
+ | <syntaxhighlight lang="c"> | ||
+ | int MY_C_FUNCTION(int some_var, SYS_STRING* some_str) | ||
+ | </syntaxhighlight> | ||
+ | In the import_c command that declares the interface from MC-Basic to C function, declare: <syntaxhighlight lang="vb"> | ||
+ | import_c MY_C_FUNCTION(byval as long, byval as string) as long | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | | ||
+ | |||
+ | == Using Linux sys.log from Shared Object context == | ||
+ | |||
+ | It is possible to log messages in the Linux logger sys.log. In order to do so you need to include in your code the following declarations: | ||
+ | <syntaxhighlight lang="c"> | ||
+ | |||
+ | /************************** Linux sys.log Declarations ******************************/ | ||
+ | |||
+ | /* MC Modules */ | ||
+ | #define MODULE_NON 0 | ||
+ | #define MODULE_MOTION 1 | ||
+ | #define MODULE_RTS 2 | ||
+ | #define MODULE_TRANSLAT 3 | ||
+ | #define MODULE_SERCOS 4 | ||
+ | #define MODULE_ROBOT 5 | ||
+ | #define MODULE_TRACER 6 | ||
+ | #define MODULE_SYSTEM 7 | ||
+ | #define MODULE_MEMORY 8 | ||
+ | #define MODULE_FILE_SYSTEM 9 | ||
+ | #define MODULE_CLI 10 | ||
+ | #define MODULE_RBOOTP 11 | ||
+ | #define MODULE_ETHERCAT 12 | ||
+ | #define MODULE_FASTDATA 13 | ||
+ | #define MODULE_UAC 14 | ||
+ | #define MODULE_MC_BASIC 15 | ||
+ | #define MODULE_CANOPEN 16 | ||
+ | |||
+ | |||
+ | /* MC Log Level */ | ||
+ | #define LOG_LEVEL_NON 0 | ||
+ | #define LOG_LEVEL_ERROR 1 | ||
+ | #define LOG_LEVEL_WARNING 2 | ||
+ | #define LOG_LEVEL_NOTE 3 | ||
+ | #define LOG_LEVEL_DEBUG 4 | ||
+ | #define LOG_LEVEL_ALL 5 | ||
+ | |||
+ | extern int sys_log(int sub_system, int _debug_level, const char * fmt, int arg1, int arg2, | ||
+ | int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10); | ||
+ | /******************************************************************************************/ | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | To send a message to sys.log invoke sys_log with fmt as a printf formatted string. A more thorough explanation about sys.log and an example can be found in [[Program_Examples:sys_log|Linux sys.log]]. | ||
+ | |||
+ | | ||
+ | |||
+ | == Examples == | ||
+ | |||
+ | Shared Object x86.<br/> [[File:Shared Object.zip|Shared_Object.zip]] | ||
+ | |||
+ | The example corresponds to commit SHA-1: 5228016ac44122213dcb05d781b15c8e05054d5b in GIT. | ||
+ | |||
+ | "Hello world " project ARM Cortex A9 | ||
+ | |||
+ | [[Media:ARM_Hello_world.zip|Media:ARM Hello world.zip]] | ||
+ | |||
+ | | ||
− | |||
== See Also == | == See Also == | ||
− | * [[MC-Basic:IMPORT_C|IMPORT_C]] | + | |
+ | *[[MC-Basic_C-Interface|MC-Basic C-Interface]] | ||
+ | *[[MC-Basic:OLOAD|OLOAD]] | ||
+ | *[[MC-Basic:IMPORT_C|IMPORT_C]] | ||
+ | *[[Program_Examples:sys_log|Linux sys.log]] |
Latest revision as of 10:53, 20 November 2022
Language: | English • 中文(简体) |
---|
The following example demonstrates how to compile a shared object in Linux and link it with softMC at run-time.
Below there are 5 example files: A C source file, a C header file, a CPP source file, a CPP header file and a makefile.
The source and header files implement a simple program that is given 2 integers as arguments and returns their sum or difference.
This program DOESN'T include a main function, therefore the program can be compiled only into a library, and not an executable.
Contents
- 1 Important
- 2 Example Program
- 3 Getting x86 Compiler (softMC702, softMC705)
- 4 Getting x86 Compiler (softMC703, softMC704, softMC705)
- 5 Getting ARM Compiler for softMC301 (imx.6 CortexA9), 32-bit x86 Host
- 6 Getting ARM Compiler for softMC301, 301.2 302 (imx.6 CortexA9), 32-bit x86 Host, softMC version >= 0.4.20.x
- 7 Makefile (softMC702, softMC705)
- 8 Makefile (softMC703, softMC706)
- 9 copy the shared object to softMC
- 10 Link the shared object with softMC
- 11 Passing MC-Basic strings to C functions
- 12 Using Linux sys.log from Shared Object context
- 13 Examples
- 14 See Also
Important
- You need to create a shared object. Not an object file.
- Take the example with the Makefile and modify it according to your needs.
- Nohup is deprecated. All log messages and (hopefully) printfs to stdout and stderr are redirected to /var/sys.log
- Shared objects, aka, libraries can’t contain a main() function
- It’s possible to build both C and C++ files in the same makefile. Add a list of sources WITHOUT commas
- Can I access functions and classes in the MC FW from the shared object source files? If not, how do I create an interface between them other than in MC-BASIC? Yes, you need to specify the MC FW function header in the sources.
Example Program
C Source file: Example.c
#include <stdio.h>
#include "Example.h"
/************************** Linux sys.log Declarations ******************************/
/* MC Modules */
#define MODULE_NON 0
#define MODULE_MOTION 1
#define MODULE_RTS 2
#define MODULE_TRANSLAT 3
#define MODULE_SERCOS 4
#define MODULE_ROBOT 5
#define MODULE_TRACER 6
#define MODULE_SYSTEM 7
#define MODULE_MEMORY 8
#define MODULE_FILE_SYSTEM 9
#define MODULE_CLI 10
#define MODULE_RBOOTP 11
#define MODULE_ETHERCAT 12
#define MODULE_FASTDATA 13
#define MODULE_UAC 14
#define MODULE_MC_BASIC 15
#define MODULE_CANOPEN 16
/* MC Log Level */
#define LOG_LEVEL_NON 0
#define LOG_LEVEL_ERROR 1
#define LOG_LEVEL_WARNING 2
#define LOG_LEVEL_NOTE 3
#define LOG_LEVEL_DEBUG 4
#define LOG_LEVEL_ALL 5
extern int sys_log(int sub_system, int _debug_level, const char * fmt, int arg1, int arg2,
int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10);
/******************************************************************************************/
int SHARED_OBJECT_SUM(int arg1, int arg2)
{
sys_log(MODULE_NON, LOG_LEVEL_ERROR, "%s: arg1 = %d, arg2 = %d\n", (int)__FUNCTION__, arg1, arg2, 0,0,0,0,0,0,0);
print_hello();
return arg1 + arg2;
}
void print_hello(void)
{
fprintf(stderr, "Hello! This is just an example\n");
}
/*
* This function is called when module is unloaded:
* 1) at "ounload"
* 2) at "reset all"
*/
__attribute__ ((__destructor__))
void exit_func(void)
{
/*
* Make cleanup here, kill threads, release resources, etc.
*/
}
C Header file: Example.h
void print_hello(void);
CPP Source file: CPP_Example.c
#include <iostream>
#include "CPP_Example.h"
extern "C" {
int SHARED_OBJECT_SUB(int arg1, int arg2)
{
print_hello_cpp();
return arg1 - arg2;
}
} // extern "C" {
void print_hello_cpp(void)
{
std::cerr << "A cpp example" << std::endl;
}
/*
* This function is called when module is unloaded:
* 1) at "ounload"
* 2) at "reset all"
*/
__attribute__ ((__destructor__))
void exit_func(void)
{
/*
* Make cleanup here, kill threads, release resources, etc.
*/
}
CPP Header file: CPP_Example.h
void print_hello_cpp(void);
IMPORTANT | |
When declaring function names that will be used from MC-Basic context you must use UPPERCASE letters, as in the example of SHARED_OBJECT_SUM and SHARED_OBJECT_SUB. User functions must be wrapped with extern "C" to avoid CPP mangled names |
Output strings of functions like printf and fprintf are usually displayed in the Linux terminal, however in the softMC case the behavior is different.
The outputs of printf and cout are discarded while output strings of fprintf and cerr are directed to an object called 'nohup' and can later be read by the user.
To display the contents of nohup do the following: 1. Connect to the softMC using ssh or serial console.
2. In the Linux terminal type:
-bash-3.2$ cat /var/home/mc/nohup.out .... .... Hello! This is just an example A cpp example
Getting x86 Compiler (softMC702, softMC705)
The compiler and linker shall be used in order to build the shared object is defined by the CC variable in the makefile.
You would need any linux installation (like Ubuntu) in order to run softMC compiler.
Cut and Paste following commands to Linux command line:
cd ~
wget --no-check-certificate http://servotronix.com/html/softMC_Tool_Chain/0B-jc7OYLo3AYaGFfN2ZkTUNJdHM.tar
tar -zxvf 0B-jc7OYLo3AYaGFfN2ZkTUNJdHM.tar
Complete softMC tool-chain will be installed into your home directory at ~/OSELAS.Toolchain-2011.03.1
If you are working on a 64 bits Linux, install the following packages:
sudo apt-get install libc6-i386
sudo apt-get install zlib1g:i386
Getting x86 Compiler (softMC703, softMC704, softMC705)
The compiler and linker shall be used in order to build the shared object is defined by the CC variable in the makefile.
You would need any linux installation (like Ubuntu) in order to run softMC compiler.
Cut and Paste following commands to Linux command line:
cd ~
wget --no-check-certificate http://www.servotronix.com/html/softMC/tools/yocto/32-bit/poky-glibc-x86_64-core-image-minimal-core2-32-toolchain-2.3.sh
chmod +x poky-glibc-x86_64-core-image-minimal-core2-32-toolchain-2.3.sh
./poky-glibc-x86_64-core-image-minimal-core2-32-toolchain-2.3.sh
install to /opt/poky
If you are working on a 64 bits Linux, install the following packages:
sudo apt-get install libc6-i386
sudo apt-get install zlib1g:i386
Getting ARM Compiler for softMC301 (imx.6 CortexA9), 32-bit x86 Host
Cut and Paste following commands to Linux command line:
cd ~
wget --no-check-certificate http://servotronix.com/html/softMC/tools/poky_eglibc_i686_meta_toolchain_cortexa9hf_vfp_neon_toolchain_1.5_snapshot.sh.zip
unzip poky_eglibc_i686_meta_toolchain_cortexa9hf_vfp_neon_toolchain_1.5_snapshot.sh.zip
md5sum poky_eglibc_i686_meta_toolchain_cortexa9hf_vfp_neon_toolchain_1.5_snapshot.sh
# check that md5 is d5a20658f047811ce25fe77203385212
chmod +x ./poky-eglibc-i686-meta-toolchain-cortexa9hf-vfp-neon-toolchain-1.5+snapshot.sh
./poky-eglibc-i686-meta-toolchain-cortexa9hf-vfp-neon-toolchain-1.5+snapshot.sh
Getting ARM Compiler for softMC301, 301.2 302 (imx.6 CortexA9), 32-bit x86 Host, softMC version >= 0.4.20.x
wget --no-check-certificate https://servotronix.com/html/softMC/tools/imx.6/301.2-302/poky-glibc-x86_64-core-image-minimal-cortexa9hf-neon-toolchain-2.4.3.sh
Makefile (softMC702, softMC705)
Please notice that makefle CC variable is assigned with a complete path to gcc compiler. This specific gcc is a part of the tool chain we use to build softMC. When compiling shared objects to be linked with softMC it is advised to use OSELAS.Toolchain-2011.03.1 tool chain.
The CFLAGS and CPPFLAGS variables in the example might cause compilation errors. It is not advised, but you can remove those that prevent a successful compilation. The better option is to fix the compilation errors.
The makefile syntax:
CC=~/OSELAS.Toolchain-2011.03.1/i586-unknown-linux-gnu/gcc-4.5.2-glibc-2.13-binutils-2.21-kernel-2.6.36-sanitized/bin/i586-unknown-linux-gnu-gcc
CXX=~/OSELAS.Toolchain-2011.03.1/i586-unknown-linux-gnu/gcc-4.5.2-glibc-2.13-binutils-2.21-kernel-2.6.36-sanitized/bin/i586-unknown-linux-gnu-g++
CFLAGS=-c -g -ansi -pedantic -Wall -Werror
CPPFLAGS=-c -g -ansi -pedantic -Wall -Werror
LD_LIBRARY_PATH := .:$(LD_LIBRARY_PATH)
C_SOURCE=Example.c
CPP_SOURCE=CPP_Example.cpp
C_OBJECTS=$(C_SOURCE:.c=.o)
CPP_OBJECTS=$(CPP_SOURCE:.cpp=.o)
TARGET=EXAMPLE.O
$(TARGET): $(C_OBJECTS) $(CPP_OBJECTS)
$(CC) -shared -o $@ $(C_OBJECTS) $(CPP_OBJECTS)
$(C_OBJECTS): $(C_SOURCE)
$(CC) $(CFLAGS) -c $(C_SOURCE)
$(CPP_OBJECTS): $(CPP_SOURCE)
$(CXX) $(CPPFLAGS) -c $(CPP_SOURCE)
clean:
rm $(C_OBJECTS) $(CPP_OBJECTS) $(TARGET)
In order to adapt the makefile to your needs, please change the assignment of the variables 'C_SOURCE' and 'CPP_SOURCE' to the name of the source files in your project, and the assignment of the variable 'TARGET'.
IMPORTANT | |
softMC can handle only UPPERCASE file names limited to 8.3 convention, meaning, up to 8 characters, followed by a dot, followed by the extensions PRG, or LIB or O (of course in our case it will be .O) Bear that in mind when assigning the TARGET variable |
After a successful compilation you will find in the working directory the file EXAMPLE.O, or whatever string was assigned to the variable 'TARGET'.
Makefile (softMC703, softMC706)
The Gcc used to compile the softMC is a part of the tool chain we use to build softMC
Open a terminal and write:
source /opt/poky/2.3/environment-setup-core2-32-poky-linux
Then go to the directory the files are in (from the same terminal) and write make.
The makefile syntax:
LD_LIBRARY_PATH := .:$(LD_LIBRARY_PATH)
C_SOURCE=Example.c
CXX_SOURCE=CPP_Example.cpp
C_OBJECTS=$(C_SOURCE:.c=.o)
CXX_OBJECTS=$(CXX_SOURCE:.cpp=.o)
TARGET=EXAMPLE.O
$(TARGET): $(C_OBJECTS) $(CXX_OBJECTS)
$(CC) -shared -fPIC -o $@ $(C_OBJECTS) $(CXX_OBJECTS)
$(C_OBJECTS): $(C_SOURCE)
$(CC) $(CFLAGS) -fPIC -c $(C_SOURCE) -fPIC
$(CXX_OBJECTS): $(CXX_SOURCE)
$(CXX) $(CXXFLAGS) -fPIC -c $(CXX_SOURCE) -fPIC
clean:
rm $(C_OBJECTS) $(CXX_OBJECTS) $(TARGET)
In order to adapt the makefile to your needs, please change the assignment of the variables 'C_SOURCE' and 'CPP_SOURCE' to the name of the source files in your project, and the assignment of the variable 'TARGET'.
IMPORTANT | |
softMC can handle only UPPERCASE file names limited to 8.3 convention, meaning, up to 8 characters, followed by a dot, followed by the extensions PRG, or LIB or O (of course in our case it will be .O) Bear that in mind when assigning the TARGET variable |
After a successful compilation you will find in the working directory the file EXAMPLE.O, or whatever string was assigned to the variable 'TARGET'.
Shared Object x86,32 bit zip:
File:Example Shared Object.zip
You can copy the shared object to softMC in 2 different ways:
1. Using scp, copy the file directly to softMC.
In the Linux terminal type:
my_user@my_computer:~/working_directory$ scp EXAMPLE.O mc@mc.ip.add.ress:/FFS0/SSMC
Where mc.ip.add.ress is the sfotMC's ip address, for example, 192.168.7.152.
or
2. Use the ControlStudio's file manager to drag and drop the file EXAMPLE.O to the softMC.
The shared object now resides within softMC. Now we want to link softMC with the shared object during run-time, and use it. Linking the shared object is done with 'oload' command in CONFIG.PRG context. Please add to your CONFIG.PRG the line:
oload EXAMPLE.O
Now we need to declare about the shared object's contents and how to use it. This is done by the PROTO.PRO file. please add the following lines to your PROTO.PRO file:
import_c SHARED_OBJECT_SUM(byval as long, byval as long) as long import_c SHARED_OBJECT_SUB(byval as long, byval as long) as long
Of course, 'SHARED_OBJECT_SUM' is a function implemented in Example.c. You will need to specify the prototypes of your own functions.
Using ControlStudio send the edited CONFIG.PRG and PROTO.PRO to softMC and type in the ControlStudio terminal 'reset all'.
If the process was successful, you are now able to invoke functions from the shared object. Type in the ControlStudio terminal:
-->
-->
-->
-->?SHARED_OBJECT_SUM(5, 6)
11
-->
-->
-->?SHARED_OBJECT_SUB(5, 6)
-1
-->
Passing MC-Basic strings to C functions
It is possible to send string objects to C functions for parsing purposes, for example. In order to do so you need to include in your code the following declarations:
typedef int INT32;
typedef unsigned int UINT32;
typedef pthread_mutex_t* SEMM_ID;
typedef int FUNCPTR; /* ptr to func returning int */
/* defining MC Basic SYS String */
typedef struct {
INT32 type; /* string type */
INT32 scope; /* string variable scope */
INT32 temp; /* memory release flag */
INT32 alloc_size; /* number of bytes allocated */
INT32 occup_size; /* number of bytes occupied */
INT32 num_chars; /* number of characters */
UINT32 counter; /* assignment counter */
SEMM_ID mutex; /* mutex */
unsigned char* data; /* pointer to string */
FUNCPTR FuncUpdateString; /* pointer to callback function */
INT32 FuncUpdateStringParam; /* parameter of callback function */
} SYS_STRING;
In the declaration of the C function that receives the string, specify the string argument:
int MY_C_FUNCTION(int some_var, SYS_STRING* some_str)
import_c MY_C_FUNCTION(byval as long, byval as string) as long
It is possible to log messages in the Linux logger sys.log. In order to do so you need to include in your code the following declarations:
/************************** Linux sys.log Declarations ******************************/
/* MC Modules */
#define MODULE_NON 0
#define MODULE_MOTION 1
#define MODULE_RTS 2
#define MODULE_TRANSLAT 3
#define MODULE_SERCOS 4
#define MODULE_ROBOT 5
#define MODULE_TRACER 6
#define MODULE_SYSTEM 7
#define MODULE_MEMORY 8
#define MODULE_FILE_SYSTEM 9
#define MODULE_CLI 10
#define MODULE_RBOOTP 11
#define MODULE_ETHERCAT 12
#define MODULE_FASTDATA 13
#define MODULE_UAC 14
#define MODULE_MC_BASIC 15
#define MODULE_CANOPEN 16
/* MC Log Level */
#define LOG_LEVEL_NON 0
#define LOG_LEVEL_ERROR 1
#define LOG_LEVEL_WARNING 2
#define LOG_LEVEL_NOTE 3
#define LOG_LEVEL_DEBUG 4
#define LOG_LEVEL_ALL 5
extern int sys_log(int sub_system, int _debug_level, const char * fmt, int arg1, int arg2,
int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10);
/******************************************************************************************/
To send a message to sys.log invoke sys_log with fmt as a printf formatted string. A more thorough explanation about sys.log and an example can be found in Linux sys.log.
Examples
Shared Object x86.
File:Shared Object.zip
The example corresponds to commit SHA-1: 5228016ac44122213dcb05d781b15c8e05054d5b in GIT.
"Hello world " project ARM Cortex A9