From 2d3ab68c60e8bacf9e0efe403895e7065ef683be Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Thu, 12 Mar 2015 15:35:13 +0100 Subject: Update Interoperability Tutorial Language cleaned up by the technical writers xsipewe and tmanevik from Combitech. Proofreading and corrections by Hans Bolinder. --- system/doc/tutorial/erl_interface.xmlsrc | 108 +++++++++++++++++++++++-------- 1 file changed, 82 insertions(+), 26 deletions(-) (limited to 'system/doc/tutorial/erl_interface.xmlsrc') diff --git a/system/doc/tutorial/erl_interface.xmlsrc b/system/doc/tutorial/erl_interface.xmlsrc index 0c4c5a99c2..5751a945d6 100644 --- a/system/doc/tutorial/erl_interface.xmlsrc +++ b/system/doc/tutorial/erl_interface.xmlsrc @@ -4,7 +4,7 @@
- 20002013 + 20002015 Ericsson AB. All Rights Reserved. @@ -28,14 +28,29 @@ erl_interface.xml
-

This is an example of how to solve the example problem by using a port and erl_interface. It is necessary to read the port example before reading this chapter.

+ +

This section outlines an example of how to solve the example + problem in Problem Example by + using a port and Erl_Interface. It is necessary to read the port + example in Ports before reading + this section.

Erlang Program -

The example below shows an Erlang program communicating with a C program over a plain port with home made encoding.

- -

Compared to the Erlang module - above used for the plain port, there are two differences when using Erl_Interface on the C side: Since Erl_Interface operates on the Erlang external term format the port must be set to use binaries and, instead of inventing an encoding/decoding scheme, the BIFs term_to_binary/1 and binary_to_term/1 should be used. That is:

+

The following example shows an Erlang program communicating + with a C program over a plain port with home made encoding:

+ +

There are two differences when using Erl_Interface on the C + side compared to the example in + Ports, using only the plain port:

+ + As Erl_Interface operates on the Erlang external term format, + the port must be set to use binaries. + Instead of inventing an encoding/decoding scheme, the + term_to_binary/1 and binary_to_term/1 BIFs are to + be used. + +

That is:

 open_port({spawn, ExtPrg}, [{packet, 2}])

is replaced with:

@@ -55,69 +70,110 @@ receive {Port, {data, Data}} -> Caller ! {complex, binary_to_term(Data)} end -

The resulting Erlang program is shown below.

+

The resulting Erlang program is as follows:

-

Note that calling complex2:foo/1 and complex2:bar/1 will result in the tuple {foo,X} or {bar,Y} being sent to the complex process, which will code them as binaries and send them to the port. This means that the C program must be able to handle these two tuples.

+

Notice that calling complex2:foo/1 and + complex2:bar/1 results in the tuple {foo,X} or + {bar,Y} being sent to the complex process, which + codes them as binaries and sends them to the port. This means + that the C program must be able to handle these two tuples.

C Program -

The example below shows a C program communicating with an Erlang program over a plain port with home made encoding.

+

The following example shows a C program communicating with an + Erlang program over a plain port with home made encoding:

-

Compared to the C program above - used for the plain port the while-loop must be rewritten. Messages coming from the port will be on the Erlang external term format. They should be converted into an ETERM struct, a C struct similar to an Erlang term. The result of calling foo() or bar() must be converted to the Erlang external term format before being sent back to the port. But before calling any other erl_interface function, the memory handling must be initiated.

+

Compared to the C program in + Ports, using only the plain port, the + while-loop must be rewritten. Messages coming from the + port is on the Erlang external term format. They must be + converted into an ETERM struct, which is a C struct + similar to an Erlang term. The result of calling foo() or + bar() must be converted to the Erlang external term + format before being sent back to the port. But before calling + any other Erl_Interface function, the memory handling must be + initiated:

 erl_init(NULL, 0);
-

For reading from and writing to the port the functions read_cmd() and write_cmd() from the erl_comm.c example below - can still be used. +

The following functions, read_cmd() and + write_cmd(), from the erl_comm.c example in + Ports can still be + used for reading from and writing to the port:

-

The function erl_decode() from erl_marshal will convert the binary into an ETERM struct.

+

