Difference between revisions of "MC-Basic C-Interface"

From SoftMC-Wiki
Jump to: navigation, search
m (Special Considerations)
m (Prototype File)
Line 94: Line 94:
 
<pre>
 
<pre>
 
Dim shared Str2global as string
 
Dim shared Str2global as string
 
 
Dim shared Str1global as string
 
Dim shared Str1global as string
 
 
<nowiki>Dim shared LongArray[100] as long</nowiki>
 
<nowiki>Dim shared LongArray[100] as long</nowiki>
 
 
Dim shared d1 as double
 
Dim shared d1 as double
 
 
program
 
program
 
 
' Use OLOAD to load the object file before loading the program
 
' Use OLOAD to load the object file before loading the program
 
 
' that uses the C-Functions
 
' that uses the C-Functions
 
  
 
' /* No Parameters */  
 
' /* No Parameters */  
 
 
' int CFUNC_LV(void)  
 
' int CFUNC_LV(void)  
 
 
?CFUNC_LV()
 
?CFUNC_LV()
 
  
 
' double CFUNC_DV(double)  
 
' double CFUNC_DV(double)  
 
 
?CFUNC_DRD(1.2345)
 
?CFUNC_DRD(1.2345)
 
  
 
' /* returns string */
 
' /* returns string */
 
 
char* CFUNC_SV(void)
 
char* CFUNC_SV(void)
 
 
?CFUNC_SV()
 
?CFUNC_SV()
 
  
 
' /* No Parameters, not return value */
 
' /* No Parameters, not return value */
 
 
' void CFUNC_VV(void)
 
' void CFUNC_VV(void)
 
 
CFUNC_VV()
 
CFUNC_VV()
 
 
' /* Strings */
 
' /* Strings */
 
 
' char* CFUNC_SS(char* S)
 
' char* CFUNC_SS(char* S)
 
 
Str2global=CFUNC_SS(Str1global)
 
Str2global=CFUNC_SS(Str1global)
 
  
 
' /* Arrays */
 
' /* Arrays */
 
 
' double CFUNC_LARD(long *l);
 
' double CFUNC_LARD(long *l);
 
 
d1= cFunc_LARD(LongArray)
 
d1= cFunc_LARD(LongArray)
 
 
end program
 
end program
 
</pre>
 
</pre>
 +
 
Example of PROTO.PRO:
 
Example of PROTO.PRO:
 
<pre>
 
<pre>
 
'No Parametrs
 
'No Parametrs
 
 
import_c CFUNC_LV() As Long
 
import_c CFUNC_LV() As Long
 
 
import_c CFUNC_DV() As Double
 
import_c CFUNC_DV() As Double
 
 
import_c CFUNC_SV() As String
 
import_c CFUNC_SV() As String
 
 
import_c CFUNC_VV()
 
import_c CFUNC_VV()
 
 
'A Single "By Value" Parameter
 
'A Single "By Value" Parameter
 
 
import_c CFUNC_LL(ByVal As Long) As Long
 
import_c CFUNC_LL(ByVal As Long) As Long
 
 
import_c CFUNC_DD(ByVal As Double) As Double
 
import_c CFUNC_DD(ByVal As Double) As Double
 
 
import_c CFUNC_SS(ByVal As String) As String
 
import_c CFUNC_SS(ByVal As String) As String
 
 
'A Single "By Reference" Parameter
 
'A Single "By Reference" Parameter
 
 
import_c CFUNC_LRL(As Long) As Long
 
import_c CFUNC_LRL(As Long) As Long
 
 
import_c CFUNC_DRD(As Double) As Double
 
import_c CFUNC_DRD(As Double) As Double
 
 
import_c CFUNC_SRS(As String) As String
 
import_c CFUNC_SRS(As String) As String
 
+
'Multiple "By Value" Parameters
'Multiple "By Value" Parametrs
 
 
 
 
import_c CFUNC_LVALP(ByVal As double, ByVal As Long, ByVal As String) As Long
 
import_c CFUNC_LVALP(ByVal As double, ByVal As Long, ByVal As String) As Long
 
 
import_c CFUNC_VVALP(ByVal As String, ByVal As double, ByVal AS Long)
 
import_c CFUNC_VVALP(ByVal As String, ByVal As double, ByVal AS Long)
 
 
'Multiple "By Reference" Parameters
 
'Multiple "By Reference" Parameters
 
 
import_c CFUNC_DREFP(As String, As Long, As Double) As Double
 
