MC-Basic C-Interface

From SoftMC-Wiki
Revision as of 15:06, 5 June 2014 by Nurit (talk | contribs) (Prototype File)
Jump to: navigation, search

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). There is also an option to wrire prototypes in library files, within the declarations section, instead of using the PROTO.PRO file. 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- , string-, joint- and location-type parameters. The parameters may be passed “by value” or “by reference”.

The returned value may be long, double, string, joint, location 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_DV(void);
import_c cFunc_SV As String SYS_STRING* CFUNC_SV(void);
import_c cFunc_PV As Joint Of XYZR SYS_POINT* CFUNC_PV(void);
import_c cFunc_GPV As Generic Location SYS_POINT* CFUNC_GPV(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 SYS_STRING* CFUNC_SRS(SYS_STRING** S);
import_c cFunc_PRP(As Joint Of XY) As Location Of XYZ SYS_POINT* CFUNC_PRP(SYS_STRING** P);
import_c cFunc_GPRGP(As Generic Location) As Generic Joint SYS_POINT* CFUNC_GPRGP(SYS_STRING** P);
Import_C cFunc_LARD([*] as Long) as Double double CFUNC_LARD(long *l);
import_c cFunc_SS(ByVal As String) As String SYS_STRING* CFUNC_SS(SYS_STRING* S);
import_c cFunc_PGP(ByVal As Generic Joint) As Location Of XYZ SYS_POINT* CFUNC_PP(SYS_POINT* P);
import_c cFunc_GPP(ByVal As Location Of XY) As Generic Joint SYS_POINT* CFUNC_GPGP(SYS_POINT* P);

Parameters can be of type long, double, string, joint or location; 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_PV() As Location Of XYZ
import_c CFUNC_GPV() As Generic Joint
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
import_c CFUNC_PP(ByVal As Joint of XY) As Location Of XYZ
import_c CFUNC_GPP(ByVal As Generic Location) As Generic Joint
'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
import_c CFUNC_PRP(As Joint of XY) As Location Of XYZ
import_c CFUNC_GPRP(As Generic Location) As Generic Joint
'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 (e.g., puting a task to sleep, taking a semaphore, passing messages through a message queue, 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.