The function erl_decode() from erl_marshal + converts the binary into an ETERM struct:

 int main() {
   ETERM *tuplep;
 
   while (read_cmd(buf) > 0) {
     tuplep = erl_decode(buf);
-

In this case tuplep now points to an ETERM struct representing a tuple with two elements; the function name (atom) and the argument (integer). By using the function erl_element() from erl_eterm it is possible to extract these elements, which also must be declared as pointers to an ETERM struct.

+

Here, tuplep points to an ETERM struct + representing a tuple with two elements; the function name (atom) + and the argument (integer). Using the function + erl_element() from erl_eterm, these elements can + be extracted, but they must also be declared as pointers to an + ETERM struct:

     fnp = erl_element(1, tuplep);
     argp = erl_element(2, tuplep);
-

The macros ERL_ATOM_PTR and ERL_INT_VALUE from erl_eterm can be used to obtain the actual values of the atom and the integer. The atom value is represented as a string. By comparing this value with the strings "foo" and "bar" it can be decided which function to call.

+

The macros ERL_ATOM_PTR and ERL_INT_VALUE from + erl_eterm can be used to obtain the actual values of the + atom and the integer. The atom value is represented as a string. + By comparing this value with the strings "foo" and "bar", it can + be decided which function to call:

     if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) {
       res = foo(ERL_INT_VALUE(argp));
     } else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 3) == 0) {
       res = bar(ERL_INT_VALUE(argp));
     }
-

Now an ETERM struct representing the integer result can be constructed using the function erl_mk_int() from erl_eterm. It is also possible to use the function erl_format() from the module erl_format.

+

Now an ETERM struct that represents the integer result + can be constructed using the function erl_mk_int() from + erl_eterm. The function + erl_format() from the module erl_format can also + be used:

     intp = erl_mk_int(res);
-

The resulting ETERM struct is converted into the Erlang external term format using the function erl_encode() from erl_marshal and sent to Erlang using write_cmd().

+

The resulting ETERM struct is converted into the Erlang + external term format using the function erl_encode() from + erl_marshal and sent to Erlang using + write_cmd():

     erl_encode(intp, buf);
     write_cmd(buf, erl_eterm_len(intp));
-

Last, the memory allocated by the ETERM creating functions must be freed.

+

Finally, the memory allocated by the ETERM creating + functions must be freed:

     erl_free_compound(tuplep);
     erl_free_term(fnp);
     erl_free_term(argp);
     erl_free_term(intp);
-

The resulting C program is shown below:

+

The resulting C program is as follows:

Running the Example -

1. Compile the C code, providing the paths to the include files erl_interface.h and ei.h, and to the libraries erl_interface and ei.

+

Step 1. Compile the C code. This provides the paths to + the include files erl_interface.h and ei.h, and + also to the libraries erl_interface and ei:

 unix> gcc -o extprg -I/usr/local/otp/lib/erl_interface-3.2.1/include \\ 
       -L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ 
       complex.c erl_comm.c ei.c -lerl_interface -lei
-

In R5B and later versions of OTP, the include and lib directories are situated under OTPROOT/lib/erl_interface-VSN, where OTPROOT is the root directory of the OTP installation (/usr/local/otp in the example above) and VSN is the version of the erl_interface application (3.2.1 in the example above).

- - In R4B and earlier versions of OTP, include and lib are situated under OTPROOT/usr.

-

2. Start Erlang and compile the Erlang code.

+

In Erlang/OTP R5B and later versions of OTP, the include + and lib directories are situated under + OTPROOT/lib/erl_interface-VSN, where OTPROOT is + the root directory of the OTP installation + (/usr/local/otp in the recent example) and VSN is + the version of the Erl_interface application (3.2.1 in the + recent example).

+

In R4B and earlier versions of OTP, include and lib + are situated under OTPROOT/usr.

+

Step 2. Start Erlang and compile the Erlang code:

 unix> erl
 Erlang (BEAM) emulator version 4.9.1.2
@@ -125,7 +181,7 @@ Erlang (BEAM) emulator version 4.9.1.2
 Eshell V4.9.1.2 (abort with ^G)
 1> c(complex2).
 {ok,complex2}
-

3. Run the example.

+

Step 3. Run the example:

 2> complex2:start("extprg").
 <0.34.0>
-- 
cgit v1.2.3