import_c CFUNC_DREFP(As String, As Long, As Double) As Double
 
 
import_c CFUNC_VREFP(As Long, As Double, As String)
 
import_c CFUNC_VREFP(As Long, As Double, As String)
 
 
' Mixed Parameters
 
' Mixed Parameters
 
 
import_c CFUNC_VMIXP(ByVal As Long,As Double,ByVal As String,As String,As Long,ByVal As double) AS Long
 
import_c CFUNC_VMIXP(ByVal As Long,As Double,ByVal As String,As String,As Long,ByVal As double) AS Long
 
</pre>
 
</pre>
 +
 
Example of test.c:
 
Example of test.c:
 
<pre>
 
<pre>
 
/* No Parameters */
 
/* No Parameters */
 
 
int CFUNC_LV(void)
 
int CFUNC_LV(void)
 
 
{
 
{
 
 
return 1;
 
return 1;
 
 
}
 
}
 
 
double CFUNC_DV(void)
 
double CFUNC_DV(void)
 
 
{
 
{
 
 
return 2.2;
 
return 2.2;
 
 
}
 
}
 
 
char* CFUNC_SV(void)
 
char* CFUNC_SV(void)
 
 
{
 
{
 
 
return "SV";
 
return "SV";
 
 
}
 
}
 
 
void CFUNC_VV(void)
 
void CFUNC_VV(void)
 
 
{
 
{
 
 
int fd = open("/tyCo/1",2,0);
 
int fd = open("/tyCo/1",2,0);
 
 
fdprintf(fd,"VV\r\n");
 
fdprintf(fd,"VV\r\n");
 
 
close(fd);
 
close(fd);
 
 
}
 
}
 
 
/* A Single "By Value" Parameter */
 
/* A Single "By Value" Parameter */
 
 
int CFUNC_LL(int L)
 
int CFUNC_LL(int L)
 
 
{
 
{
 
 
L = L + 1;
 
L = L + 1;
 
 
return L;
 
return L;
 
 
}
 
}
 
 
double CFUNC_DD(double D)
 
double CFUNC_DD(double D)
 
 
{
 
{
 
 
D = D + 2.2;
 
D = D + 2.2;
 
 
return D;
 
return D;
 
 
}
 
}
 
 
char* CFUNC_SS(char* S)
 
char* CFUNC_SS(char* S)
 
 
{
 
{
 
 
strcpy(S,"SS");
 
strcpy(S,"SS");
 
 
return S;
 
return S;
 
 
}
 
}
 
 
/* A Single "By Reference" Parameter */
 
/* A Single "By Reference" Parameter */
 
 
int CFUNC_LRL(int* L)
 
int CFUNC_LRL(int* L)
 
 
{
 
{
 
 
<nowiki>*L = *L + 3;</nowiki>
 
<nowiki>*L = *L + 3;</nowiki>
 
 
return *L;
 
return *L;
 
 
}
 
}
 
 
double CFUNC_DRD(double* D)
 
double CFUNC_DRD(double* D)
 
 
{
 
{
 
 
<nowiki>*D = *D + 4.4;</nowiki>
 
<nowiki>*D = *D + 4.4;</nowiki>
 
 
return *D;
 
return *D;
 
 
}
 
}
 
 
char* CFUNC_SRS(char** S)
 
char* CFUNC_SRS(char** S)
 
 
{
 
{
 
 
strcpy(*S,"SRS");
 
strcpy(*S,"SRS");
 
 
return *S;
 
return *S;
 
 
}
 
}
 
 
/* Multiple Parameters */
 
/* Multiple Parameters */
 
 
/* By Value Parameters */
 
/* By Value Parameters */
 
 
int CFUNC_LVALP(double D, int L, char* S)
 
int CFUNC_LVALP(double D, int L, char* S)
 
 
return (D + L + atoi(S));  
 
return (D + L + atoi(S));  
 
 
}  
 
}  
 
 
void CFUNC_VVALP(char* S, double D, int L)
 
void CFUNC_VVALP(char* S, double D, int L)
 
 
{
 
{
 
 
int fd = open("/tyCo/1",2,0);
 
int fd = open("/tyCo/1",2,0);
 
 
 
fdprintf(fd,"Original Values:%d, %f, %s\r\n", L, D, S);
 
fdprintf(fd,"Original Values:%d, %f, %s\r\n", L, D, S);
 
 
 
L = 10;
 
L = 10;
 
 
D = 22.2;
 
D = 22.2;
 
 
strcpy(S,"VValP");
 
strcpy(S,"VValP");
 
 
 
fdprintf(fd,"New Value:%d, %f, %s\r\n", L, D, S);
 
fdprintf(fd,"New Value:%d, %f, %s\r\n", L, D, S);
 
 
 
close(fd);  
 
close(fd);  
 
 
}  
 
}  
 
 
 
