- It is a general-purpose implementation of Inter-processing communication between the Server and Client (IPC section).
- It consists mainly of the following:
- IPC library implementation source: src, include
- IPC unit test program: ipc_unit_test
- Building by following steps:
$ mkdir build $ cd build $ cmake .. $ make
- The above commands can be executed with the following script:
$ ./buildtest.sh
- The above commands can be executed with the following script:
The installation described next will be installed on the host PC (/usr/local/). To change the installation destination, change the option passed to cmake.
Example
$ cmake -DCMAKE_INSTALL_PREFIX=./install ..
$ cd build
$ sudo make install
When succeeded, the following log will be output.
[100%] Built target ipc
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/lib/pkgconfig/ipc.pc
-- Installing: /usr/local/lib/libipc.so.1.0.0
-- Installing: /usr/local/lib/libipc.so.1
-- Installing: /usr/local/lib/libipc.so
-- Installing: /usr/local/include/ipc.h
-- Installing: /usr/local/include/ipc_protocol.h
- At last, Building will generate the following:
- <installdir>/include/
(External Public header files)
ipc.h ipc_protocol.h
- <installdir>/lib/
(Shared library files)
libipc.so ( Symbolic link ) libipc.so.1 ( Symbolic link ) libipc.so.1.0.0
- build/ipc_unit_test/
(Test program executable file)
ipc_unit_test_client ipc_unit_test_server
- <installdir>/include/
(External Public header files)
- This library contains functions for Server and Client; Each has different usage.
- The user needs to link with the following libraries.
libipc.so
- User includes the library as following.
- #include <ipc.h>
- ipc_protocol.h description is not required; it described later within ipc.h (include <ipc.h>).
- #include <ipc.h>
- The header files are used as follows.
- ipc.h
- Declare a list of available API functions.
- ipc_protocol.h
- Define IPC usage types and data structures for each usage.
- ipc.h
- In libraries, Server and Client communicate using Unix Domain Socket.
- Generate different communication files for each usage type.
- By default, a communication file is generated in the execution hierarchy of the Server.
- For changing the location where generating the communication files, set the environment variable "IPC_DOMAIN_PATH"
Example) $ export IPC_DOMAIN_PATH="/tmp" →Unix Domain Socket communication files will be generated under /tmp.
- Using this library for IC-Service, use the following values and structures (see ipc_protocol.h).
- UsageType:IPC_USAGE_TYPE_IC_SERVICE
- Sending data structure:IPC_DATA_IC_SERVICE_S
- Changing type callback notification (enum):IPC_KIND_IC_SERVICE_E
- Unix Domain Socket communication File name:IpcIcService
- For IC-Service, the Cluster API library (libcluster_api.so) is the IPC Client.
- The API for Client is called from libcluster_api.so (described later)
- Server applied libipc.so can use the following APIs:
- ipcServerStart(IPC_USAGE_TYPE_E usageType);
- Starting the IPC Server for the specified usageType.
- ipcSendMessage(IPC_USAGE_TYPE_E usageType, const void* pData, signed int size);
- Sending data to the IPC Client for the specified usageType.
- Specifying address and size of the sending data by pData and size arguments.
- Sending data is stored in the Data Pool prepared on the IPC Client side.
- ipcServerStop(IPC_USAGE_TYPE_E usageType);
- Terminate the IPC Server for the specified usageType.
- ipcServerStart(IPC_USAGE_TYPE_E usageType);
- The Client applied libipc.so can use the following APIs:
- ipcClientStart(IPC_USAGE_TYPE_E usageType);
- Starting the IPC Client for the specified usageType.
- Connecting with IPC Server for the same usageType.
- ipcReadDataPool(IPC_USAGE_TYPE_E usageType, void* pData, signed int* pSize);
- Reading all data in the Data Pool for the specified usageType.
- The address where storing the read data is specified in pData. Moreover, the size of storing data is specified in pSize.
- The contents of the Data Pool output to pData, and the actual read size output to pSize.
- ipcRegisterCallback(IPC_USAGE_TYPE_E usageType, IPC_CHANGE_NOTIFY_CB changeNotifyCb);
- When receiving data from the IPC Server, register the callback function for the specified usageType, which receiving notification of which data changed to what.
- ipcClientStop(IPC_USAGE_TYPE_E usageType);
- Terminate the IPC Client for the specified usageType.
- ipcClientStart(IPC_USAGE_TYPE_E usageType);
-
Limitations
- Currently 2020/12/25, this test program connects Server and Client for IC-Service.
- The Unix domain socket communication files are generated under /tmp/ with the file name ipcIcService.
-
Since Inter processing communication takes place between ipc_unit_test_server and ipc_unit_test_client, so start each one in a separate terminal. Testing example as bellow (Manually operated):
-
Starting Server and then starting Client
(Terminal 1) $ ./ipc_unit_test_server command (h=help, q=quit):
(Terminal 2) $ ./ipc_unit_test_client command (h=help, q=quit):
At this point, the Server and Client connection for IC-Service is completed. (Executing ipcServerStart () and ipcClientStart ())
-
Editing and Sending Server data
(Terminal 1) command (h=help, q=quit):w ←★input w write command (h=help q=goto main menu):2 1 ←★input 2 1 write command (h=help q=goto main menu):70 50 ←★input 70 50 write command (h=help q=goto main menu):l ←★input 1 ★Sending data list is displayed, the result of input contents as below. 2: brake(4) = 1 ←★write command 2 1 result 70: oTempUnitVal(4) = 50 ←★write command 70 50 result write command (h=help q=goto main menu):q ←★input q command (h=help, q=quit):s ←★input s (Executing ipcSendMessage()) ipcSendMessage return:0 command (h=help, q=quit):
On the Client side, The callback function should be responding.
(Terminal 2) command (h=help, q=quit):Enter changeNotifyCb ←★callback kind = 2, size = 4, data=1 ←★Notification of brake value changed to 1 Leave changeNotifyCb
★oFor TempUnitVal change as an IC-Service, there is no callback since it is not monitored.
-
Check Client side receiving.
(Terminal 2) command (h=help, q=quit):r ←★input r ★Sending data list is displayed, Sending data contained as bellow. 2: brake(4) = 1 70: oTempUnitVal(4) = 50
-
Exit Client then Server.
(Terminal 2) command (h=help, q=quit):q bye... $
(Terminal 1) command (h=help, q=quit):q bye... $
-
- First, the implementation only for IC-Service, but configured to add data for other services easily.
- Information for each usage type is managed in the following files:
- include/ipc_protocol.h (External Public header)
- src/ipc_usage_info_table.c (IPC Internal Source)
- Adding information for new service or changing information for existed service only by two files above.
- No changes are required other than .c or .h files in ipc.
- However, Regarding the application and test program used IPC, It is necessary to take measures according to the adding/changing of the ipc_protocol.h definition.
- Ideally, code can be generated automatically using tools and else. We do not consider that implementation this time.
First, the sample code for adding/changing two files as follow.
The following example shows differences when adding the temporary usage type NEW_SERVICE. (Parameters influenced when adding new usage type within the IPC)
diff --git a/include/ipc_protocol.h b/include/ipc_protocol.h
index c0ad861..2bc1115 100644
--- a/include/ipc_protocol.h
+++ b/include/ipc_protocol.h
@@ -6,6 +6,7 @@
typedef enum {
IPC_USAGE_TYPE_IC_SERVICE = 0,
IPC_USAGE_TYPE_FOR_TEST,
+ IPC_USAGE_TYPE_NEW_SERVICE, // Adding usage type
IPC_USAGE_TYPE_MAX
} IPC_USAGE_TYPE_E;
@@ -145,4 +146,17 @@ typedef struct {
signed int test;
} IPC_DATA_FOR_TEST_S;
+// for IPC_USAGE_TYPE_NEW_SERVICE
+typedef enum { // Preparing only the type which we want to monitor/notify data change
+ IPC_KIND_NS_PARAM1 = 0,
+ IPC_KIND_NS_PARAM2
+} IPC_KIND_NEW_SERVICE_E;
+
+typedef struct { // This part for sending and receiving all data
+ int param1;
+ int param2;
+ int param3;
+ int param4;
+} IPC_DATA_NEW_SERVICE_S;
+
#endif // IPC_PROTOCOL_H
diff --git a/src/ipc_usage_info_table.c b/src/ipc_usage_info_table.c
index 976cc73..51264c6 100644
--- a/src/ipc_usage_info_table.c
+++ b/src/ipc_usage_info_table.c
@@ -51,16 +51,24 @@ static IPC_CHECK_CHANGE_INFO_S g_ipcCheckChangeForTest[] = {
DEFINE_OFFSET_SIZE(IPC_DATA_FOR_TEST_S, test, IPC_KIND_TEST_TEST)
};
+// for IPC_USAGE_TYPE_FOR_TEST
+static IPC_CHECK_CHANGE_INFO_S g_ipcCheckChangeNewService[] = { // Describing only the type which we want to monitor/notify data change
+ DEFINE_OFFSET_SIZE(IPC_DATA_NEW_SERVICE_S, param1, IPC_KIND_NS_PARAM1),
+ DEFINE_OFFSET_SIZE(IPC_DATA_NEW_SERVICE_S, param2, IPC_KIND_NS_PARAM2)
+}; //This example not monitoring/notifying changes of param3, param4 data
+
// == usage info table ==
// index of [] is IPC_USAGE_TYPE_E
IPC_DOMAIN_INFO_S g_ipcDomainInfoList[] =
{
{sizeof(IPC_DATA_IC_SERVICE_S), "ipcIcService"},
- {sizeof(IPC_DATA_FOR_TEST_S), "ipcForTest"}
+ {sizeof(IPC_DATA_FOR_TEST_S), "ipcForTest"},
+ {sizeof(IPC_DATA_NEW_SERVICE_S), "ipcNewService"} // add sending/receiving size information for new Service
};
IPC_CHECK_CHANGE_INFO_TABLE_S g_ipcCheckChangeInfoTbl[] = {
DEFINE_CHANGE_INFO_TABLE(g_ipcCheckChangeIcService),
- DEFINE_CHANGE_INFO_TABLE(g_ipcCheckChangeForTest)
+ DEFINE_CHANGE_INFO_TABLE(g_ipcCheckChangeForTest),
+ DEFINE_CHANGE_INFO_TABLE(g_ipcCheckChangeNewService) // Registering data change monitoring table for new Service
};
The following example shows differences when deleting the member variable brake from usage sending/receiving data of existing IC-Service. (Parameters influenced when a member variable is deleted within the IPC)
diff --git a/include/ipc_protocol.h b/include/ipc_protocol.h
index c0ad861..7fed8bf 100644
--- a/include/ipc_protocol.h
+++ b/include/ipc_protocol.h
@@ -13,7 +13,6 @@ typedef enum {
typedef enum {
IPC_KIND_ICS_TURN_R = 0,
IPC_KIND_ICS_TURN_L,
- IPC_KIND_ICS_BRAKE,
IPC_KIND_ICS_SEATBELT,
IPC_KIND_ICS_HIGHBEAM,
IPC_KIND_ICS_DOOR,
@@ -51,7 +50,6 @@ typedef struct {
// Telltale
signed int turnR;
signed int turnL;
- signed int brake;
signed int seatbelt;
signed int frontRightSeatbelt;
signed int frontCenterSeatbelt;
diff --git a/src/ipc_usage_info_table.c b/src/ipc_usage_info_table.c
index 976cc73..40ac8df 100644
--- a/src/ipc_usage_info_table.c
+++ b/src/ipc_usage_info_table.c
@@ -12,7 +12,6 @@
static IPC_CHECK_CHANGE_INFO_S g_ipcCheckChangeIcService[] = {
DEFINE_OFFSET_SIZE(IPC_DATA_IC_SERVICE_S, turnR, IPC_KIND_ICS_TURN_R),
DEFINE_OFFSET_SIZE(IPC_DATA_IC_SERVICE_S, turnL, IPC_KIND_ICS_TURN_L),
- DEFINE_OFFSET_SIZE(IPC_DATA_IC_SERVICE_S, brake, IPC_KIND_ICS_BRAKE),
DEFINE_OFFSET_SIZE(IPC_DATA_IC_SERVICE_S, seatbelt, IPC_KIND_ICS_SEATBELT),
DEFINE_OFFSET_SIZE(IPC_DATA_IC_SERVICE_S, highbeam, IPC_KIND_ICS_HIGHBEAM),
DEFINE_OFFSET_SIZE(IPC_DATA_IC_SERVICE_S, door, IPC_KIND_ICS_DOOR),
- Adding some new enumerations/structures, with addition to existing enumeration/structure. There are no restrictions on the names.
- For one usage type, adding the following three items of information.
- Add usage type name.
- For new usage, Define enumeration for the change notification type.
- For new usage, Define sending/receiving data structure.
- Adding usage type name
- Sample code of this part will be as follow:
typedef enum { IPC_USAGE_TYPE_IC_SERVICE = 0, IPC_USAGE_TYPE_FOR_TEST, + IPC_USAGE_TYPE_NEW_SERVICE, // Adding usage type IPC_USAGE_TYPE_MAX } IPC_USAGE_TYPE_E;
- Adding a member for the usage type in enum IPC_USAGE_TYPE_E.
- Make sure to add it just before IPC_USAGE_TYPE_MAX (Avoiding effect on existing definitions)
- The value defined here is used to specify the argument usageType such as ipcServerStart() defined in ipc.h.
- Sample code of this part will be as follow:
- For new usage, Define enumeration for the change notification type.
- Sample code of this part will be as follow:
+typedef enum { // Preparing only the type which we want to monitor data change + IPC_KIND_NS_PARAM1 = 0, + IPC_KIND_NS_PARAM2 +} IPC_KIND_NEW_SERVICE_E;
- Adding an enumeration for the data change notification type. Related to the sending/receiving data structures will describe next.
- This value is used to specify the third argument kind of callback function registered by ipcRegisterCallback().
- There are no restrictions for naming enumeration and member.
- Sample code of this part will be as follow:
- For new usage, Define sending/receiving data structure.
- Sample code of this part will be as follow:
+typedef struct { // This part for sending and receiving all data + int param1; + int param2; + int param3; + int param4; +} IPC_DATA_NEW_SERVICE_S;
- For new usage, adding send/receive data structures.
- The IPC Server will send all the data in the defined structure to the IPC Client.
- Sample code of this part will be as follow:
-
For one usage type, adding the following three items of information.
- Add a type mapping table for data change notification.
- Add communication domain information (Communication size and file name).
- Add mapping table for a relationship between usage and change type.
-
Add a type mapping table for data change notification.
- Sample code of this part will be as follow:
+// for IPC_USAGE_TYPE_FOR_TEST +static IPC_CHECK_CHANGE_INFO_S g_ipcCheckChangeNewService[] = { // Preparing only the type which we want to monitor data change + DEFINE_OFFSET_SIZE(IPC_DATA_NEW_SERVICE_S, param1, IPC_KIND_NS_PARAM1), + DEFINE_OFFSET_SIZE(IPC_DATA_NEW_SERVICE_S, param2, IPC_KIND_NS_PARAM2) +}; // This example not monitoring/notifying changes of param3, param4 data
- For new usage, add a structure array of IPC_CHECK_CHANGE_INFO_S.
- Describing a table that maps the definition of change notification type enumeration (defined in ipc_protocol.h) with the data structure members.
- This table is used for Callback notification of the last receiving data type change when the IPC Client received data from the IPC Server.
- In structure array, describing multiple macros which defining matching as shown below.
DEFINE_OFFSET_SIZE(<Data structure name>, <Structure member name>, Change notification enumeration member name),
- In the case of the above sample code, g_ipcCheckChangeNewService[] will be as follows.
- If the value of param1 is different from the value of the previous receiving, the callback change type IPC_KIND_NS_PARAM1 is notified to the IPC Client.
- If the value of param2 is different from the value of the previous receiving, the callback change type IPC_KIND_NS_PARAM2 is notified to the IPC Client.
- For param3 and param4 are not described, the callback does not notify even if the value of the previous receiving is different.
- Sample code of this part will be as follow:
-
Add communication domain information (Communication size and file name).
- Sample code of this part will be as follow:
IPC_DOMAIN_INFO_S g_ipcDomainInfoList[] = { {sizeof(IPC_DATA_IC_SERVICE_S), "ipcIcService"}, - {sizeof(IPC_DATA_FOR_TEST_S), "ipcForTest"} + {sizeof(IPC_DATA_FOR_TEST_S), "ipcForTest"}, + {sizeof(IPC_DATA_NEW_SERVICE_S), "ipcNewService"} //add sending/receiving size information for new Service };
- In structure array g_ipcDomainInfoList[], adding the domain information for new usage.
- This addition determines the sending/receiving data size used for the newly added usage type and Domain file name used for Unix Domain Socket communication.
- It is necessary to match the definition order of the enum IPC_USAGE_TYPE_E of ipc_protocol.h, so ensure adding it at the end.
- Add communication data size structure and the domain filename information to the end of g_ipcDomainInfoList[], as follows:
{sizeof(<communication data structure name>), "domain file name"},
- Sample code of this part will be as follow:
-
Add mapping table for a relationship between usage and change type.
- Sample code of this part will be as follow:
IPC_CHECK_CHANGE_INFO_TABLE_S g_ipcCheckChangeInfoTbl[] = {i DEFINE_CHANGE_INFO_TABLE(g_ipcCheckChangeIcService), - DEFINE_CHANGE_INFO_TABLE(g_ipcCheckChangeForTest) + DEFINE_CHANGE_INFO_TABLE(g_ipcCheckChangeForTest), + DEFINE_CHANGE_INFO_TABLE(g_ipcCheckChangeNewService) // Registering data change monitoring table for new service };
- In structure array g_ipcCheckChangeInfoTbl[], adding information about the mapping table for a relationship between new usage and change notification type.
- It is necessary to match the definition order of the enum IPC_USAGE_TYPE_E of ipc_protocol.h, so ensure adding it at the end.
- Describing the above-mentioned "change notification type mapping table structure" in the following macro, then add it to the end of g_ipcCheckChangeInfoTbl[].
DEFINE_CHANGE_INFO_TABLE(<change notification type mapping table structure name>),
- Sample code of this part will be as follow:
-
When deleting or renaming a member variable in an existing sending data structure in ipc_protocol.h
- Trying to build each ipc part and application that uses ipc for the service, then fix the part that causing the Compile error.
-
When adding a member variable in an existing sending data structure in ipc_protocol.h
- Refer to Adding/Changing IPC usage type method, add it to include/ipc_protocol.h and src/ipc_usage_info_table.c.
- In src/ipc_usage_info_table.c, the information is described in the DEFINE_OFFSET_SIZE() macro, which using offsetof() and sizeof() to get the offset and size of member variables from the head of the related structure.
- In order to make it easier to add usage types, the IPC process does not directly specify variable names in data structures.
- For each usage, by preparing an offset table of the data structure, it becomes possible to know what variables are in which byte of the sending data.
- This structure makes it possible to check data change without directly specifying the member variable name inside the IPC process.
- Adding the usage type according to Adding/Changing IPC usage type method, the IPC inter processing can process new usage.