/* By Reference Parameters */
 
/* By Reference Parameters */
 
 
double CFUNC_DREFP(char** S, int* L, double* D)
 
double CFUNC_DREFP(char** S, int* L, double* D)
 
 
{
 
{
 
 
return (*D + *L + atof(*S));  
 
return (*D + *L + atof(*S));  
 
 
}
 
}
 
</pre>
 
</pre>
 +
 
== Special Considerations ==
 
== Special Considerations ==
 
Motion and System properties can only be passed by value.
 
Motion and System properties can only be passed by value.

Revision as of 12:26, 2 April 2014

Introduction

The softMC offers users an option to incorporate applications written in C or C++ into an MC-Basic task. You can write your algorithm in C/C++, compile it with a GNU compiler, download it into a target program and call the code from a program written in MC-Basic or directly from the command line.

The parameters can be passed by value as well as by reference. This function returns a value that can be processed by an MC-Basic application.

MC-Basic provides a facility to load a user object-file into the RAM of the softMC. This file is relocatable and must include information about global symbols for the softMC to find the C-function. The object module may consist of any number of functions. The only restriction is RAM limit.

Object Files

Object files (extension “.o”), contain compiled C-programs and are stored in the Flash disk. You can SEND object files to the controller, load files into RAM with OLOAD and unload them with OUNLOAD. If OLOAD/OUNLOAD fails for any reason, details are found in the OLOAD.ERR file.

Prototype File

For the MC-Basic language translator to match function parameters, provide a C-function prototype file (PROTO.PRO). It is important to understand that matching between the provided softMC prototype and actual C implementation cannot be tested by the translator. It is your responsibility to keep consistency between the function prototype and C implementation.


NOTE-Info.svgNOTE
To speedup translation of the prototype file, PROTO.PRO is copied into RAM at startup and at every OLOAD. When PROTO.PRO is modified and sent to the controller, issue an OLOAD or reboot the softMC to refresh the prototypes in the RAM.

The translator is case-insensitive, while object module loader is case-sensitive, so write the name of a C function in capital letters within the C code. softMC prototypes of C functions and C function calls through the softMC are not case sensitive.

Parameters can be passed “by value” and “by reference”

Few object files may be incrementally linked together.

The general syntax for the softMC prototype of a C-function is:

IMPORT_C <Function_Name> ({AS <type>}, {BYVAL AS {<type>}) {AS <type>}

A parameter passed by value has the BYVAL prefix.

A parameter passed by reference has no prefix.

Prototypes do not include parameter names.

A C function prototype with no parameters is written with empty parentheses:

IMPORT_C <Function_Name> ( ) {AS <type>}

A C function prototype with no returned value (a void function) is written as:

IMPORT_C <Function_Name> ({AS <type>}, {BYVAL AS {<type>})

A C-function accepts any combination of double-, long- and string-type parameters. The parameters may be passed “by value” or “by reference”.

The returned value may be long, double, string or none (for C functions with void returned value).

Examples of prototypes and implementation:


MC-Basic Prototype
C Implementation
import_c cFunc_LV As Long int CFUNC_LV(void);
import_c cFunc_DV As double double CFUNC_LV(void);
import_c cFunc_SV As string char* CFUNC_LV(void);
import_c cFunc_VV() void CFUNC_VV(void);
import_c cFunc_LL(ByVal As Long) As Long int CFUNC_LL(int L);
import_c cFunc_DRD(As Double) As Double double CFUNC_DRD(double* D);
import_c cFunc_SRS(As String) As String char* CFUNC_SRS(char** S);
Import_C cFunc_LARD([*] as Long) as Double double CFUNC_LARD(long *l);
import_c cFunc_SS(ByVal As String) As String char* CFUNC_SS(char* S);

Parameters can be of type long, double or string; in any order, up to 32 parameters.

Only one-dimensional arrays are allowed as C-functions arguments.

Example of calling a C-function from MC-Basic:

Dim shared Str2global as string
Dim shared Str1global as string
Dim shared LongArray[100] as long
Dim shared d1 as double
program
' Use OLOAD to load the object file before loading the program
' that uses the C-Functions

' /* No Parameters */ 
' int CFUNC_LV(void) 
?CFUNC_LV()

' double CFUNC_DV(double) 
?CFUNC_DRD(1.2345)

' /* returns string */
char* CFUNC_SV(void)
?CFUNC_SV()

' /* No Parameters, not return value */
' void CFUNC_VV(void)
CFUNC_VV()
' /* Strings */
' char* CFUNC_SS(char* S)
Str2global=CFUNC_SS(Str1global)

' /* Arrays */
' double CFUNC_LARD(long *l);
d1= cFunc_LARD(LongArray)
end program

Example of PROTO.PRO:

'No Parametrs
import_c CFUNC_LV() As Long
import_c CFUNC_DV() As Double
import_c CFUNC_SV() As String
import_c CFUNC_VV()
'A Single "By Value" Parameter
import_c CFUNC_LL(ByVal As Long) As Long
import_c CFUNC_DD(ByVal As Double) As Double
import_c CFUNC_SS(ByVal As String) As String
'A Single "By Reference" Parameter
import_c CFUNC_LRL(As Long) As Long
import_c CFUNC_DRD(As Double) As Double
import_c CFUNC_SRS(As String) As String
'Multiple "By Value" Parameters
import_c CFUNC_LVALP(ByVal As double, ByVal As Long, ByVal As String) As Long
import_c CFUNC_VVALP(ByVal As String, ByVal As double, ByVal AS Long)
'Multiple "By Reference" Parameters
import_c CFUNC_DREFP(As String, As Long, As Double) As Double
import_c CFUNC_VREFP(As Long, As Double, As String)
' Mixed Parameters
import_c CFUNC_VMIXP(ByVal As Long,As Double,ByVal As String,As String,As Long,ByVal As double) AS Long

Example of test.c:

/* No Parameters */
int CFUNC_LV(void)
{
return 1;
}
double CFUNC_DV(void)
{
return 2.2;
}
char* CFUNC_SV(void)
{
return "SV";
}
void CFUNC_VV(void)
{
int fd = open("/tyCo/1",2,0);
fdprintf(fd,"VV\r\n");
close(fd);
}
/* A Single "By Value" Parameter */
int CFUNC_LL(int L)
{
L = L + 1;
return L;
}
double CFUNC_DD(double D)
{
D = D + 2.2;
return D;
}
char* CFUNC_SS(char* S)
{
strcpy(S,"SS");
return S;
}
/* A Single "By Reference" Parameter */
int CFUNC_LRL(int* L)
{
*L = *L + 3;
return *L;
}
double CFUNC_DRD(double* D)
{
*D = *D + 4.4;
return *D;
}
char* CFUNC_SRS(char** S)
{
strcpy(*S,"SRS");
return *S;
}
/* Multiple Parameters */
/* By Value Parameters */
int CFUNC_LVALP(double D, int L, char* S)
return (D + L + atoi(S)); 
} 
void CFUNC_VVALP(char* S, double D, int L)
{
int fd = open("/tyCo/1",2,0);
fdprintf(fd,"Original Values:%d, %f, %s\r\n", L, D, S);
L = 10;
D = 22.2;
strcpy(S,"VValP");
fdprintf(fd,"New Value:%d, %f, %s\r\n", L, D, S);
close(fd); 
} 
/* By Reference Parameters */
double CFUNC_DREFP(char** S, int* L, double* D)
{
return (*D + *L + atof(*S)); 
}

Special Considerations

Motion and System properties can only be passed by value.

KILLTASK will not unblock a task locked inside the C-function. An endless block on a semaphore, message queue, etc. inside a C-function prevent sa task from correct being killed. If C-function has some blocking operation system call (taskDelay(), semTake(), msgQGet(), msqQSend(), IO operation, etc.), this may interfere with killing the user task.

When an object module is loaded several times without unloading, all its instances are kept in the RAM, while the system symbol table has references only to the resent instance. MC-Basic applications may refer to the obsolete version of some modified object file.

OUNLOAD does not check to see if the object file is in use. It is your responsibility to ensure that the object is not unloaded as long as there tasks and libraries that refer to the object.

Consider following example, both the program TASK1.PRG and TASK2.PRG use the same function from object module.

-->oload my_obj.o
-->load TASK1.PRG
-->send my_obj.o ‘ send updated version of object file
-->oload my_obj.o
-->load TASK2.PRG

In this example, TASK1.PRG references the oldest instance of my_obj.o while TASK2.PRG references the recent version.