Добавлена реализация контроллера, для работы с физическим роботом

This commit is contained in:
Даниил Грабарь
2025-11-21 16:32:53 +10:00
parent b8905b1bca
commit 7bc2a21575
50 changed files with 8458 additions and 1 deletions
+8
View File
@@ -1,3 +1,11 @@
Подмена файла по пути обязательна: `/opt/ros/rolling/lib/webots_ros2_driver/ros2_supervisor.py` Подмена файла по пути обязательна: `/opt/ros/rolling/lib/webots_ros2_driver/ros2_supervisor.py`
> необходимо `warn` заменить на `warning` в логере > необходимо `warn` заменить на `warning` в логере
```bash
sudo apt install -y ros-${ROS_DISTRO}-webots-ros2 \
ros-${ROS_DISTRO}-ros2-control \
ros-${ROS_DISTRO}-ros2-controllers \
ros-${ROS_DISTRO}-moveit-* \
```
+104
View File
@@ -0,0 +1,104 @@
cmake_minimum_required(VERSION 3.8)
project(iiwa_controller)
# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
find_package(ament_cmake REQUIRED)
find_package(hardware_interface REQUIRED)
find_package(pluginlib REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclcpp_lifecycle REQUIRED)
find_package(Eigen3 REQUIRED)
# FRI headers / sources
set(FRI_HEADER
external/libFRI/include
external/libFRI/src/protobuf_gen
external/libFRI/src/nanopb-0.2.8
external/libFRI/src/protobuf
external/libFRI/src/connection
external/libFRI/src/client_lbr
external/libFRI/src/base
)
set(FRI_SRC
external/libFRI/src/base/friClientApplication.cpp
external/libFRI/src/client_lbr/friLBRClient.cpp
external/libFRI/src/client_lbr/friLBRCommand.cpp
external/libFRI/src/client_lbr/friLBRState.cpp
external/libFRI/src/connection/friUdpConnection.cpp
external/libFRI/src/protobuf/friCommandMessageEncoder.cpp
external/libFRI/src/protobuf/friMonitoringMessageDecoder.cpp
external/libFRI/src/protobuf/pb_frimessages_callbacks.c
external/libFRI/src/protobuf_gen/FRIMessages.pb.c
external/libFRI/src/nanopb-0.2.8/pb_decode.c
external/libFRI/src/nanopb-0.2.8/pb_encode.c
external/libFRI/src/client_trafo/friTransformationClient.cpp
)
add_library(${PROJECT_NAME}
SHARED
src/IIWAHardwareInterface.cpp
${FRI_SRC}
src/FRIClient.cpp
)
target_include_directories(${PROJECT_NAME}
PRIVATE
include
${FRI_HEADER}
)
target_compile_definitions(${PROJECT_NAME}
PRIVATE
PB_FIELD_16BIT
HAVE_SOCKLEN_T
PB_FIELD_16BIT
PB_NO_ERRMSG
)
target_link_libraries(${PROJECT_NAME}
PUBLIC
hardware_interface::hardware_interface
pluginlib::pluginlib
rclcpp::rclcpp
rclcpp_lifecycle::rclcpp_lifecycle
Eigen3::Eigen
)
# Export plugin description for pluginlib
pluginlib_export_plugin_description_file(hardware_interface iiwa_controller_plugin.xml)
# Installation
install(TARGETS ${PROJECT_NAME}
DESTINATION lib
)
install(
DIRECTORY include/
DESTINATION include
)
ament_export_include_directories(
include
)
ament_export_libraries(
${PROJECT_NAME}
)
ament_export_dependencies(
hardware_interface
pluginlib
rclcpp
rclcpp_lifecycle
Eigen3
)
ament_package()
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -0,0 +1,155 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#ifndef _KUKA_FRI_CLIENT_APPLICATION_H
#define _KUKA_FRI_CLIENT_APPLICATION_H
/** Kuka namespace */
namespace KUKA
{
/** Fast Robot Interface (FRI) namespace */
namespace FRI
{
// forward declarations
class IClient;
class TransformationClient;
class IConnection;
struct ClientData;
/**
* \brief FRI client application class.
*
* A client application takes an instance of the IConnection interface and
* an instance of an IClient interface to provide the functionality
* needed to set up an FRI client application. It can be used to easily
* integrate the FRI client code within other applications.
* The algorithmic functionality of an FRI client application is implemented
* using the IClient interface.
*/
class ClientApplication
{
public:
/**
* \brief Constructor without transformation client.
*
* This constructor takes an instance of the IConnection interface and
* an instance of the IClient interface as parameters.
* @param connection FRI connection class
* @param client FRI client class
*/
ClientApplication(IConnection& connection, IClient& client);
/**
* \brief Constructor with transformation client.
*
* This constructor takes an instance of the IConnection interface and
* an instance of the IClient interface and an instance of a
* TransformationClient as parameters.
* @param connection FRI connection class
* @param client FRI client class
* @param trafoClient FRI transformation client class
*/
ClientApplication(IConnection& connection, IClient& client, TransformationClient& trafoClient);
/** \brief Destructor. */
~ClientApplication();
/**
* \brief Connect the FRI client application with a KUKA Sunrise controller.
*
* @param port The port ID
* @param remoteHost The address of the remote host
* @return True if connection was established
*/
bool connect(int port, const char *remoteHost = NULL);
/**
* \brief Disconnect the FRI client application from a KUKA Sunrise controller.
*/
void disconnect();
/**
* \brief Run a single processing step.
*
* The processing step consists of receiving a new FRI monitoring message,
* calling the corresponding client callback and sending the resulting
* FRI command message back to the KUKA Sunrise controller.
* @return True if all of the substeps succeeded.
*/
bool step();
protected:
IConnection& _connection; //!< connection interface
IClient* _robotClient; //!< robot client interface
TransformationClient* _trafoClient; //!< transformation client interface
ClientData* _data; //!< client data structure (for internal use)
};
}
}
#endif // _KUKA_FRI_CLIENT_APPLICATION_H
@@ -0,0 +1,202 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#ifndef _KUKA_FRI_CLIENT_H
#define _KUKA_FRI_CLIENT_H
/** Kuka namespace */
namespace KUKA
{
/** Fast Robot Interface (FRI) namespace */
namespace FRI
{
// forward declarations
struct ClientData;
/** \brief Enumeration of the FRI session state. */
enum ESessionState
{
IDLE = 0, //!< no session available
MONITORING_WAIT = 1, //!< monitoring mode with insufficient connection quality
MONITORING_READY = 2, //!< monitoring mode with connection quality sufficient for command mode
COMMANDING_WAIT = 3, //!< command mode about to start (overlay motion queued)
COMMANDING_ACTIVE = 4 //!< command mode active
};
/** \brief Enumeration of the FRI connection quality. */
enum EConnectionQuality
{
POOR = 0, //!< poor connection quality
FAIR = 1, //!< connection quality insufficient for command mode
GOOD = 2, //!< connection quality sufficient for command mode
EXCELLENT = 3 //!< excellent connection quality
};
/** \brief Enumeration of the controller's safety state. */
enum ESafetyState
{
NORMAL_OPERATION = 0, //!< No safety stop request present.
SAFETY_STOP_LEVEL_0 = 1,//!< Safety stop request STOP0 or STOP1 present.
SAFETY_STOP_LEVEL_1 = 2,//!< Safety stop request STOP1 (on-path) present.
SAFETY_STOP_LEVEL_2 = 3 //!< Safety stop request STOP2 present.
};
/** \brief Enumeration of the controller's current mode of operation. */
enum EOperationMode
{
TEST_MODE_1 = 0, //!< test mode 1 with reduced speed (T1)
TEST_MODE_2 = 1, //!< test mode 2 (T2)
AUTOMATIC_MODE = 2 //!< automatic operation mode (AUT)
};
/** \brief Enumeration of a drive's state. */
enum EDriveState
{
OFF = 0, //!< drive is not being used
TRANSITIONING = 1, //!< drive is in a transitioning state (before or after motion)
ACTIVE = 2 //!< drive is being actively commanded
};
/** \brief Enumeration of control mode. */
enum EControlMode
{
POSITION_CONTROL_MODE = 0, //!< position control mode
CART_IMP_CONTROL_MODE = 1, //!< cartesian impedance control mode
JOINT_IMP_CONTROL_MODE = 2, //!< joint impedance control mode
NO_CONTROL = 3 //!< drives are not used
};
/** \brief Enumeration of the client command mode. */
enum EClientCommandMode
{
NO_COMMAND_MODE = 0, //!< no client command mode available
POSITION = 1, //!< commanding joint positions by the client
WRENCH = 2, //!< commanding wrenches and joint positions by the client
TORQUE = 3 //!< commanding joint torques and joint positions by the client
};
/** \brief Enumeration of the overlay type. */
enum EOverlayType
{
NO_OVERLAY = 0, //!< no overlay type available
JOINT = 1, //!< joint overlay
CARTESIAN = 2 //!< cartesian overlay
};
/**
* \brief FRI client interface.
*
* This is the callback interface that should be implemented by FRI clients.
* Callbacks are automatically called by the client application
* (ClientApplication) whenever new FRI messages arrive.
*/
class IClient
{
friend class ClientApplication;
public:
/** \brief Virtual destructor. */
virtual ~IClient() {}
/**
* \brief Callback that is called whenever the FRI session state changes.
*
* @param oldState previous FRI session state
* @param newState current FRI session state
*/
virtual void onStateChange(ESessionState oldState, ESessionState newState) = 0;
/**
* \brief Callback for the FRI session states 'Monitoring Wait' and 'Monitoring Ready'.
*/
virtual void monitor() = 0;
/**
* \brief Callback for the FRI session state 'Commanding Wait'.
*/
virtual void waitForCommand() = 0;
/**
* \brief Callback for the FRI session state 'Commanding'.
*/
virtual void command() = 0;
protected:
/**
* \brief Method to create and initialize the client data structure (used internally).
*
* @return newly allocated client data structure
*/
virtual ClientData* createData() = 0;
};
}
}
#endif // _KUKA_FRI_CLIENT_H
@@ -0,0 +1,130 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#ifndef _KUKA_FRI_CONNECTION_H
#define _KUKA_FRI_CONNECTION_H
/** Kuka namespace */
namespace KUKA
{
namespace FRI
{
/**
* \brief FRI connection interface.
*
* Connections to the KUKA Sunrise controller have to be implemented using
* this interface.
*/
class IConnection
{
public:
/** \brief Virtual destructor. */
virtual ~IConnection() {}
/**
* \brief Open a connection to the KUKA Sunrise controller.
*
* @param port The port ID
* @param remoteHost The address of the remote host
* @return True if connection was established
*/
virtual bool open(int port, const char *remoteHost) = 0;
/**
* \brief Close a connection to the KUKA Sunrise controller.
*/
virtual void close() = 0;
/**
* \brief Checks whether a connection to the KUKA Sunrise controller is established.
*
* @return True if connection is established
*/
virtual bool isOpen() const = 0;
/**
* \brief Receive a new FRI monitoring message from the KUKA Sunrise controller.
*
* This method blocks until a new message arrives.
* @param buffer Pointer to the allocated buffer that will hold the FRI message
* @param maxSize Size in bytes of the allocated buffer
* @return Number of bytes received (0 when connection was terminated, negative in case of errors)
*/
virtual int receive(char *buffer, int maxSize) = 0;
/**
* \brief Send a new FRI command message to the KUKA Sunrise controller.
*
* @param buffer Pointer to the buffer holding the FRI message
* @param size Size in bytes of the message to be send
* @return True if successful
*/
virtual bool send(const char* buffer, int size) = 0;
};
}
}
#endif // _KUKA_FRI_CONNECTION_H
@@ -0,0 +1,153 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#ifndef _KUKA_FRI_EXCEPTION_H
#define _KUKA_FRI_EXCEPTION_H
#include "stdio.h"
/** Kuka namespace */
namespace KUKA
{
namespace FRI
{
/**
* \brief Standard exception for the FRI Client
*
* \note For realtime considerations the internal message buffer is static.
* So don't use this exception in more than one thread per process.
*/
class FRIException
{
public:
/**
* \brief FRIException Constructor
*
* @param message Error message
*/
FRIException(const char* message)
{
strncpy(_buffer, message, sizeof(_buffer) - 1);
_buffer[sizeof(_buffer) - 1] = 0; // ensure string termination
printf("FRIException: ");
printf(_buffer);
printf("\n");
}
/**
* \brief FRIException Constructor
*
* @param message Error message which may contain one "%s" parameter
* @param param1 First format parameter for parameter message.
*/
FRIException(const char* message, const char* param1)
{
#ifdef _MSC_VER
_snprintf( // visual studio compilers (up to VS 2013) only know this method
#else
snprintf(
#endif
_buffer, sizeof(_buffer), message, param1);
printf("FRIException: ");
printf(_buffer);
printf("\n");
}
/**
* \brief FRIException Constructor
*
* @param message Error message which may contain two "%s" parameter
* @param param1 First format parameter for parameter message.
* @param param2 Second format parameter for parameter message.
*/
FRIException(const char* message, const char* param1, const char* param2)
{
#ifdef _MSC_VER
_snprintf( // visual studio compilers (up to VS 2013) only know this method
#else
snprintf(
#endif
_buffer, sizeof(_buffer), message, param1, param2);
printf("FRIException: ");
printf(_buffer);
printf("\n");
}
/**
* \brief Get error string.
* @return Error message stored in the exception.
*/
const char* getErrorMessage() const { return _buffer; }
/** \brief Virtual destructor. */
virtual ~FRIException() {}
protected:
static char _buffer[1024];
};
}
}
#endif // _KUKA_FRI_EXCEPTION_H
@@ -0,0 +1,145 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#ifndef _KUKA_FRI_LBR_CLIENT_H
#define _KUKA_FRI_LBR_CLIENT_H
#include "friClientIf.h"
#include "friLBRState.h"
#include "friLBRCommand.h"
/** Kuka namespace */
namespace KUKA
{
namespace FRI
{
/**
* \brief Implementation of the IClient interface for the KUKA LBR (lightweight) robots.
*
* Provides access to the current LBR state and the possibility to send new
* commands to the LBR.
*/
class LBRClient : public IClient
{
public:
/** \brief Constructor. */
LBRClient();
/** \brief Destructor. */
~LBRClient();
/**
* \brief Callback that is called whenever the FRI session state changes.
*
* @param oldState previous FRI session state
* @param newState current FRI session state
*/
virtual void onStateChange(ESessionState oldState, ESessionState newState);
/**
* \brief Callback for the FRI session states 'Monitoring Wait' and 'Monitoring Ready'.
*/
virtual void monitor();
/**
* \brief Callback for the FRI session state 'Commanding Wait'.
*/
virtual void waitForCommand();
/**
* \brief Callback for the FRI session state 'Commanding'.
*/
virtual void command();
/**
* \brief Provide read access to the current robot state.
*
* @return Reference to the LBRState instance
*/
const LBRState& robotState() const { return _robotState; }
/**
* \brief Provide write access to the robot commands.
*
* @return Reference to the LBRCommand instance
*/
LBRCommand& robotCommand() { return _robotCommand; }
private:
LBRState _robotState; //!< wrapper class for the FRI monitoring message
LBRCommand _robotCommand; //!< wrapper class for the FRI command message
/**
* \brief Method to create and initialize the client data structure (used internally).
*
* @return newly allocated client data structure
*/
virtual ClientData* createData();
};
}
}
#endif // _KUKA_FRI_LBR_CLIENT_H
@@ -0,0 +1,162 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#ifndef _KUKA_FRI_LBR_COMMAND_H
#define _KUKA_FRI_LBR_COMMAND_H
// forward declarations
typedef struct _FRICommandMessage FRICommandMessage;
/** Kuka namespace */
namespace KUKA
{
namespace FRI
{
/**
* \brief Wrapper class for the FRI command message for a KUKA LBR (leightweight) robot.
*/
class LBRCommand
{
friend class LBRClient;
public:
/**
* \brief Set the joint positions for the current interpolation step.
*
* This method is only effective when the client is in a commanding state.
* @param values Array with the new joint positions (in rad)
*/
void setJointPosition(const double* values);
/**
* \brief Set the applied wrench vector of the current interpolation step.
*
* The wrench vector consists of:
* [F_x, F_y, F_z, tau_A, tau_B, tau_C]
*
* F ... forces (in N) applied along the Cartesian axes of the
* currently used motion center.
* tau ... torques (in Nm) applied along the orientation angles
* (Euler angles A, B, C) of the currently used motion center.
*
* This method is only effective when the client is in a commanding state.
* The ControlMode of the robot has to be Cartesian impedance control mode. The
* Client Command Mode has to be wrench.
*
* @param wrench Applied Cartesian wrench vector.
*/
void setWrench(const double* wrench);
/**
* \brief Set the applied joint torques for the current interpolation step.
*
* This method is only effective when the client is in a commanding state.
* The ControlMode of the robot has to be joint impedance control mode. The
* Client Command Mode has to be torque.
*
* @param torques Array with the applied torque values (in Nm)
*/
void setTorque(const double* torques);
/**
* \brief Set boolean output value.
*
* @throw FRIException Throws a FRIException if more outputs are set than can be registered.
* @throw FRIException May throw an FRIException if the IO is of wrong type, unknown or not an output.
* @param name Full name of the IO (Syntax "IOGroupName.IOName").
* @param value Boolean value to set.
*/
void setBooleanIOValue(const char* name, const bool value);
/**
* \brief Set digital output value.
*
* @throw FRIException Throws a FRIException if more outputs are set than can be registered.
* @throw FRIException May throw an FRIException if the IO is of wrong type, unknown or not an output.
* @param name Full name of the IO (Syntax "IOGroupName.IOName").
* @param value Digital value to set.
*/
void setDigitalIOValue(const char* name, const unsigned long long value);
/**
* \brief Set analog output value.
*
* @throw FRIException Throws a FRIException if more outputs are set than can be registered.
* @throw FRIException May throw an FRIException if the IO is of wrong type, unknown or not an output.
* @param name Full name of the IO (Syntax "IOGroupName.IOName").
* @param value Analog value to set.
*/
void setAnalogIOValue(const char* name, const double value);
protected:
static const int LBRCOMMANDMESSAGEID = 0x34001; //!< type identifier for the FRI command message corresponding to a KUKA LBR robot
FRICommandMessage* _cmdMessage; //!< FRI command message (protobuf struct)
FRIMonitoringMessage* _monMessage; //!< FRI monitoring message (protobuf struct)
};
}
}
#endif // _KUKA_FRI_LBR_COMMAND_H
@@ -0,0 +1,278 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#ifndef _KUKA_FRI_LBR_STATE_H
#define _KUKA_FRI_LBR_STATE_H
#include "friClientIf.h"
// forward declarations
typedef struct _FRIMonitoringMessage FRIMonitoringMessage;
/** Kuka namespace */
namespace KUKA
{
namespace FRI
{
/**
* \brief Wrapper class for the FRI monitoring message for a KUKA LBR (leightweight) robot.
*/
class LBRState
{
friend class LBRClient;
public:
enum
{
NUMBER_OF_JOINTS = 7 //!< number of axes of the KUKA LBR robot
};
LBRState();
/**
* \brief Get the sample time in seconds.
*
* This is the period in which the KUKA Sunrise controller is sending
* FRI packets.
* @return sample time in seconds
*/
double getSampleTime() const; // sec
/**
* \brief Get the current FRI session state.
*
* @return current FRI session state
*/
ESessionState getSessionState() const;
/**
* \brief Get the current FRI connection quality.
*
* @return current FRI connection quality
*/
EConnectionQuality getConnectionQuality() const;
/**
* \brief Get the current safety state of the KUKA Sunrise controller.
*
* @return current safety state
*/
ESafetyState getSafetyState() const;
/**
* \brief Get the current operation mode of the KUKA Sunrise controller.
*
* @return current operation mode
*/
EOperationMode getOperationMode() const;
/**
* \brief Get the accumulated drive state over all drives of the KUKA LBR controller.
*
* If the drive states differ between drives, the following rule applies:
* 1) The drive state is OFF if all drives are OFF.
* 2) The drive state is ACTIVE if all drives are ACTIVE.
* 3) otherwise the drive state is TRANSITIONING.
* @return accumulated drive state
*/
EDriveState getDriveState() const;
/**
* \brief Get the client command mode specified by the client.
*
* @return the client command mode specified by the client.
*/
EClientCommandMode getClientCommandMode() const;
/**
* \brief Get the overlay type specified by the client.
*
* @return the overlay type specified by the client.
*/
EOverlayType getOverlayType() const;
/**
* \brief Get the control mode of the KUKA LBR robot.
*
* @return current control mode of the KUKA LBR robot.
*/
EControlMode getControlMode() const;
/**
* \brief Get the timestamp of the current robot state in Unix time.
*
* This method returns the seconds since 0:00, January 1st, 1970 (UTC).
* Use getTimestampNanoSec() to increase your timestamp resolution when
* seconds are insufficient.
* @return timestamp encoded as Unix time (seconds)
*/
unsigned int getTimestampSec() const;
/**
* \brief Get the nanoseconds elapsed since the last second (in Unix time).
*
* This method complements getTimestampSec() to get a high resolution
* timestamp.
* @return timestamp encoded as Unix time (nanoseconds part)
*/
unsigned int getTimestampNanoSec() const;
/**
* \brief Get the currently measured joint positions of the robot.
*
* @return array of the measured joint positions in radians
*/
const double* getMeasuredJointPosition() const;
/**
* \brief Get the last commanded joint positions of the robot.
*
* @return array of the commanded joint positions in radians
*/
const double* getCommandedJointPosition() const;
/**
* \brief Get the currently measured joint torques of the robot.
*
* @return array of the measured torques in Nm
*/
const double* getMeasuredTorque() const;
/**
* \brief Get the last commanded joint torques of the robot.
*
* @return array of the commanded torques in Nm
*/
const double* getCommandedTorque() const;
/**
* \brief Get the currently measured external joint torques of the robot.
*
* The external torques corresponds to the measured torques when removing
* the torques induced by the robot itself.
* @return array of the external torques in Nm
*/
const double* getExternalTorque() const;
/**
* \brief Get the joint positions commanded by the interpolator.
*
* When commanding a motion overlay in your robot application, this method
* will give access to the joint positions currently commanded by the
* motion interpolator.
* @throw FRIException This method will throw an FRIException during monitoring mode.
* @return array of the ipo joint positions in radians
*/
const double* getIpoJointPosition() const;
/**
* \brief Get an indicator for the current tracking performance of the commanded robot.
*
* The tracking performance is an indicator on how well the commanded robot
* is able to follow the commands of the FRI client. The best possible value
* 1.0 is reached when the robot executes the given commands instantaneously.
* The tracking performance drops towards 0 when latencies are induced,
* e.g. when the commanded velocity, acceleration or jerk exceeds the
* capabilities of the robot.
* The tracking performance will always be 0 when the session state does
* not equal COMMANDING_ACTIVE.
* @return current tracking performance
*/
double getTrackingPerformance() const;
/**
* \brief Get boolean IO value.
*
* @throw FRIException May throw an FRIException if the IO is of wrong type or unknown.
* @param name Full name of the IO (Syntax "IOGroupName.IOName").
* @return Returns IO's boolean value.
*/
bool getBooleanIOValue(const char* name) const;
/**
* \brief Get digital IO value.
*
* @throw FRIException May throw an FRIException if the IO is of wrong type or unknown.
* @param name Full name of the IO (Syntax "IOGroupName.IOName").
* @return Returns IO's digital value.
*/
unsigned long long getDigitalIOValue(const char* name) const;
/**
* \brief Get analog IO value.
*
* @throw FRIException May throw an FRIException if the IO is of wrong type or unknown.
* @param name Full name of the IO (Syntax "IOGroupName.IOName").
* @return Returns IO's analog value.
*/
double getAnalogIOValue(const char* name) const;
protected:
static const int LBRMONITORMESSAGEID = 0x245142; //!< type identifier for the FRI monitoring message corresponding to a KUKA LBR robot
FRIMonitoringMessage* _message; //!< FRI monitoring message (protobuf struct)
};
}
}
#endif // _KUKA_FRI_LBR_STATE_H
@@ -0,0 +1,267 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#ifndef _KUKA_FRI_TRANSFORMATION_CLIENT_H
#define _KUKA_FRI_TRANSFORMATION_CLIENT_H
#include <vector>
#include "friClientIf.h"
/** Kuka namespace */
namespace KUKA
{
namespace FRI
{
// forward declaration
struct ClientData;
/**
* \brief Abstract FRI transformation client.
*
* A transformation client enables the user to send transformation matrices cyclically to the
* KUKA Sunrise controller for manipulating the transformations of dynamic frames in the
* Sunrise scenegraph.
* Usually, these matrices will be provided by external sensors.
* <br>
* Custom transformation clients have to be derived from this class and need to
* implement the provide() callback. This callback is called once by the
* client application whenever a new FRI message arrives.
*
* <b>This element is an undocumented internal feature. It is not intended to be used by applications as it might change or be removed in future versions.</b>
*/
class TransformationClient
{
friend class ClientApplication;
public:
/**
* <br> <b>This element is an undocumented internal feature. It is not intended to be used by applications as it might change or be removed in future versions.</b> <br>
* \brief Constructor.
**/
TransformationClient();
/** <br> <b>This element is an undocumented internal feature. It is not intended to be used by applications as it might change or be removed in future versions.</b> <br>
* \brief Virtual destructor.
**/
virtual ~TransformationClient();
/**
* <br> <b>This element is an undocumented internal feature. It is not intended to be used by applications as it might change or be removed in future versions.</b> <br>
* \brief Callback which is called whenever a new FRI message arrives.
*
* In this callback all requested transformations have to be set.
*
* \see getRequestedTransformationIDs(), setTransformation()
*/
virtual void provide() = 0;
/**
* \brief Get the sample time in seconds.
*
* This is the period in which the KUKA Sunrise controller is sending
* FRI packets.
* @return sample time in seconds
*/
double getSampleTime() const; // sec
/**
* \brief Get the current FRI connection quality.
*
* @return current FRI connection quality
*/
EConnectionQuality getConnectionQuality() const;
/**
* <br> <b>This element is an undocumented internal feature. It is not intended to be used by applications as it might change or be removed in future versions.</b> <br>
* \brief Returns a vector of identifiers of all requested transformation matrices.
*
* The custom TransformationClient has to provide data for transformation matrices with these
* identifiers.
*
* @return reference to vector of IDs of requested transformations
*/
const std::vector<const char*>& getRequestedTransformationIDs() const;
/**
* <br> <b>This element is an undocumented internal feature. It is not intended to be used by applications as it might change or be removed in future versions.</b> <br>
*
* \brief Get the timestamp of the current received FRI monitor message in Unix time.
*
* This method returns the seconds since 0:00, January 1st, 1970 (UTC).
* Use getTimestampNanoSec() to increase your timestamp resolution when
* seconds are insufficient.
*
* @return timestamp encoded as Unix time (seconds)
*/
const unsigned int getTimestampSec() const;
/**
* <br> <b>This element is an undocumented internal feature. It is not intended to be used by applications as it might change or be removed in future versions.</b> <br>
* \brief Get the nanoseconds elapsed since the last second (in Unix time).
*
* This method complements getTimestampSec() to get a high resolution
* timestamp.
*
* @return timestamp encoded as Unix time (nanoseconds part)
*/
const unsigned int getTimestampNanoSec() const;
/**
* <br> <b>This element is an undocumented internal feature. It is not intended to be used by applications as it might change or be removed in future versions.</b> <br>
* \brief Provides a requested transformation matrix.
*
* A transformation matrix has 3x4 elements. It consists of a rotational matrix (3x3 elements)
* and a translational vector (3x1 elements). The complete transformation matrix has the
* following structure: <br>
* [Transformation(3x4)] = [Rotation(3x3) | Translation(3x1) ]
* <p>
* All provided transformation matrices need a timestamp that corresponds to their
* time of acquisiton. This timestamp must be synchronized to the timestamp
* provided by the KUKA Sunrise controller (see getTimestampSec(), getTimestampNanoSec()).
* <p>
* If an update to the last transformation is not yet available when the provide()
* callback is executed, the last transformation (including its timestamp) should be
* repeated until a new transformation is available.
*
* @throw FRIException Throws a FRIException if the maximum number of transformations is exceeded.
* @param transformationID Identifier string of the transformation matrix
* @param transformationMatrix Provided transformation matrix
* @param timeSec Timestamp encoded as Unix time (seconds)
* @param timeNanoSec Timestamp encoded as Unix time (nanoseconds part)
*/
void setTransformation(const char* transformationID, const double transformationMatrix[3][4],
unsigned int timeSec, unsigned int timeNanoSec);
/**
* \brief Set boolean output value.
*
* @throw FRIException Throws a FRIException if more outputs are set than can be registered.
* @throw FRIException May throw an FRIException if the IO is of wrong type, unknown or not an output.
* @param name Full name of the IO (Syntax "IOGroupName.IOName").
* @param value Boolean value to set.
*/
void setBooleanIOValue(const char* name, const bool value);
/**
* \brief Set digital output value.
*
* @throw FRIException Throws a FRIException if more outputs are set than can be registered.
* @throw FRIException May throw an FRIException if the IO is of wrong type, unknown or not an output.
* @param name Full name of the IO (Syntax "IOGroupName.IOName").
* @param value Digital value to set.
*/
void setDigitalIOValue(const char* name, const unsigned long long value);
/**
* \brief Set analog output value.
*
* @throw FRIException Throws a FRIException if more outputs are set than can be registered.
* @throw FRIException May throw an FRIException if the IO is of wrong type, unknown or not an output.
* @param name Full name of the IO (Syntax "IOGroupName.IOName").
* @param value Analog value to set.
*/
void setAnalogIOValue(const char* name, const double value);
/**
* \brief Get boolean IO value.
*
* @throw FRIException May throw an FRIException if the IO is of wrong type or unknown.
* @param name Full name of the IO (Syntax "IOGroupName.IOName").
* @return Returns IO's boolean value.
*/
bool getBooleanIOValue(const char* name) const;
/**
* \brief Get digital IO value.
*
* @throw FRIException May throw an FRIException if the IO is of wrong type or unknown.
* @param name Full name of the IO (Syntax "IOGroupName.IOName").
* @return Returns IO's digital value.
*/
unsigned long long getDigitalIOValue(const char* name) const;
/**
* \brief Get analog IO value.
*
* @throw FRIException May throw an FRIException if the IO is of wrong type or unknown.
* @param name Full name of the IO (Syntax "IOGroupName.IOName").
* @return Returns IO's analog value.
*/
double getAnalogIOValue(const char* name) const;
private:
ClientData* _data; //!< the client data structure
/**
* \brief Method to link the client data structure (used internally).
*
* @param clientData the client data structure
*/
void linkData(ClientData* clientData);
};
}
}
#endif // _KUKA_FRI_TRANSFORMATION_CLIENT_H
@@ -0,0 +1,163 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#ifndef _KUKA_FRI_UDP_CONNECTION_H
#define _KUKA_FRI_UDP_CONNECTION_H
#include <cstdlib>
#ifdef _WIN32
#include <winsock2.h>
#else
// if linux or a other unix system is used, select uses the following include
#ifdef __unix__
#include <sys/select.h>
#endif
// for VxWorks
#ifdef VXWORKS
#include <selectLib.h>
#include <sockLib.h>
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include "friConnectionIf.h"
/** Kuka namespace */
namespace KUKA
{
namespace FRI
{
/**
* \brief This class implements the IConnection interface using UDP sockets.
*/
class UdpConnection : public IConnection
{
public:
/**
* \brief Constructor with an optional parameter for setting a receive timeout.
*
* @param receiveTimeout Timeout (in ms) for receiving a UDP message (0 = wait forever)
* */
UdpConnection(unsigned int receiveTimeout = 0);
/** \brief Destructor. */
~UdpConnection();
/**
* \brief Open a connection to the KUKA Sunrise controller.
*
* @param port The port ID for the connection
* @param controllerAddress The IPv4 address of the KUKA Sunrise controller.
* If NULL, the FRI Client accepts connections from any
* address.
* @return True if connection was established, false otherwise
*/
virtual bool open(int port, const char *controllerAddress = NULL);
/**
* \brief Close a connection to the KUKA Sunrise controller.
*/
virtual void close();
/**
* \brief Checks whether a connection to the KUKA Sunrise controller is established.
*
* @return True if connection is established
*/
virtual bool isOpen() const;
/**
* \brief Receive a new FRI monitoring message from the KUKA Sunrise controller.
*
* This method blocks until a new message arrives.
* @param buffer Pointer to the allocated buffer that will hold the FRI message
* @param maxSize Size in bytes of the allocated buffer
* @return Number of bytes received (0 when connection was terminated,
* negative in case of errors or receive timeout)
*/
virtual int receive(char *buffer, int maxSize);
/**
* \brief Send a new FRI command message to the KUKA Sunrise controller.
*
* @param buffer Pointer to the buffer holding the FRI message
* @param size Size in bytes of the message to be send
* @return True if successful
*/
virtual bool send(const char* buffer, int size);
private:
int _udpSock; //!< UDP socket handle
struct sockaddr_in _controllerAddr; //!< the controller's socket address
unsigned int _receiveTimeout;
fd_set _filedescriptor;
};
}
}
#endif // _KUKA_FRI_UDP_CONNECTION_H
+11
View File
@@ -0,0 +1,11 @@
BASE_DIR = ../..
include $(BASE_DIR)/build/GNUMake/paths.mak
include $(BASE_DIR)/build/GNUMake/$(TOOLS_MAK)
CXX_SRC = friClientApplication.cpp
INC_DIR += $(NANOPB_DIR) $(PROTOBUF_DIR) $(PROTOBUF_GEN_DIR)
CXXFLAGS +=
LDFLAGS +=
include $(BASE_DIR)/build/GNUMake/rules.mak
@@ -0,0 +1,211 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#include <cstdio>
#include "friClientApplication.h"
#include "friClientIf.h"
#include "friConnectionIf.h"
#include "friClientData.h"
#include "FRIMessages.pb.h"
#include "friTransformationClient.h"
using namespace KUKA::FRI;
//******************************************************************************
ClientApplication::ClientApplication(IConnection& connection, IClient& client)
: _connection(connection), _robotClient(&client),_trafoClient(NULL), _data(NULL)
{
_data = _robotClient->createData();
}
//******************************************************************************
ClientApplication::ClientApplication(IConnection& connection, IClient& client, TransformationClient& trafoClient)
: _connection(connection), _robotClient(&client),_trafoClient(&trafoClient), _data(NULL)
{
_data = _robotClient->createData();
_trafoClient->linkData(_data);
}
//******************************************************************************
ClientApplication::~ClientApplication()
{
disconnect();
delete _data;
}
//******************************************************************************
bool ClientApplication::connect(int port, const char *remoteHost)
{
if (_connection.isOpen())
{
printf("Warning: client application already connected!\n");
return true;
}
return _connection.open(port, remoteHost);
}
//******************************************************************************
void ClientApplication::disconnect()
{
if (_connection.isOpen()) _connection.close();
}
//******************************************************************************
bool ClientApplication::step()
{
if (!_connection.isOpen())
{
printf("Error: client application is not connected!\n");
return false;
}
// **************************************************************************
// Receive and decode new monitoring message
// **************************************************************************
int size = _connection.receive(_data->receiveBuffer, FRI_MONITOR_MSG_MAX_SIZE);
if (size <= 0)
{ // TODO: size == 0 -> connection closed (maybe go to IDLE instead of stopping?)
printf("Error: failed while trying to receive monitoring message!\n");
return false;
}
if (!_data->decoder.decode(_data->receiveBuffer, size))
{
return false;
}
// check message type (so that our wrappers match)
if (_data->expectedMonitorMsgID != _data->monitoringMsg.header.messageIdentifier)
{
printf("Error: incompatible IDs for received message (got: %d expected %d)!\n",
(int)_data->monitoringMsg.header.messageIdentifier,
(int)_data->expectedMonitorMsgID);
return false;
}
// **************************************************************************
// callbacks
// **************************************************************************
// reset commmand message before callbacks
_data->resetCommandMessage();
// callbacks for robot client
ESessionState currentState = (ESessionState)_data->monitoringMsg.connectionInfo.sessionState;
if (_data->lastState != currentState)
{
_robotClient->onStateChange(_data->lastState, currentState);
_data->lastState = currentState;
}
switch (currentState)
{
case MONITORING_WAIT:
case MONITORING_READY:
_robotClient->monitor();
break;
case COMMANDING_WAIT:
_robotClient->waitForCommand();
break;
case COMMANDING_ACTIVE:
_robotClient->command();
break;
case IDLE:
default:
return true; // nothing to send back
}
// callback for transformation client
if(_trafoClient != NULL)
{
_trafoClient->provide();
}
// **************************************************************************
// Encode and send command message
// **************************************************************************
_data->lastSendCounter++;
// check if its time to send an answer
if (_data->lastSendCounter >= _data->monitoringMsg.connectionInfo.receiveMultiplier)
{
_data->lastSendCounter = 0;
// set sequence counters
_data->commandMsg.header.sequenceCounter = _data->sequenceCounter++;
_data->commandMsg.header.reflectedSequenceCounter =
_data->monitoringMsg.header.sequenceCounter;
if (!_data->encoder.encode(_data->sendBuffer, size))
{
return false;
}
if (!_connection.send(_data->sendBuffer, size))
{
printf("Error: failed while trying to send command message!\n");
return false;
}
}
return true;
}
@@ -0,0 +1,240 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#ifndef _KUKA_FRI_CLIENT_DATA_H
#define _KUKA_FRI_CLIENT_DATA_H
#include <vector>
#include "FRIMessages.pb.h"
#include "friMonitoringMessageDecoder.h"
#include "friCommandMessageEncoder.h"
#include "friClientIf.h"
#include "friException.h"
namespace KUKA
{
namespace FRI
{
struct ClientData
{
char receiveBuffer[FRI_MONITOR_MSG_MAX_SIZE];//!< monitoring message receive buffer
char sendBuffer[FRI_COMMAND_MSG_MAX_SIZE]; //!< command message send buffer
FRIMonitoringMessage monitoringMsg; //!< monitoring message struct
FRICommandMessage commandMsg; //!< command message struct
MonitoringMessageDecoder decoder; //!< monitoring message decoder
CommandMessageEncoder encoder; //!< command message encoder
ESessionState lastState; //!< last FRI state
uint32_t sequenceCounter; //!< sequence counter for command messages
uint32_t lastSendCounter; //!< steps since last send command
uint32_t expectedMonitorMsgID; //!< expected ID for received monitoring messages
const size_t MAX_REQUESTED_TRANSFORMATIONS; //!< maximum count of requested transformations
const size_t MAX_SIZE_TRANSFORMATION_ID; //!< maximum size in bytes of a transformation ID
std::vector<const char*> requestedTrafoIDs; //!< list of requested transformation ids
ClientData(int numDofs)
: decoder(&monitoringMsg, numDofs),
encoder(&commandMsg, numDofs),
lastState(IDLE),
sequenceCounter(0),
lastSendCounter(0),
expectedMonitorMsgID(0),
MAX_REQUESTED_TRANSFORMATIONS(sizeof(monitoringMsg.requestedTransformations) /
sizeof(monitoringMsg.requestedTransformations[0])),
MAX_SIZE_TRANSFORMATION_ID(sizeof(monitoringMsg.requestedTransformations[0].name))
{
requestedTrafoIDs.reserve(MAX_REQUESTED_TRANSFORMATIONS);
}
void resetCommandMessage()
{
commandMsg.commandData.has_jointPosition = false;
commandMsg.commandData.has_cartesianWrenchFeedForward = false;
commandMsg.commandData.has_jointTorque = false;
commandMsg.commandData.commandedTransformations_count = 0;
commandMsg.has_commandData = false;
commandMsg.commandData.writeIORequest_count = 0;
}
//******************************************************************************
static const FriIOValue& getBooleanIOValue(const FRIMonitoringMessage* message, const char* name)
{
return getIOValue(message, name, FriIOType_BOOLEAN);
}
//******************************************************************************
static const FriIOValue& getDigitalIOValue(const FRIMonitoringMessage* message, const char* name)
{
return getIOValue(message, name, FriIOType_DIGITAL);
}
//******************************************************************************
static const FriIOValue& getAnalogIOValue(const FRIMonitoringMessage* message, const char* name)
{
return getIOValue(message, name, FriIOType_ANALOG);
}
//******************************************************************************
static void setBooleanIOValue(FRICommandMessage* message, const char* name, const bool value,
const FRIMonitoringMessage* monMessage)
{
setIOValue(message, name, monMessage, FriIOType_BOOLEAN).digitalValue = value;
}
//******************************************************************************
static void setDigitalIOValue(FRICommandMessage* message, const char* name, const unsigned long long value,
const FRIMonitoringMessage* monMessage)
{
setIOValue(message, name, monMessage, FriIOType_DIGITAL).digitalValue = value;
}
//******************************************************************************
static void setAnalogIOValue(FRICommandMessage* message, const char* name, const double value,
const FRIMonitoringMessage* monMessage)
{
setIOValue(message, name, monMessage, FriIOType_ANALOG).analogValue = value;
}
protected:
//******************************************************************************
static const FriIOValue& getIOValue(const FRIMonitoringMessage* message, const char* name,
const FriIOType ioType)
{
if(message != NULL && message->has_monitorData == true)
{
const MessageMonitorData& monData = message->monitorData;
const bool analogValue = (ioType == FriIOType_ANALOG);
const bool digitalValue = (ioType == FriIOType_DIGITAL | ioType == FriIOType_BOOLEAN);
for(size_t i = 0; i < monData.readIORequest_count; i++)
{
const FriIOValue& ioValue = monData.readIORequest[i];
if(strcmp(name, ioValue.name) == 0)
{
if(ioValue.type == ioType &&
ioValue.has_digitalValue == digitalValue &&
ioValue.has_analogValue == analogValue)
{
return ioValue;
}
const char* ioTypeName;
switch(ioType)
{
case FriIOType_ANALOG: ioTypeName = "analog value"; break;
case FriIOType_DIGITAL: ioTypeName = "digital value"; break;
case FriIOType_BOOLEAN: ioTypeName = "boolean"; break;
default: ioTypeName = "?"; break;
}
throw FRIException("IO %s is not of type %s.", name, ioTypeName);
}
}
}
throw FRIException("Could not locate IO %s in monitor message.", name);
}
//******************************************************************************
static FriIOValue& setIOValue(FRICommandMessage* message, const char* name,
const FRIMonitoringMessage* monMessage, const FriIOType ioType)
{
MessageCommandData& cmdData = message->commandData;
const size_t maxIOs = sizeof(cmdData.writeIORequest) / sizeof(cmdData.writeIORequest[0]);
if(cmdData.writeIORequest_count < maxIOs)
{
// call getter which will raise an exception if the output doesn't exist
// or is of wrong type.
if(getIOValue(monMessage, name, ioType).direction != FriIODirection_OUTPUT)
{
throw FRIException("IO %s is not an output value.", name);
}
// add IO value to command message
FriIOValue& ioValue = cmdData.writeIORequest[cmdData.writeIORequest_count];
strncpy(ioValue.name, name, sizeof(ioValue.name) - 1);
ioValue.name[sizeof(ioValue.name) - 1] = 0; // ensure termination
ioValue.type = ioType;
ioValue.has_digitalValue = (ioType == FriIOType_DIGITAL | ioType == FriIOType_BOOLEAN);
ioValue.has_analogValue = (ioType == FriIOType_ANALOG);
ioValue.direction = FriIODirection_OUTPUT;
cmdData.writeIORequest_count ++;
message->has_commandData = true;
return ioValue;
}
else
{
throw FRIException("Exceeded maximum number of IOs that can be set.");
}
}
};
}
}
#endif // _KUKA_FRI_CLIENT_DATA_H
@@ -0,0 +1,13 @@
BASE_DIR = ../..
include $(BASE_DIR)/build/GNUMake/paths.mak
include $(BASE_DIR)/build/GNUMake/$(TOOLS_MAK)
CXX_SRC = friLBRClient.cpp \
friLBRCommand.cpp \
friLBRState.cpp
INC_DIR += $(CLIENTBASE_DIR) $(NANOPB_DIR) $(PROTOBUF_DIR) $(PROTOBUF_GEN_DIR)
CXXFLAGS +=
LDFLAGS +=
include $(BASE_DIR)/build/GNUMake/rules.mak
@@ -0,0 +1,120 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#include <cstdio>
#include "friLBRClient.h"
#include "friClientData.h"
using namespace KUKA::FRI;
char FRIException::_buffer[1024] = { 0 };
//******************************************************************************
LBRClient::LBRClient()
{
}
//******************************************************************************
LBRClient::~LBRClient()
{
}
//******************************************************************************
void LBRClient::onStateChange(ESessionState oldState, ESessionState newState)
{
// TODO: String converter function for states
printf("LBRiiwaClient state changed from %d to %d\n", oldState, newState);
}
//******************************************************************************
void LBRClient::monitor()
{
robotCommand().setJointPosition(robotState().getCommandedJointPosition());
}
//******************************************************************************
void LBRClient::waitForCommand()
{
robotCommand().setJointPosition(robotState().getIpoJointPosition());
}
//******************************************************************************
void LBRClient::command()
{
robotCommand().setJointPosition(robotState().getIpoJointPosition());
}
//******************************************************************************
ClientData* LBRClient::createData()
{
ClientData* data = new ClientData(_robotState.NUMBER_OF_JOINTS);
// link monitoring and command message to wrappers
_robotState._message = &data->monitoringMsg;
_robotCommand._cmdMessage = &data->commandMsg;
_robotCommand._monMessage = &data->monitoringMsg;
// set specific message IDs
data->expectedMonitorMsgID = _robotState.LBRMONITORMESSAGEID;
data->commandMsg.header.messageIdentifier = _robotCommand.LBRCOMMANDMESSAGEID;
return data;
}
@@ -0,0 +1,113 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#include "friLBRState.h"
#include "friLBRCommand.h"
#include "friClientData.h"
#include "pb_frimessages_callbacks.h"
using namespace KUKA::FRI;
//******************************************************************************
void LBRCommand::setJointPosition(const double* values)
{
_cmdMessage->has_commandData = true;
_cmdMessage->commandData.has_jointPosition = true;
tRepeatedDoubleArguments *dest =
(tRepeatedDoubleArguments*)_cmdMessage->commandData.jointPosition.value.arg;
memcpy(dest->value, values, LBRState::NUMBER_OF_JOINTS * sizeof(double));
}
//******************************************************************************
void LBRCommand::setWrench(const double* wrench)
{
_cmdMessage->has_commandData = true;
_cmdMessage->commandData.has_cartesianWrenchFeedForward = true;
double *dest = _cmdMessage->commandData.cartesianWrenchFeedForward.element;
memcpy(dest, wrench, 6 * sizeof(double));
}
//******************************************************************************
void LBRCommand::setTorque(const double* torques)
{
_cmdMessage->has_commandData = true;
_cmdMessage->commandData.has_jointTorque= true;
tRepeatedDoubleArguments *dest =
(tRepeatedDoubleArguments*)_cmdMessage->commandData.jointTorque.value.arg;
memcpy(dest->value, torques, LBRState::NUMBER_OF_JOINTS * sizeof(double));
}
//******************************************************************************
void LBRCommand::setBooleanIOValue(const char* name, const bool value)
{
ClientData::setBooleanIOValue(_cmdMessage, name, value, _monMessage);
}
//******************************************************************************
void LBRCommand::setAnalogIOValue(const char* name, const double value)
{
ClientData::setAnalogIOValue(_cmdMessage, name, value, _monMessage);
}
//******************************************************************************
void LBRCommand::setDigitalIOValue(const char* name, const unsigned long long value)
{
ClientData::setDigitalIOValue(_cmdMessage, name, value, _monMessage);
}
@@ -0,0 +1,234 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#include "friLBRState.h"
#include "friClientData.h"
#include "pb_frimessages_callbacks.h"
using namespace KUKA::FRI;
LBRState::LBRState():_message(0)
{
}
//******************************************************************************
double LBRState::getSampleTime() const
{
return _message->connectionInfo.sendPeriod * 0.001;
}
//******************************************************************************
ESessionState LBRState::getSessionState() const
{
return (ESessionState)_message->connectionInfo.sessionState;
}
//******************************************************************************
EConnectionQuality LBRState::getConnectionQuality() const
{
return (EConnectionQuality)_message->connectionInfo.quality;
}
//******************************************************************************
ESafetyState LBRState::getSafetyState() const
{
return (ESafetyState)_message->robotInfo.safetyState;
}
//******************************************************************************
EOperationMode LBRState::getOperationMode() const
{
return (EOperationMode)_message->robotInfo.operationMode;
}
//******************************************************************************
EDriveState LBRState::getDriveState() const
{
tRepeatedIntArguments *values =
(tRepeatedIntArguments *)_message->robotInfo.driveState.arg;
int firstState = (int)values->value[0];
for (int i=1; i<NUMBER_OF_JOINTS; i++)
{
int state = (int)values->value[i];
if (state != firstState)
{
return TRANSITIONING;
}
}
return (EDriveState)firstState;
}
//********************************************************************************
EOverlayType LBRState::getOverlayType() const
{
return (EOverlayType)_message->ipoData.overlayType;
}
//********************************************************************************
EClientCommandMode LBRState::getClientCommandMode() const
{
return (EClientCommandMode)_message->ipoData.clientCommandMode;
}
//******************************************************************************
EControlMode LBRState::getControlMode() const
{
return (EControlMode)_message->robotInfo.controlMode;
}
//******************************************************************************
unsigned int LBRState::getTimestampSec() const
{
return _message->monitorData.timestamp.sec;
}
//******************************************************************************
unsigned int LBRState::getTimestampNanoSec() const
{
return _message->monitorData.timestamp.nanosec;
}
//******************************************************************************
const double* LBRState::getMeasuredJointPosition() const
{
tRepeatedDoubleArguments *values =
(tRepeatedDoubleArguments*)_message->monitorData.measuredJointPosition.value.arg;
return (double*)values->value;
}
//******************************************************************************
const double* LBRState::getCommandedJointPosition() const
{
tRepeatedDoubleArguments *values =
(tRepeatedDoubleArguments*)_message->monitorData.commandedJointPosition.value.arg;
return (double*)values->value;
}
//******************************************************************************
const double* LBRState::getMeasuredTorque() const
{
tRepeatedDoubleArguments *values =
(tRepeatedDoubleArguments*)_message->monitorData.measuredTorque.value.arg;
return (double*)values->value;
}
//******************************************************************************
const double* LBRState::getCommandedTorque() const
{
tRepeatedDoubleArguments *values =
(tRepeatedDoubleArguments*)_message->monitorData.commandedTorque.value.arg;
return (double*)values->value;
}
//******************************************************************************
const double* LBRState::getExternalTorque() const
{
tRepeatedDoubleArguments *values =
(tRepeatedDoubleArguments*)_message->monitorData.externalTorque.value.arg;
return (double*)values->value;
}
//******************************************************************************
const double* LBRState::getIpoJointPosition() const
{
if (!_message->ipoData.has_jointPosition)
{
throw FRIException("IPO joint position not available in monitoring mode.");
return NULL;
}
tRepeatedDoubleArguments *values =
(tRepeatedDoubleArguments*)_message->ipoData.jointPosition.value.arg;
return (double*)values->value;
}
//******************************************************************************
double LBRState::getTrackingPerformance() const
{
if (!_message->ipoData.has_trackingPerformance) return 0.0;
return _message->ipoData.trackingPerformance;
}
//******************************************************************************
bool LBRState::getBooleanIOValue(const char* name) const
{
return ClientData::getBooleanIOValue(_message, name).digitalValue != 0;
}
//******************************************************************************
unsigned long long LBRState::getDigitalIOValue(const char* name) const
{
return ClientData::getDigitalIOValue(_message, name).digitalValue;
}
//******************************************************************************
double LBRState::getAnalogIOValue(const char* name) const
{
return ClientData::getAnalogIOValue(_message, name).analogValue;
}
//******************************************************************************
/*const std::vector<const char*>& LBRState::getRequestedIO_IDs() const
{
return _clientData->getRequestedIO_IDs();
}*/
@@ -0,0 +1,11 @@
BASE_DIR = ../..
include $(BASE_DIR)/build/GNUMake/paths.mak
include $(BASE_DIR)/build/GNUMake/$(TOOLS_MAK)
CXX_SRC = friTransformationClient.cpp
INC_DIR += $(CLIENTBASE_DIR) $(NANOPB_DIR) $(PROTOBUF_DIR) $(PROTOBUF_GEN_DIR)
CXXFLAGS +=
LDFLAGS +=
include $(BASE_DIR)/build/GNUMake/rules.mak
@@ -0,0 +1,191 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#include <cstring>
#include <cstdio>
#include "friTransformationClient.h"
#include "friClientData.h"
#include "FRIMessages.pb.h"
#include "pb_frimessages_callbacks.h"
using namespace KUKA::FRI;
//******************************************************************************
TransformationClient::TransformationClient()
{
}
//******************************************************************************
TransformationClient::~TransformationClient()
{
}
//******************************************************************************
const std::vector<const char*>& TransformationClient::getRequestedTransformationIDs() const
{
unsigned int trafoCount = _data->monitoringMsg.requestedTransformations_count;
_data->requestedTrafoIDs.resize(trafoCount);
for (unsigned int i=0; i<trafoCount; i++)
{
_data->requestedTrafoIDs[i] = _data->monitoringMsg.requestedTransformations[i].name;
}
return _data->requestedTrafoIDs;
}
//******************************************************************************
const unsigned int TransformationClient::getTimestampSec() const
{
return _data->monitoringMsg.monitorData.timestamp.sec;
}
//******************************************************************************
const unsigned int TransformationClient::getTimestampNanoSec() const
{
return _data->monitoringMsg.monitorData.timestamp.nanosec;
}
//******************************************************************************
void TransformationClient::setTransformation(const char* transformationID,
const double transformationMatrix[3][4], unsigned int timeSec, unsigned int timeNanoSec)
{
_data->commandMsg.has_commandData = true;
unsigned int currentSize = _data->commandMsg.commandData.commandedTransformations_count;
if (currentSize < _data->MAX_REQUESTED_TRANSFORMATIONS)
{
_data->commandMsg.commandData.commandedTransformations_count++;
Transformation& dest = _data->commandMsg.commandData.commandedTransformations[currentSize];
strncpy(dest.name, transformationID, _data->MAX_SIZE_TRANSFORMATION_ID);
dest.name[_data->MAX_SIZE_TRANSFORMATION_ID - 1] = '\0';
dest.matrix_count = 12;
memcpy(dest.matrix, transformationMatrix, 12 * sizeof(double));
dest.has_timestamp = true;
dest.timestamp.sec = timeSec;
dest.timestamp.nanosec = timeNanoSec;
}
else
{
throw FRIException("Exceeded maximum number of transformations.");
}
}
//******************************************************************************
void TransformationClient::linkData(ClientData* clientData)
{
_data = clientData;
}
//******************************************************************************
double TransformationClient::getSampleTime() const
{
return _data->monitoringMsg.connectionInfo.sendPeriod * 0.001;
}
//******************************************************************************
EConnectionQuality TransformationClient::getConnectionQuality() const
{
return (EConnectionQuality)_data->monitoringMsg.connectionInfo.quality;
}
//******************************************************************************
void TransformationClient::setBooleanIOValue(const char* name, const bool value)
{
ClientData::setBooleanIOValue(&_data->commandMsg, name, value, &_data->monitoringMsg);
}
//******************************************************************************
void TransformationClient::setAnalogIOValue(const char* name, const double value)
{
ClientData::setAnalogIOValue(&_data->commandMsg, name, value, &_data->monitoringMsg);
}
//******************************************************************************
void TransformationClient::setDigitalIOValue(const char* name, const unsigned long long value)
{
ClientData::setDigitalIOValue(&_data->commandMsg, name, value, &_data->monitoringMsg);
}
//******************************************************************************
bool TransformationClient::getBooleanIOValue(const char* name) const
{
return ClientData::getBooleanIOValue(&_data->monitoringMsg, name).digitalValue != 0;
}
//******************************************************************************
unsigned long long TransformationClient::getDigitalIOValue(const char* name) const
{
return ClientData::getDigitalIOValue(&_data->monitoringMsg, name).digitalValue;
}
//******************************************************************************
double TransformationClient::getAnalogIOValue(const char* name) const
{
return ClientData::getAnalogIOValue(&_data->monitoringMsg, name).analogValue;
}
//******************************************************************************
/*const std::vector<const char*>& TransformationClient::getRequestedIO_IDs() const
{
return _data->getRequestedIO_IDs();
}*/
@@ -0,0 +1,14 @@
BASE_DIR = ../..
include $(BASE_DIR)/build/GNUMake/paths.mak
include $(BASE_DIR)/build/GNUMake/$(TOOLS_MAK)
CXX_SRC = friUdpConnection.cpp
CXXFLAGS +=
LDFLAGS +=
################################################################################
### Include general makefile (at the end)
################################################################################
include $(BASE_DIR)/build/GNUMake/rules.mak
@@ -0,0 +1,243 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software KUKA Sunrise.Connectivity FRI Client SDK is targeted to work in
conjunction with the KUKA Sunrise.Connectivity FastRobotInterface toolkit.
In the following, the term software refers to all material directly
belonging to the provided SDK Software development kit, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#include <cstring>
#include <cstdio>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include "friUdpConnection.h"
#ifdef WIN32
#include <winsock2.h>
#include <Ws2tcpip.h>
#ifdef _MSC_VER
#pragma comment(lib, "ws2_32.lib")
#endif
#endif
using namespace KUKA::FRI;
//******************************************************************************
UdpConnection::UdpConnection(unsigned int receiveTimeout) :
_udpSock(-1),
_receiveTimeout(receiveTimeout)
{
#ifdef WIN32
WSADATA WSAData;
WSAStartup(MAKEWORD(2,0), &WSAData);
#endif
}
//******************************************************************************
UdpConnection::~UdpConnection()
{
close();
#ifdef WIN32
WSACleanup();
#endif
}
//******************************************************************************
bool UdpConnection::open(int port, const char *controllerAddress)
{
struct sockaddr_in servAddr;
memset(&servAddr, 0, sizeof(servAddr));
memset(&_controllerAddr, 0, sizeof(_controllerAddr));
// socket creation
_udpSock = socket(PF_INET, SOCK_DGRAM, 0);
if (_udpSock < 0)
{
printf("opening socket failed!\n");
return false;
}
// use local server port
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(port);
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(_udpSock, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0)
{
printf("binding port number %d failed!\n", port);
close();
return false;
}
// initialize the socket properly
_controllerAddr.sin_family = AF_INET;
_controllerAddr.sin_port = htons(port);
if (controllerAddress)
{
#ifndef __MINGW32__
inet_pton(AF_INET, controllerAddress, &_controllerAddr.sin_addr);
#else
_controllerAddr.sin_addr.s_addr = inet_addr(controllerAddress);
#endif
if ( connect(_udpSock, (struct sockaddr *)&_controllerAddr, sizeof(_controllerAddr)) < 0)
{
printf("connecting to controller with address %s failed !\n", controllerAddress);
close();
return false;
}
}
else
{
_controllerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
}
return true;
}
//******************************************************************************
void UdpConnection::close()
{
if (isOpen())
{
#ifdef WIN32
closesocket(_udpSock);
#else
::close(_udpSock);
#endif
}
_udpSock = -1;
}
//******************************************************************************
bool UdpConnection::isOpen() const
{
return (_udpSock >= 0);
}
//******************************************************************************
int UdpConnection::receive(char *buffer, int maxSize)
{
if (isOpen())
{
/** HAVE_SOCKLEN_T
Yes - unbelievable: There are differences in standard calling parameters (types) to recvfrom
Windows winsock, VxWorks and QNX use int
newer Posix (most Linuxes) use socklen_t
*/
#ifdef HAVE_SOCKLEN_T
socklen_t sockAddrSize;
#else
int sockAddrSize;
#endif
sockAddrSize = static_cast<socklen_t>(sizeof(struct sockaddr_in));
/** check for timeout
Because SO_RCVTIMEO is in Windows not correctly implemented, select is used for the receive time out.
If a timeout greater than 0 is given, wait until the timeout is reached or a message was received.
If t, abort the function with an error.
*/
if(_receiveTimeout > 0)
{
// Set up struct timeval
struct timeval tv;
tv.tv_sec = _receiveTimeout / 1000;
tv.tv_usec = (_receiveTimeout % 1000) * 1000;
// initialize file descriptor
/**
* Replace FD_ZERO with memset, because bzero is not available for VxWorks
* User Space Aplications(RTPs). Therefore the macro FD_ZERO does not compile.
*/
#ifndef VXWORKS
FD_ZERO(&_filedescriptor);
#else
memset((char *)(&_filedescriptor), 0, sizeof(*(&_filedescriptor)));
#endif
FD_SET(_udpSock, &_filedescriptor);
// wait until something was received
int numberActiveFileDescr = select(_udpSock+1, &_filedescriptor,NULL,NULL,&tv);
// 0 indicates a timeout
if(numberActiveFileDescr == 0)
{
printf("The connection has timed out. Timeout is %d\n", _receiveTimeout);
return -1;
}
// a negative value indicates an error
else if(numberActiveFileDescr == -1)
{
printf("An error has occured \n");
return -1;
}
}
return recvfrom(_udpSock, buffer, maxSize, 0, (struct sockaddr *)&_controllerAddr, &sockAddrSize);
}
return -1;
}
//******************************************************************************
bool UdpConnection::send(const char* buffer, int size)
{
if ((isOpen()) && (ntohs(_controllerAddr.sin_port) != 0))
{
int sent = sendto(_udpSock, const_cast<char*>(buffer), size, 0, (struct sockaddr *)&_controllerAddr, sizeof(_controllerAddr));
if (sent == size)
{
return true;
}
}
return false;
}
@@ -0,0 +1,150 @@
nanopb-0.2.8 (2014-05-20)
Fix security issue with PB_ENABLE_MALLOC. (issue 117)
Add option to not add timestamps to .pb.h and .pb.c preambles. (issue 115)
Documentation updates
Improved tests
nanopb-0.2.7 (2014-04-07)
Fix bug with default values for extension fields (issue 111)
Fix some MISRA-C warnings (issue 91)
Implemented optional malloc() support (issue 80)
Changed pointer-type bytes field datatype
Add a "found" field to pb_extension_t (issue 112)
Add convenience function pb_get_encoded_size() (issue 16)
nanopb-0.2.6 (2014-02-15)
Fix generator error with bytes callback fields (issue 99)
Fix warnings about large integer constants (issue 102)
Add comments to where STATIC_ASSERT is used (issue 96)
Add warning about unknown field names on .options (issue 105)
Move descriptor.proto to google/protobuf subdirectory (issue 104)
Improved tests
nanopb-0.2.5 (2014-01-01)
Fix a bug with encoding negative values in int32 fields (issue 97)
Create binary packages of the generator + dependencies (issue 47)
Add support for pointer-type fields to the encoder (part of issue 80)
Fixed path in FindNanopb.cmake (issue 94)
Improved tests
nanopb-0.2.4 (2013-11-07)
Remove the deprecated NANOPB_INTERNALS functions from public API.
Document the security model.
Check array and bytes max sizes when encoding (issue 90)
Add #defines for maximum encoded message size (issue 89)
Add #define tags for extension fields (issue 93)
Fix MISRA C violations (issue 91)
Clean up pb_field_t definition with typedefs.
nanopb-0.2.3 (2013-09-18)
Improve compatibility by removing ternary operator from initializations (issue 88)
Fix build error on Visual C++ (issue 84, patch by Markus Schwarzenberg)
Don't stop on unsupported extension fields (issue 83)
Add an example pb_syshdr.h file for non-C99 compilers
Reorganize tests and examples into subfolders (issue 63)
Switch from Makefiles to scons for building the tests
Make the tests buildable on Windows
nanopb-0.2.2 (2013-08-18)
Add support for extension fields (issue 17)
Fix unknown fields in empty message (issue 78)
Include the field tags in the generated .pb.h file.
Add pb_decode_delimited and pb_encode_delimited wrapper functions (issue 74)
Add a section in top of pb.h for changing compilation settings (issue 76)
Documentation improvements (issues 12, 77 and others)
Improved tests
nanopb-0.2.1 (2013-04-14)
NOTE: The default callback function signature has changed.
If you don't want to update your code, define PB_OLD_CALLBACK_STYLE.
Change the callback function to use void** (issue 69)
Add support for defining the nanopb options in a separate file (issue 12)
Add support for packed structs in IAR and MSVC (in addition to GCC) (issue 66)
Implement error message support for the encoder side (issue 7)
Handle unterminated strings when encoding (issue 68)
Fix bug with empty strings in repeated string callbacks (issue 73)
Fix regression in 0.2.0 with optional callback fields (issue 70)
Fix bugs with empty message types (issues 64, 65)
Fix some compiler warnings on clang (issue 67)
Some portability improvements (issues 60, 62)
Various new generator options
Improved tests
nanopb-0.2.0 (2013-03-02)
NOTE: This release requires you to regenerate all .pb.c
files. Files generated by older versions will not
compile anymore.
Reformat generated .pb.c files using macros (issue 58)
Rename PB_HTYPE_ARRAY -> PB_HTYPE_REPEATED
Separate PB_HTYPE to PB_ATYPE and PB_HTYPE
Move STATIC_ASSERTs to .pb.c file
Added CMake file (by Pavel Ilin)
Add option to give file extension to generator (by Michael Haberler)
Documentation updates
nanopb-0.1.9 (2013-02-13)
Fixed error message bugs (issues 52, 56)
Sanitize #ifndef filename (issue 50)
Performance improvements
Add compile-time option PB_BUFFER_ONLY
Add Java package name to nanopb.proto
Check for sizeof(double) == 8 (issue 54)
Added generator option to ignore some fields. (issue 51)
Added generator option to make message structs packed. (issue 49)
Add more test cases.
nanopb-0.1.8 (2012-12-13)
Fix bugs in the enum short names introduced in 0.1.7 (issues 42, 43)
Fix STATIC_ASSERT macro when using multiple .proto files. (issue 41)
Fix missing initialization of istream.errmsg
Make tests/Makefile work for non-gcc compilers (issue 40)
nanopb-0.1.7 (2012-11-11)
Remove "skip" mode from pb_istream_t callbacks. Example implementation had a bug. (issue 37)
Add option to use shorter names for enum values (issue 38)
Improve options support in generator (issues 12, 30)
Add nanopb version number to generated files (issue 36)
Add extern "C" to generated headers (issue 35)
Add names for structs to allow forward declaration (issue 39)
Add buffer size check in example (issue 34)
Fix build warnings on MS compilers (issue 33)
nanopb-0.1.6 (2012-09-02)
Reorganize the field decoder interface (issue 2)
Improve performance in submessage decoding (issue 28)
Implement error messages in the decoder side (issue 7)
Extended testcases (alltypes test is now complete).
Fix some compiler warnings (issues 25, 26, 27, 32).
nanopb-0.1.5 (2012-08-04)
Fix bug in decoder with packed arrays (issue 23).
Extended testcases.
Fix some compiler warnings.
nanopb-0.1.4 (2012-07-05)
Add compile-time options for easy-to-use >255 field support.
Improve the detection of missing required fields.
Added example on how to handle union messages.
Fix generator error with .proto without messages.
Fix problems that stopped the code from compiling with some compilers.
Fix some compiler warnings.
nanopb-0.1.3 (2012-06-12)
Refactor the field encoder interface.
Improve generator error messages (issue 5)
Add descriptor.proto into the #include exclusion list
Fix some compiler warnings.
nanopb-0.1.2 (2012-02-15)
Make the generator to generate include for other .proto files (issue 4).
Fixed generator not working on Windows (issue 3)
nanopb-0.1.1 (2012-01-14)
Fixed bug in encoder with 'bytes' fields (issue 1).
Fixed a bug in the generator that caused a compiler error on sfixed32 and sfixed64 fields.
Extended testcases.
nanopb-0.1.0 (2012-01-06)
First stable release.
@@ -0,0 +1,20 @@
Copyright (c) 2011 Petteri Aimonen <jpa at nanopb.mail.kapsi.fi>
This software is provided 'as-is', without any express or
implied warranty. In no event will the authors be held liable
for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
@@ -0,0 +1,15 @@
BASE_DIR = ../..
include $(BASE_DIR)/build/GNUMake/paths.mak
include $(BASE_DIR)/build/GNUMake/$(TOOLS_MAK)
CC_SRC = pb_encode.c \
pb_decode.c
CFLAGS +=
LDFLAGS +=
################################################################################
### Include general makefile (at the end)
################################################################################
include $(BASE_DIR)/build/GNUMake/rules.mak
@@ -0,0 +1,61 @@
Nanopb is a small code-size Protocol Buffers implementation in ansi C. It is
especially suitable for use in microcontrollers, but fits any memory
restricted system.
Homepage: http://kapsi.fi/~jpa/nanopb/
Using the nanopb library
========================
To use the nanopb library, you need to do two things:
1) Compile your .proto files for nanopb, using protoc.
2) Include pb_encode.c and pb_decode.c in your project.
The easiest way to get started is to study the project in "examples/simple".
It contains a Makefile, which should work directly under most Linux systems.
However, for any other kind of build system, see the manual steps in
README.txt in that folder.
Using the Protocol Buffers compiler (protoc)
============================================
The nanopb generator is implemented as a plugin for the Google's own protoc
compiler. This has the advantage that there is no need to reimplement the
basic parsing of .proto files. However, it does mean that you need the
Google's protobuf library in order to run the generator.
If you have downloaded a binary package for nanopb (either Windows, Linux or
Mac OS X version), the 'protoc' binary is included in the 'generator-bin'
folder. In this case, you are ready to go. Simply run this command:
generator-bin/protoc --nanopb_out=. myprotocol.proto
However, if you are using a git checkout or a plain source distribution, you
need to provide your own version of protoc and the Google's protobuf library.
On Linux, the necessary packages are protobuf-compiler and python-protobuf.
On Windows, you can either build Google's protobuf library from source or use
one of the binary distributions of it. In either case, if you use a separate
protoc, you need to manually give the path to nanopb generator:
protoc --plugin=protoc-gen-nanopb=nanopb/generator/protoc-gen-nanopb ...
Running the tests
=================
If you want to perform further development of the nanopb core, or to verify
its functionality using your compiler and platform, you'll want to run the
test suite. The build rules for the test suite are implemented using Scons,
so you need to have that installed. To run the tests:
cd tests
scons
This will show the progress of various test cases. If the output does not
end in an error, the test cases were successful.
@@ -0,0 +1,519 @@
/* Common parts of the nanopb library. Most of these are quite low-level
* stuff. For the high-level interface, see pb_encode.h and pb_decode.h.
*/
#ifndef _PB_H_
#define _PB_H_
/*****************************************************************
* Nanopb compilation time options. You can change these here by *
* uncommenting the lines, or on the compiler command line. *
*****************************************************************/
/* Enable support for dynamically allocated fields */
/* #define PB_ENABLE_MALLOC 1 */
/* Define this if your CPU architecture is big endian, i.e. it
* stores the most-significant byte first. */
/* #define __BIG_ENDIAN__ 1 */
/* Increase the number of required fields that are tracked.
* A compiler warning will tell if you need this. */
/* #define PB_MAX_REQUIRED_FIELDS 256 */
/* Add support for tag numbers > 255 and fields larger than 255 bytes. */
/* #define PB_FIELD_16BIT 1 */
/* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */
/* #define PB_FIELD_32BIT 1 */
/* Disable support for error messages in order to save some code space. */
/* #define PB_NO_ERRMSG 1 */
/* Disable support for custom streams (support only memory buffers). */
/* #define PB_BUFFER_ONLY 1 */
/* Switch back to the old-style callback function signature.
* This was the default until nanopb-0.2.1. */
/* #define PB_OLD_CALLBACK_STYLE */
/******************************************************************
* You usually don't need to change anything below this line. *
* Feel free to look around and use the defined macros, though. *
******************************************************************/
/* Version of the nanopb library. Just in case you want to check it in
* your own program. */
#define NANOPB_VERSION nanopb-0.2.8
/* Include all the system headers needed by nanopb. You will need the
* definitions of the following:
* - strlen, memcpy, memset functions
* - [u]int8_t, [u]int16_t, [u]int32_t, [u]int64_t
* - size_t
* - bool
*
* If you don't have the standard header files, you can instead provide
* a custom header that defines or includes all this. In that case,
* define PB_SYSTEM_HEADER to the path of this file.
*/
#ifdef PB_SYSTEM_HEADER
#include PB_SYSTEM_HEADER
#else
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#ifdef PB_ENABLE_MALLOC
#include <stdlib.h>
#endif
#endif
/* Macro for defining packed structures (compiler dependent).
* This just reduces memory requirements, but is not required.
*/
#if defined(__GNUC__) || defined(__clang__)
/* For GCC and clang */
# define PB_PACKED_STRUCT_START
# define PB_PACKED_STRUCT_END
# define pb_packed __attribute__((packed))
#elif defined(__ICCARM__)
/* For IAR ARM compiler */
# define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)")
# define PB_PACKED_STRUCT_END _Pragma("pack(pop)")
# define pb_packed
#elif defined(_MSC_VER) && (_MSC_VER >= 1500)
/* For Microsoft Visual C++ */
# define PB_PACKED_STRUCT_START __pragma(pack(push, 1))
# define PB_PACKED_STRUCT_END __pragma(pack(pop))
# define pb_packed
#else
/* Unknown compiler */
# define PB_PACKED_STRUCT_START
# define PB_PACKED_STRUCT_END
# define pb_packed
#endif
/* Handly macro for suppressing unreferenced-parameter compiler warnings. */
#ifndef UNUSED
#define UNUSED(x) (void)(x)
#endif
/* Compile-time assertion, used for checking compatible compilation options.
* If this does not work properly on your compiler, use #define STATIC_ASSERT
* to disable it.
*
* But before doing that, check carefully the error message / place where it
* comes from to see if the error has a real cause. Unfortunately the error
* message is not always very clear to read, but you can see the reason better
* in the place where the STATIC_ASSERT macro was called.
*/
#ifndef STATIC_ASSERT
#define STATIC_ASSERT(COND,MSG) typedef char STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1];
#define STATIC_ASSERT_MSG(MSG, LINE, COUNTER) STATIC_ASSERT_MSG_(MSG, LINE, COUNTER)
#define STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) static_assertion_##MSG##LINE##COUNTER
#endif
/* Number of required fields to keep track of. */
#ifndef PB_MAX_REQUIRED_FIELDS
#define PB_MAX_REQUIRED_FIELDS 64
#endif
#if PB_MAX_REQUIRED_FIELDS < 64
#error You should not lower PB_MAX_REQUIRED_FIELDS from the default value (64).
#endif
/* List of possible field types. These are used in the autogenerated code.
* Least-significant 4 bits tell the scalar type
* Most-significant 4 bits specify repeated/required/packed etc.
*/
typedef uint8_t pb_type_t;
/**** Field data types ****/
/* Numeric types */
#define PB_LTYPE_VARINT 0x00 /* int32, int64, enum, bool */
#define PB_LTYPE_UVARINT 0x01 /* uint32, uint64 */
#define PB_LTYPE_SVARINT 0x02 /* sint32, sint64 */
#define PB_LTYPE_FIXED32 0x03 /* fixed32, sfixed32, float */
#define PB_LTYPE_FIXED64 0x04 /* fixed64, sfixed64, double */
/* Marker for last packable field type. */
#define PB_LTYPE_LAST_PACKABLE 0x04
/* Byte array with pre-allocated buffer.
* data_size is the length of the allocated PB_BYTES_ARRAY structure. */
#define PB_LTYPE_BYTES 0x05
/* String with pre-allocated buffer.
* data_size is the maximum length. */
#define PB_LTYPE_STRING 0x06
/* Submessage
* submsg_fields is pointer to field descriptions */
#define PB_LTYPE_SUBMESSAGE 0x07
/* Extension pseudo-field
* The field contains a pointer to pb_extension_t */
#define PB_LTYPE_EXTENSION 0x08
/* Number of declared LTYPES */
#define PB_LTYPES_COUNT 9
#define PB_LTYPE_MASK 0x0F
/**** Field repetition rules ****/
#define PB_HTYPE_REQUIRED 0x00
#define PB_HTYPE_OPTIONAL 0x10
#define PB_HTYPE_REPEATED 0x20
#define PB_HTYPE_MASK 0x30
/**** Field allocation types ****/
#define PB_ATYPE_STATIC 0x00
#define PB_ATYPE_POINTER 0x80
#define PB_ATYPE_CALLBACK 0x40
#define PB_ATYPE_MASK 0xC0
#define PB_ATYPE(x) ((x) & PB_ATYPE_MASK)
#define PB_HTYPE(x) ((x) & PB_HTYPE_MASK)
#define PB_LTYPE(x) ((x) & PB_LTYPE_MASK)
/* Data type used for storing sizes of struct fields
* and array counts.
*/
#if defined(PB_FIELD_32BIT)
typedef uint32_t pb_size_t;
typedef int32_t pb_ssize_t;
#elif defined(PB_FIELD_16BIT)
typedef uint16_t pb_size_t;
typedef int16_t pb_ssize_t;
#else
typedef uint8_t pb_size_t;
typedef int8_t pb_ssize_t;
#endif
/* This structure is used in auto-generated constants
* to specify struct fields.
* You can change field sizes if you need structures
* larger than 256 bytes or field tags larger than 256.
* The compiler should complain if your .proto has such
* structures. Fix that by defining PB_FIELD_16BIT or
* PB_FIELD_32BIT.
*/
PB_PACKED_STRUCT_START
typedef struct _pb_field_t pb_field_t;
struct _pb_field_t {
pb_size_t tag;
pb_type_t type;
pb_size_t data_offset; /* Offset of field data, relative to previous field. */
pb_ssize_t size_offset; /* Offset of array size or has-boolean, relative to data */
pb_size_t data_size; /* Data size in bytes for a single item */
pb_size_t array_size; /* Maximum number of entries in array */
/* Field definitions for submessage
* OR default value for all other non-array, non-callback types
* If null, then field will zeroed. */
const void *ptr;
} pb_packed;
PB_PACKED_STRUCT_END
/* Make sure that the standard integer types are of the expected sizes.
* All kinds of things may break otherwise.. atleast all fixed* types.
*
* If you get errors here, it probably means that your stdint.h is not
* correct for your platform.
*/
STATIC_ASSERT(sizeof(int8_t) == 1, INT8_T_WRONG_SIZE)
STATIC_ASSERT(sizeof(uint8_t) == 1, UINT8_T_WRONG_SIZE)
STATIC_ASSERT(sizeof(int16_t) == 2, INT16_T_WRONG_SIZE)
STATIC_ASSERT(sizeof(uint16_t) == 2, UINT16_T_WRONG_SIZE)
STATIC_ASSERT(sizeof(int32_t) == 4, INT32_T_WRONG_SIZE)
STATIC_ASSERT(sizeof(uint32_t) == 4, UINT32_T_WRONG_SIZE)
STATIC_ASSERT(sizeof(int64_t) == 8, INT64_T_WRONG_SIZE)
STATIC_ASSERT(sizeof(uint64_t) == 8, UINT64_T_WRONG_SIZE)
/* This structure is used for 'bytes' arrays.
* It has the number of bytes in the beginning, and after that an array.
* Note that actual structs used will have a different length of bytes array.
*/
#define PB_BYTES_ARRAY_T(n) struct { size_t size; uint8_t bytes[n]; }
#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes))
struct _pb_bytes_array_t {
size_t size;
uint8_t bytes[1];
};
typedef struct _pb_bytes_array_t pb_bytes_array_t;
/* This structure is used for giving the callback function.
* It is stored in the message structure and filled in by the method that
* calls pb_decode.
*
* The decoding callback will be given a limited-length stream
* If the wire type was string, the length is the length of the string.
* If the wire type was a varint/fixed32/fixed64, the length is the length
* of the actual value.
* The function may be called multiple times (especially for repeated types,
* but also otherwise if the message happens to contain the field multiple
* times.)
*
* The encoding callback will receive the actual output stream.
* It should write all the data in one call, including the field tag and
* wire type. It can write multiple fields.
*
* The callback can be null if you want to skip a field.
*/
typedef struct _pb_istream_t pb_istream_t;
typedef struct _pb_ostream_t pb_ostream_t;
typedef struct _pb_callback_t pb_callback_t;
struct _pb_callback_t {
#ifdef PB_OLD_CALLBACK_STYLE
/* Deprecated since nanopb-0.2.1 */
union {
bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void *arg);
bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, const void *arg);
} funcs;
#else
/* New function signature, which allows modifying arg contents in callback. */
union {
bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg);
bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg);
} funcs;
#endif
/* Free arg for use by callback */
void *arg;
};
/* Wire types. Library user needs these only in encoder callbacks. */
typedef enum {
PB_WT_VARINT = 0,
PB_WT_64BIT = 1,
PB_WT_STRING = 2,
PB_WT_32BIT = 5
} pb_wire_type_t;
/* Structure for defining the handling of unknown/extension fields.
* Usually the pb_extension_type_t structure is automatically generated,
* while the pb_extension_t structure is created by the user. However,
* if you want to catch all unknown fields, you can also create a custom
* pb_extension_type_t with your own callback.
*/
typedef struct _pb_extension_type_t pb_extension_type_t;
typedef struct _pb_extension_t pb_extension_t;
struct _pb_extension_type_t {
/* Called for each unknown field in the message.
* If you handle the field, read off all of its data and return true.
* If you do not handle the field, do not read anything and return true.
* If you run into an error, return false.
* Set to NULL for default handler.
*/
bool (*decode)(pb_istream_t *stream, pb_extension_t *extension,
uint32_t tag, pb_wire_type_t wire_type);
/* Called once after all regular fields have been encoded.
* If you have something to write, do so and return true.
* If you do not have anything to write, just return true.
* If you run into an error, return false.
* Set to NULL for default handler.
*/
bool (*encode)(pb_ostream_t *stream, const pb_extension_t *extension);
/* Free field for use by the callback. */
const void *arg;
};
struct _pb_extension_t {
/* Type describing the extension field. Usually you'll initialize
* this to a pointer to the automatically generated structure. */
const pb_extension_type_t *type;
/* Destination for the decoded data. This must match the datatype
* of the extension field. */
void *dest;
/* Pointer to the next extension handler, or NULL.
* If this extension does not match a field, the next handler is
* automatically called. */
pb_extension_t *next;
/* The decoder sets this to true if the extension was found.
* Ignored for encoding. */
bool found;
};
/* Memory allocation functions to use. You can define pb_realloc and
* pb_free to custom functions if you want. */
#ifdef PB_ENABLE_MALLOC
# ifndef pb_realloc
# define pb_realloc(ptr, size) realloc(ptr, size)
# endif
# ifndef pb_free
# define pb_free(ptr) free(ptr)
# endif
#endif
/* These macros are used to declare pb_field_t's in the constant array. */
/* Size of a structure member, in bytes. */
#define pb_membersize(st, m) (sizeof ((st*)0)->m)
/* Number of entries in an array. */
#define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0]))
/* Delta from start of one member to the start of another member. */
#define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2))
/* Marks the end of the field list */
#define PB_LAST_FIELD {0,(pb_type_t) 0,0,0,0,0,0}
/* Macros for filling in the data_offset field */
/* data_offset for first field in a message */
#define PB_DATAOFFSET_FIRST(st, m1, m2) (offsetof(st, m1))
/* data_offset for subsequent fields */
#define PB_DATAOFFSET_OTHER(st, m1, m2) (offsetof(st, m1) - offsetof(st, m2) - pb_membersize(st, m2))
/* Choose first/other based on m1 == m2 (deprecated, remains for backwards compatibility) */
#define PB_DATAOFFSET_CHOOSE(st, m1, m2) (int)(offsetof(st, m1) == offsetof(st, m2) \
? PB_DATAOFFSET_FIRST(st, m1, m2) \
: PB_DATAOFFSET_OTHER(st, m1, m2))
/* Required fields are the simplest. They just have delta (padding) from
* previous field end, and the size of the field. Pointer is used for
* submessages and default values.
*/
#define PB_REQUIRED_STATIC(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \
fd, 0, pb_membersize(st, m), 0, ptr}
/* Optional fields add the delta to the has_ variable. */
#define PB_OPTIONAL_STATIC(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \
fd, \
pb_delta(st, has_ ## m, m), \
pb_membersize(st, m), 0, ptr}
/* Repeated fields have a _count field and also the maximum number of entries. */
#define PB_REPEATED_STATIC(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | ltype, \
fd, \
pb_delta(st, m ## _count, m), \
pb_membersize(st, m[0]), \
pb_arraysize(st, m), ptr}
/* Allocated fields carry the size of the actual data, not the pointer */
#define PB_REQUIRED_POINTER(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_POINTER | PB_HTYPE_REQUIRED | ltype, \
fd, 0, pb_membersize(st, m[0]), 0, ptr}
/* Optional fields don't need a has_ variable, as information would be redundant */
#define PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \
fd, 0, pb_membersize(st, m[0]), 0, ptr}
/* Repeated fields have a _count field and a pointer to array of pointers */
#define PB_REPEATED_POINTER(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_POINTER | PB_HTYPE_REPEATED | ltype, \
fd, pb_delta(st, m ## _count, m), \
pb_membersize(st, m[0]), 0, ptr}
/* Callbacks are much like required fields except with special datatype. */
#define PB_REQUIRED_CALLBACK(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_CALLBACK | PB_HTYPE_REQUIRED | ltype, \
fd, 0, pb_membersize(st, m), 0, ptr}
#define PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \
fd, 0, pb_membersize(st, m), 0, ptr}
#define PB_REPEATED_CALLBACK(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_CALLBACK | PB_HTYPE_REPEATED | ltype, \
fd, 0, pb_membersize(st, m), 0, ptr}
/* Optional extensions don't have the has_ field, as that would be redundant. */
#define PB_OPTEXT_STATIC(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \
0, \
0, \
pb_membersize(st, m), 0, ptr}
#define PB_OPTEXT_CALLBACK(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \
0, 0, pb_membersize(st, m), 0, ptr}
/* The mapping from protobuf types to LTYPEs is done using these macros. */
#define PB_LTYPE_MAP_BOOL PB_LTYPE_VARINT
#define PB_LTYPE_MAP_BYTES PB_LTYPE_BYTES
#define PB_LTYPE_MAP_DOUBLE PB_LTYPE_FIXED64
#define PB_LTYPE_MAP_ENUM PB_LTYPE_VARINT
#define PB_LTYPE_MAP_FIXED32 PB_LTYPE_FIXED32
#define PB_LTYPE_MAP_FIXED64 PB_LTYPE_FIXED64
#define PB_LTYPE_MAP_FLOAT PB_LTYPE_FIXED32
#define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT
#define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT
#define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE
#define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32
#define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64
#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT
#define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT
#define PB_LTYPE_MAP_STRING PB_LTYPE_STRING
#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT
#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT
#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION
/* This is the actual macro used in field descriptions.
* It takes these arguments:
* - Field tag number
* - Field type: BOOL, BYTES, DOUBLE, ENUM, FIXED32, FIXED64,
* FLOAT, INT32, INT64, MESSAGE, SFIXED32, SFIXED64
* SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION
* - Field rules: REQUIRED, OPTIONAL or REPEATED
* - Allocation: STATIC or CALLBACK
* - Message name
* - Field name
* - Previous field name (or field name again for first field)
* - Pointer to default value or submsg fields.
*/
#define PB_FIELD(tag, type, rules, allocation, message, field, prevfield, ptr) \
PB_ ## rules ## _ ## allocation(tag, message, field, \
PB_DATAOFFSET_CHOOSE(message, field, prevfield), \
PB_LTYPE_MAP_ ## type, ptr)
/* This is a new version of the macro used by nanopb generator from
* version 0.2.3 onwards. It avoids the use of a ternary expression in
* the initialization, which confused some compilers.
*
* - Placement: FIRST or OTHER, depending on if this is the first field in structure.
*
*/
#define PB_FIELD2(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \
PB_ ## rules ## _ ## allocation(tag, message, field, \
PB_DATAOFFSET_ ## placement(message, field, prevfield), \
PB_LTYPE_MAP_ ## type, ptr)
/* These macros are used for giving out error messages.
* They are mostly a debugging aid; the main error information
* is the true/false return value from functions.
* Some code space can be saved by disabling the error
* messages if not used.
*/
#ifdef PB_NO_ERRMSG
#define PB_RETURN_ERROR(stream,msg) \
do {\
UNUSED(stream); \
return false; \
} while(0)
#define PB_GET_ERROR(stream) "(errmsg disabled)"
#else
#define PB_RETURN_ERROR(stream,msg) \
do {\
if ((stream)->errmsg == NULL) \
(stream)->errmsg = (msg); \
return false; \
} while(0)
#define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)")
#endif
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,149 @@
/* pb_decode.h: Functions to decode protocol buffers. Depends on pb_decode.c.
* The main function is pb_decode. You also need an input stream, and the
* field descriptions created by nanopb_generator.py.
*/
#ifndef _PB_DECODE_H_
#define _PB_DECODE_H_
#include "pb.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Structure for defining custom input streams. You will need to provide
* a callback function to read the bytes from your storage, which can be
* for example a file or a network socket.
*
* The callback must conform to these rules:
*
* 1) Return false on IO errors. This will cause decoding to abort.
* 2) You can use state to store your own data (e.g. buffer pointer),
* and rely on pb_read to verify that no-body reads past bytes_left.
* 3) Your callback may be used with substreams, in which case bytes_left
* is different than from the main stream. Don't use bytes_left to compute
* any pointers.
*/
struct _pb_istream_t
{
#ifdef PB_BUFFER_ONLY
/* Callback pointer is not used in buffer-only configuration.
* Having an int pointer here allows binary compatibility but
* gives an error if someone tries to assign callback function.
*/
int *callback;
#else
bool (*callback)(pb_istream_t *stream, uint8_t *buf, size_t count);
#endif
void *state; /* Free field for use by callback implementation */
size_t bytes_left;
#ifndef PB_NO_ERRMSG
const char *errmsg;
#endif
};
/***************************
* Main decoding functions *
***************************/
/* Decode a single protocol buffers message from input stream into a C structure.
* Returns true on success, false on any failure.
* The actual struct pointed to by dest must match the description in fields.
* Callback fields of the destination structure must be initialized by caller.
* All other fields will be initialized by this function.
*
* Example usage:
* MyMessage msg = {};
* uint8_t buffer[64];
* pb_istream_t stream;
*
* // ... read some data into buffer ...
*
* stream = pb_istream_from_buffer(buffer, count);
* pb_decode(&stream, MyMessage_fields, &msg);
*/
bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
/* Same as pb_decode, except does not initialize the destination structure
* to default values. This is slightly faster if you need no default values
* and just do memset(struct, 0, sizeof(struct)) yourself.
*
* This can also be used for 'merging' two messages, i.e. update only the
* fields that exist in the new message.
*
* Note: If this function returns with an error, it will not release any
* dynamically allocated fields. You will need to call pb_release() yourself.
*/
bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
/* Same as pb_decode, except expects the stream to start with the message size
* encoded as varint. Corresponds to parseDelimitedFrom() in Google's
* protobuf API.
*/
bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
#ifdef PB_ENABLE_MALLOC
/* Release any allocated pointer fields. If you use dynamic allocation, you should
* call this for any successfully decoded message when you are done with it. If
* pb_decode() returns with an error, the message is already released.
*/
void pb_release(const pb_field_t fields[], void *dest_struct);
#endif
/**************************************
* Functions for manipulating streams *
**************************************/
/* Create an input stream for reading from a memory buffer.
*
* Alternatively, you can use a custom stream that reads directly from e.g.
* a file or a network socket.
*/
pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize);
/* Function to read from a pb_istream_t. You can use this if you need to
* read some custom header data, or to read data in field callbacks.
*/
bool pb_read(pb_istream_t *stream, uint8_t *buf, size_t count);
/************************************************
* Helper functions for writing field callbacks *
************************************************/
/* Decode the tag for the next field in the stream. Gives the wire type and
* field tag. At end of the message, returns false and sets eof to true. */
bool pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof);
/* Skip the field payload data, given the wire type. */
bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type);
/* Decode an integer in the varint format. This works for bool, enum, int32,
* int64, uint32 and uint64 field types. */
bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest);
/* Decode an integer in the zig-zagged svarint format. This works for sint32
* and sint64. */
bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest);
/* Decode a fixed32, sfixed32 or float value. You need to pass a pointer to
* a 4-byte wide C variable. */
bool pb_decode_fixed32(pb_istream_t *stream, void *dest);
/* Decode a fixed64, sfixed64 or double value. You need to pass a pointer to
* a 8-byte wide C variable. */
bool pb_decode_fixed64(pb_istream_t *stream, void *dest);
/* Make a limited-length substream for reading a PB_WT_STRING field. */
bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream);
void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
@@ -0,0 +1,671 @@
/* pb_encode.c -- encode a protobuf using minimal resources
*
* 2011 Petteri Aimonen <jpa@kapsi.fi>
*/
#include "pb.h"
#include "pb_encode.h"
/* Use the GCC warn_unused_result attribute to check that all return values
* are propagated correctly. On other compilers and gcc before 3.4.0 just
* ignore the annotation.
*/
#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
#define checkreturn
#else
#define checkreturn __attribute__((warn_unused_result))
#endif
/**************************************
* Declarations internal to this file *
**************************************/
typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn;
static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count);
static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func);
static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension);
static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src);
static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src);
static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src);
static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src);
static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src);
/* --- Function pointers to field encoders ---
* Order in the array must match pb_action_t LTYPE numbering.
*/
static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = {
&pb_enc_varint,
&pb_enc_uvarint,
&pb_enc_svarint,
&pb_enc_fixed32,
&pb_enc_fixed64,
&pb_enc_bytes,
&pb_enc_string,
&pb_enc_submessage,
NULL /* extensions */
};
/*******************************
* pb_ostream_t implementation *
*******************************/
static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
{
uint8_t *dest = (uint8_t*)stream->state;
stream->state = dest + count;
while (count--)
*dest++ = *buf++;
return true;
}
pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize)
{
pb_ostream_t stream;
#ifdef PB_BUFFER_ONLY
stream.callback = (void*)1; /* Just a marker value */
#else
stream.callback = &buf_write;
#endif
stream.state = buf;
stream.max_size = bufsize;
stream.bytes_written = 0;
#ifndef PB_NO_ERRMSG
stream.errmsg = NULL;
#endif
return stream;
}
bool checkreturn pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
{
if (stream->callback != NULL)
{
if (stream->bytes_written + count > stream->max_size)
PB_RETURN_ERROR(stream, "stream full");
#ifdef PB_BUFFER_ONLY
if (!buf_write(stream, buf, count))
PB_RETURN_ERROR(stream, "io error");
#else
if (!stream->callback(stream, buf, count))
PB_RETURN_ERROR(stream, "io error");
#endif
}
stream->bytes_written += count;
return true;
}
/*************************
* Encode a single field *
*************************/
/* Encode a static array. Handles the size calculations and possible packing. */
static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field,
const void *pData, size_t count, pb_encoder_t func)
{
size_t i;
const void *p;
size_t size;
if (count == 0)
return true;
if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size)
PB_RETURN_ERROR(stream, "array max size exceeded");
/* We always pack arrays if the datatype allows it. */
if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
{
if (!pb_encode_tag(stream, PB_WT_STRING, field->tag))
return false;
/* Determine the total size of packed array. */
if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32)
{
size = 4 * count;
}
else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
{
size = 8 * count;
}
else
{
pb_ostream_t sizestream = PB_OSTREAM_SIZING;
p = pData;
for (i = 0; i < count; i++)
{
if (!func(&sizestream, field, p))
return false;
p = (const char*)p + field->data_size;
}
size = sizestream.bytes_written;
}
if (!pb_encode_varint(stream, (uint64_t)size))
return false;
if (stream->callback == NULL)
return pb_write(stream, NULL, size); /* Just sizing.. */
/* Write the data */
p = pData;
for (i = 0; i < count; i++)
{
if (!func(stream, field, p))
return false;
p = (const char*)p + field->data_size;
}
}
else
{
p = pData;
for (i = 0; i < count; i++)
{
if (!pb_encode_tag_for_field(stream, field))
return false;
/* Normally the data is stored directly in the array entries, but
* for pointer-type string and bytes fields, the array entries are
* actually pointers themselves also. So we have to dereference once
* more to get to the actual data. */
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER &&
(PB_LTYPE(field->type) == PB_LTYPE_STRING ||
PB_LTYPE(field->type) == PB_LTYPE_BYTES))
{
if (!func(stream, field, *(const void* const*)p))
return false;
}
else
{
if (!func(stream, field, p))
return false;
}
p = (const char*)p + field->data_size;
}
}
return true;
}
/* Encode a field with static or pointer allocation, i.e. one whose data
* is available to the encoder directly. */
static bool checkreturn encode_basic_field(pb_ostream_t *stream,
const pb_field_t *field, const void *pData)
{
pb_encoder_t func;
const void *pSize;
bool implicit_has = true;
func = PB_ENCODERS[PB_LTYPE(field->type)];
if (field->size_offset)
pSize = (const char*)pData + field->size_offset;
else
pSize = &implicit_has;
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
{
/* pData is a pointer to the field, which contains pointer to
* the data. If the 2nd pointer is NULL, it is interpreted as if
* the has_field was false.
*/
pData = *(const void* const*)pData;
implicit_has = (pData != NULL);
}
switch (PB_HTYPE(field->type))
{
case PB_HTYPE_REQUIRED:
if (!pData)
PB_RETURN_ERROR(stream, "missing required field");
if (!pb_encode_tag_for_field(stream, field))
return false;
if (!func(stream, field, pData))
return false;
break;
case PB_HTYPE_OPTIONAL:
/*
* KUKA adjustment for VxWorks
*/
if (*(const char*)pSize)
{
if (!pb_encode_tag_for_field(stream, field))
return false;
if (!func(stream, field, pData))
return false;
}
break;
case PB_HTYPE_REPEATED:
if (!encode_array(stream, field, pData, *(const size_t*)pSize, func))
return false;
break;
default:
PB_RETURN_ERROR(stream, "invalid field type");
}
return true;
}
/* Encode a field with callback semantics. This means that a user function is
* called to provide and encode the actual data. */
static bool checkreturn encode_callback_field(pb_ostream_t *stream,
const pb_field_t *field, const void *pData)
{
const pb_callback_t *callback = (const pb_callback_t*)pData;
#ifdef PB_OLD_CALLBACK_STYLE
const void *arg = callback->arg;
#else
void * const *arg = &(callback->arg);
#endif
if (callback->funcs.encode != NULL)
{
if (!callback->funcs.encode(stream, field, arg))
PB_RETURN_ERROR(stream, "callback error");
}
return true;
}
/* Encode a single field of any callback or static type. */
static bool checkreturn encode_field(pb_ostream_t *stream,
const pb_field_t *field, const void *pData)
{
switch (PB_ATYPE(field->type))
{
case PB_ATYPE_STATIC:
case PB_ATYPE_POINTER:
return encode_basic_field(stream, field, pData);
case PB_ATYPE_CALLBACK:
return encode_callback_field(stream, field, pData);
default:
PB_RETURN_ERROR(stream, "invalid field type");
}
}
/* Default handler for extension fields. Expects to have a pb_field_t
* pointer in the extension->type->arg field. */
static bool checkreturn default_extension_encoder(pb_ostream_t *stream,
const pb_extension_t *extension)
{
const pb_field_t *field = (const pb_field_t*)extension->type->arg;
return encode_field(stream, field, extension->dest);
}
/* Walk through all the registered extensions and give them a chance
* to encode themselves. */
static bool checkreturn encode_extension_field(pb_ostream_t *stream,
const pb_field_t *field, const void *pData)
{
const pb_extension_t *extension = *(const pb_extension_t* const *)pData;
UNUSED(field);
while (extension)
{
bool status;
if (extension->type->encode)
status = extension->type->encode(stream, extension);
else
status = default_extension_encoder(stream, extension);
if (!status)
return false;
extension = extension->next;
}
return true;
}
/*********************
* Encode all fields *
*********************/
bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
{
const pb_field_t *field = fields;
const void *pData = src_struct;
size_t prev_size = 0;
while (field->tag != 0)
{
pData = (const char*)pData + prev_size + field->data_offset;
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
prev_size = sizeof(const void*);
else
prev_size = field->data_size;
/* Special case for static arrays */
if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
PB_HTYPE(field->type) == PB_HTYPE_REPEATED)
{
prev_size *= field->array_size;
}
if (PB_LTYPE(field->type) == PB_LTYPE_EXTENSION)
{
/* Special case for the extension field placeholder */
if (!encode_extension_field(stream, field, pData))
return false;
}
else
{
/* Regular field */
if (!encode_field(stream, field, pData))
return false;
}
field++;
}
return true;
}
bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
{
return pb_encode_submessage(stream, fields, src_struct);
}
bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct)
{
pb_ostream_t stream = PB_OSTREAM_SIZING;
if (!pb_encode(&stream, fields, src_struct))
return false;
*size = stream.bytes_written;
return true;
}
/********************
* Helper functions *
********************/
bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value)
{
uint8_t buffer[10];
size_t i = 0;
if (value == 0)
return pb_write(stream, (uint8_t*)&value, 1);
while (value)
{
buffer[i] = (uint8_t)((value & 0x7F) | 0x80);
value >>= 7;
i++;
}
buffer[i-1] &= 0x7F; /* Unset top bit on last byte */
return pb_write(stream, buffer, i);
}
bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value)
{
uint64_t zigzagged;
if (value < 0)
zigzagged = ~((uint64_t)value << 1);
else
zigzagged = (uint64_t)value << 1;
return pb_encode_varint(stream, zigzagged);
}
bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value)
{
#ifdef __BIG_ENDIAN__
const uint8_t *bytes = value;
uint8_t lebytes[4];
lebytes[0] = bytes[3];
lebytes[1] = bytes[2];
lebytes[2] = bytes[1];
lebytes[3] = bytes[0];
return pb_write(stream, lebytes, 4);
#else
return pb_write(stream, (const uint8_t*)value, 4);
#endif
}
bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
{
#ifdef __BIG_ENDIAN__
const uint8_t *bytes = value;
uint8_t lebytes[8];
lebytes[0] = bytes[7];
lebytes[1] = bytes[6];
lebytes[2] = bytes[5];
lebytes[3] = bytes[4];
lebytes[4] = bytes[3];
lebytes[5] = bytes[2];
lebytes[6] = bytes[1];
lebytes[7] = bytes[0];
return pb_write(stream, lebytes, 8);
#else
return pb_write(stream, (const uint8_t*)value, 8);
#endif
}
bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
{
uint64_t tag = ((uint64_t)field_number << 3) | wiretype;
return pb_encode_varint(stream, tag);
}
bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field)
{
pb_wire_type_t wiretype;
switch (PB_LTYPE(field->type))
{
case PB_LTYPE_VARINT:
case PB_LTYPE_UVARINT:
case PB_LTYPE_SVARINT:
wiretype = PB_WT_VARINT;
break;
case PB_LTYPE_FIXED32:
wiretype = PB_WT_32BIT;
break;
case PB_LTYPE_FIXED64:
wiretype = PB_WT_64BIT;
break;
case PB_LTYPE_BYTES:
case PB_LTYPE_STRING:
case PB_LTYPE_SUBMESSAGE:
wiretype = PB_WT_STRING;
break;
default:
PB_RETURN_ERROR(stream, "invalid field type");
}
return pb_encode_tag(stream, wiretype, field->tag);
}
bool checkreturn pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size)
{
if (!pb_encode_varint(stream, (uint64_t)size))
return false;
return pb_write(stream, buffer, size);
}
bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
{
/* First calculate the message size using a non-writing substream. */
pb_ostream_t substream = PB_OSTREAM_SIZING;
size_t size;
bool status;
if (!pb_encode(&substream, fields, src_struct))
{
#ifndef PB_NO_ERRMSG
stream->errmsg = substream.errmsg;
#endif
return false;
}
size = substream.bytes_written;
if (!pb_encode_varint(stream, (uint64_t)size))
return false;
if (stream->callback == NULL)
return pb_write(stream, NULL, size); /* Just sizing */
if (stream->bytes_written + size > stream->max_size)
PB_RETURN_ERROR(stream, "stream full");
/* Use a substream to verify that a callback doesn't write more than
* what it did the first time. */
substream.callback = stream->callback;
substream.state = stream->state;
substream.max_size = size;
substream.bytes_written = 0;
#ifndef PB_NO_ERRMSG
substream.errmsg = NULL;
#endif
status = pb_encode(&substream, fields, src_struct);
stream->bytes_written += substream.bytes_written;
stream->state = substream.state;
#ifndef PB_NO_ERRMSG
stream->errmsg = substream.errmsg;
#endif
if (substream.bytes_written != size)
PB_RETURN_ERROR(stream, "submsg size changed");
return status;
}
/* Field encoders */
static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{
int64_t value = 0;
/* Cases 1 and 2 are for compilers that have smaller types for bool
* or enums. */
switch (field->data_size)
{
case 1: value = *(const int8_t*)src; break;
case 2: value = *(const int16_t*)src; break;
case 4: value = *(const int32_t*)src; break;
case 8: value = *(const int64_t*)src; break;
default: PB_RETURN_ERROR(stream, "invalid data_size");
}
return pb_encode_varint(stream, (uint64_t)value);
}
static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{
uint64_t value = 0;
switch (field->data_size)
{
case 4: value = *(const uint32_t*)src; break;
case 8: value = *(const uint64_t*)src; break;
default: PB_RETURN_ERROR(stream, "invalid data_size");
}
return pb_encode_varint(stream, value);
}
static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{
int64_t value = 0;
switch (field->data_size)
{
case 4: value = *(const int32_t*)src; break;
case 8: value = *(const int64_t*)src; break;
default: PB_RETURN_ERROR(stream, "invalid data_size");
}
return pb_encode_svarint(stream, value);
}
static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{
UNUSED(field);
return pb_encode_fixed64(stream, src);
}
static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{
UNUSED(field);
return pb_encode_fixed32(stream, src);
}
static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{
const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)src;
if (src == NULL)
{
/* Threat null pointer as an empty bytes field */
return pb_encode_string(stream, NULL, 0);
}
if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) > field->data_size)
{
PB_RETURN_ERROR(stream, "bytes size exceeded");
}
return pb_encode_string(stream, bytes->bytes, bytes->size);
}
static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{
/* strnlen() is not always available, so just use a loop */
size_t size = 0;
size_t max_size = field->data_size;
const char *p = (const char*)src;
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
max_size = (size_t)-1;
if (src == NULL)
{
size = 0; /* Threat null pointer as an empty string */
}
else
{
while (size < max_size && *p != '\0')
{
size++;
p++;
}
}
return pb_encode_string(stream, (const uint8_t*)src, size);
}
static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src)
{
if (field->ptr == NULL)
PB_RETURN_ERROR(stream, "invalid field descriptor");
return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src);
}
@@ -0,0 +1,154 @@
/* pb_encode.h: Functions to encode protocol buffers. Depends on pb_encode.c.
* The main function is pb_encode. You also need an output stream, and the
* field descriptions created by nanopb_generator.py.
*/
#ifndef _PB_ENCODE_H_
#define _PB_ENCODE_H_
#include "pb.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Structure for defining custom output streams. You will need to provide
* a callback function to write the bytes to your storage, which can be
* for example a file or a network socket.
*
* The callback must conform to these rules:
*
* 1) Return false on IO errors. This will cause encoding to abort.
* 2) You can use state to store your own data (e.g. buffer pointer).
* 3) pb_write will update bytes_written after your callback runs.
* 4) Substreams will modify max_size and bytes_written. Don't use them
* to calculate any pointers.
*/
struct _pb_ostream_t
{
#ifdef PB_BUFFER_ONLY
/* Callback pointer is not used in buffer-only configuration.
* Having an int pointer here allows binary compatibility but
* gives an error if someone tries to assign callback function.
* Also, NULL pointer marks a 'sizing stream' that does not
* write anything.
*/
int *callback;
#else
bool (*callback)(pb_ostream_t *stream, const uint8_t *buf, size_t count);
#endif
void *state; /* Free field for use by callback implementation. */
size_t max_size; /* Limit number of output bytes written (or use SIZE_MAX). */
size_t bytes_written; /* Number of bytes written so far. */
#ifndef PB_NO_ERRMSG
const char *errmsg;
#endif
};
/***************************
* Main encoding functions *
***************************/
/* Encode a single protocol buffers message from C structure into a stream.
* Returns true on success, false on any failure.
* The actual struct pointed to by src_struct must match the description in fields.
* All required fields in the struct are assumed to have been filled in.
*
* Example usage:
* MyMessage msg = {};
* uint8_t buffer[64];
* pb_ostream_t stream;
*
* msg.field1 = 42;
* stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
* pb_encode(&stream, MyMessage_fields, &msg);
*/
bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct);
/* Same as pb_encode, but prepends the length of the message as a varint.
* Corresponds to writeDelimitedTo() in Google's protobuf API.
*/
bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct);
/* Encode the message to get the size of the encoded data, but do not store
* the data. */
bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct);
/**************************************
* Functions for manipulating streams *
**************************************/
/* Create an output stream for writing into a memory buffer.
* The number of bytes written can be found in stream.bytes_written after
* encoding the message.
*
* Alternatively, you can use a custom stream that writes directly to e.g.
* a file or a network socket.
*/
pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize);
/* Pseudo-stream for measuring the size of a message without actually storing
* the encoded data.
*
* Example usage:
* MyMessage msg = {};
* pb_ostream_t stream = PB_OSTREAM_SIZING;
* pb_encode(&stream, MyMessage_fields, &msg);
* printf("Message size is %d\n", stream.bytes_written);
*/
#ifndef PB_NO_ERRMSG
#define PB_OSTREAM_SIZING {0,0,0,0,0}
#else
#define PB_OSTREAM_SIZING {0,0,0,0}
#endif
/* Function to write into a pb_ostream_t stream. You can use this if you need
* to append or prepend some custom headers to the message.
*/
bool pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count);
/************************************************
* Helper functions for writing field callbacks *
************************************************/
/* Encode field header based on type and field number defined in the field
* structure. Call this from the callback before writing out field contents. */
bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field);
/* Encode field header by manually specifing wire type. You need to use this
* if you want to write out packed arrays from a callback field. */
bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number);
/* Encode an integer in the varint format.
* This works for bool, enum, int32, int64, uint32 and uint64 field types. */
bool pb_encode_varint(pb_ostream_t *stream, uint64_t value);
/* Encode an integer in the zig-zagged svarint format.
* This works for sint32 and sint64. */
bool pb_encode_svarint(pb_ostream_t *stream, int64_t value);
/* Encode a string or bytes type field. For strings, pass strlen(s) as size. */
bool pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size);
/* Encode a fixed32, sfixed32 or float value.
* You need to pass a pointer to a 4-byte wide C variable. */
bool pb_encode_fixed32(pb_ostream_t *stream, const void *value);
/* Encode a fixed64, sfixed64 or double value.
* You need to pass a pointer to a 8-byte wide C variable. */
bool pb_encode_fixed64(pb_ostream_t *stream, const void *value);
/* Encode a submessage field.
* You need to pass the pb_field_t array and pointer to struct, just like
* with pb_encode(). This internally encodes the submessage twice, first to
* calculate message size and then to actually write it out.
*/
bool pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
@@ -0,0 +1,127 @@
/* This is an example of a header file for platforms/compilers that do
* not come with stdint.h/stddef.h/stdbool.h/string.h. To use it, define
* PB_SYSTEM_HEADER as "pb_syshdr.h", including the quotes, and add the
* extra folder to your include path.
*
* It is very likely that you will need to customize this file to suit
* your platform. For any compiler that supports C99, this file should
* not be necessary.
*
* KUKA: Added VXWORKS support
*/
#ifndef _PB_SYSHDR_H_
#define _PB_SYSHDR_H_
/* KUKA VxWorks 6.8 support */
#ifdef VXWORKS
#define HAVE_STRING_H
#define HAVE_STDLIB_H
#ifdef _WRS_KERNEL
#include <types/vxTypes.h> // int32_t, int64_t, ...
#define HAVE_STDINT_H_ALTERNATIVE
#define HAVE_STDDEF_H_ALTERNATIVE
#else
#define HAVE_STDINT_H
#define HAVE_STDDEF_H
#endif // _WRS_KERNEL
#endif // VXWORKS
/* KUKA: size_t is defined in stddef.h, stdlib.h or string.h */
#if !defined(HAVE_STDDEF_H) && !defined(HAVE_STDLIB_H) && !defined(HAVE_STRING_H)
typedef uint32_t size_t;
#endif
/* stdint.h subset */
#ifdef HAVE_STDINT_H
#include <stdint.h>
#else
#ifndef HAVE_STDINT_H_ALTERNATIVE
/* You will need to modify these to match the word size of your platform. */
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef signed int int32_t;
typedef unsigned int uint32_t;
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
#endif // HAVE_STDINT_H_ALTERNATIVE
#endif // HAVE_STDINT_H
/* stddef.h subset */
#ifdef HAVE_STDDEF_H
#include <stddef.h>
#else
#ifndef HAVE_STDDEF_H_ALTERNATIVE
#define offsetof(st, m) ((size_t)(&((st *)0)->m))
#ifndef NULL
#define NULL 0
#endif // NULL
#endif // HAVE_STDDEF_H_ALTERNATIVE
#endif // HAVE_STDDEF_H
/* stdbool.h subset */
#ifdef HAVE_STDBOOL_H
#include <stdbool.h>
#else
#ifndef __cplusplus
typedef int bool;
#define false 0
#define true 1
#endif
#endif // HAVE_STDBOOL_H
/* stdlib.h subset */
#ifdef PB_ENABLE_MALLOC
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#else
void *realloc(void *ptr, size_t size);
void free(void *ptr);
#endif // HAVE_STDLIB_H
#endif // PB_ENABLE_MALLOC
/* string.h subset */
#ifdef HAVE_STRING_H
#include <string.h>
#else
/* Implementations are from the Public Domain C Library (PDCLib). */
static size_t strlen( const char * s )
{
size_t rc = 0;
while ( s[rc] )
{
++rc;
}
return rc;
}
static void * memcpy( void *s1, const void *s2, size_t n )
{
char * dest = (char *) s1;
const char * src = (const char *) s2;
while ( n-- )
{
*dest++ = *src++;
}
return s1;
}
static void * memset( void * s, int c, size_t n )
{
unsigned char * p = (unsigned char *) s;
while ( n-- )
{
*p++ = (unsigned char) c;
}
return s;
}
#endif // HAVE_STRING_H
#endif // _PB_SYSHDR_H_
@@ -0,0 +1,119 @@
/* This is a headerfile customized for Microsoft Visual Studio 2010
* - based on example of a header file for platforms/compilers that do
* not come with stdint.h/stddef.h/stdbool.h/string.h. To use it, define
* PB_SYSTEM_HEADER as "pb_syshdr_win.h", including the quotes, and add the
* extra folder to your include path.
*
* Authorship: This file was altered/created by KUKA Deutschland GmbH, Augsburg, Germany in 2014
*
*/
#ifndef _PB_SYSHDR_WIN_H_
#define _PB_SYSHDR_WIN_H_
/* stdint.h subset */
#ifdef HAVE_STDINT_H
#include <stdint.h>
#else
/* You will need to modify these to match the word size of your platform. */
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef signed int int32_t;
typedef unsigned int uint32_t;
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
// from stdint.h
#define INT8_MAX 0x7f
#define INT16_MAX 0x7fff
#define INT32_MAX 0x7fffffff
#define UINT8_MAX 0xffU
#define UINT16_MAX 0xffffU
#define UINT32_MAX 0xffffffffU
#endif
/* stddef.h subset */
#ifdef HAVE_STDDEF_H
#include <stddef.h>
#else
//typedef uint32_t size_t; // wird dieser typedef wirklich benötigt?!?
#ifndef offsetof
#define offsetof(st, m) ((size_t)(&((st *)0)->m))
#endif
#ifndef NULL
#define NULL 0
#endif
#endif
/* stdbool.h subset */
#ifdef HAVE_STDBOOL_H
#include <stdbool.h>
#else
#ifndef __cplusplus
typedef int bool;
#define false 0
#define true 1
#endif
#endif
/* stdlib.h subset */
#ifdef PB_ENABLE_MALLOC
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#else
void *realloc(void *ptr, size_t size);
void free(void *ptr);
#endif
#endif
/* string.h subset */
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifndef WIN32
/* Implementations are from the Public Domain C Library (PDCLib). */
static size_t strlen( const char * s )
{
size_t rc = 0;
while ( s[rc] )
{
++rc;
}
return rc;
}
static void * memcpy( void *s1, const void *s2, size_t n )
{
char * dest = (char *) s1;
const char * src = (const char *) s2;
while ( n-- )
{
*dest++ = *src++;
}
return s1;
}
static void * memset( void * s, int c, size_t n )
{
unsigned char * p = (unsigned char *) s;
while ( n-- )
{
*p++ = (unsigned char) c;
}
return s;
}
#else
#include <string.h>
#endif
#endif
#endif
@@ -0,0 +1,19 @@
BASE_DIR = ../..
include $(BASE_DIR)/build/GNUMake/paths.mak
include $(BASE_DIR)/build/GNUMake/$(TOOLS_MAK)
CC_SRC = pb_frimessages_callbacks.c
CXX_SRC = friMonitoringMessageDecoder.cpp \
friCommandMessageEncoder.cpp
INC_DIR += $(NANOPB_DIR) $(PROTOBUF_GEN_DIR)
CFLAGS +=
CXXFLAGS +=
LDFLAGS +=
################################################################################
### Include general makefile (at the end)
################################################################################
include $(BASE_DIR)/build/GNUMake/rules.mak
@@ -0,0 +1,121 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#include <cstdio>
#include "friCommandMessageEncoder.h"
#include "pb_encode.h"
using namespace KUKA::FRI;
//******************************************************************************
CommandMessageEncoder::CommandMessageEncoder(FRICommandMessage* pMessage, int num)
: m_nNum(num), m_pMessage(pMessage)
{
initMessage();
}
//******************************************************************************
CommandMessageEncoder::~CommandMessageEncoder()
{
}
//******************************************************************************
void CommandMessageEncoder::initMessage()
{
m_pMessage->has_commandData = false;
m_pMessage->has_endOfMessageData = false;
m_pMessage->commandData.has_jointPosition = false;
m_pMessage->commandData.has_cartesianWrenchFeedForward = false;
m_pMessage->commandData.has_jointTorque = false;
m_pMessage->commandData.commandedTransformations_count = 0;
m_pMessage->header.messageIdentifier = 0;
// init with 0. Necessary for creating the correct reflected sequence count in the monitoring msg
m_pMessage->header.sequenceCounter = 0;
m_pMessage->header.reflectedSequenceCounter = 0;
m_pMessage->commandData.writeIORequest_count = 0;
// allocate and map memory for protobuf repeated structures
map_repeatedDouble(FRI_MANAGER_NANOPB_ENCODE, m_nNum,
&m_pMessage->commandData.jointPosition.value,
&m_tRecvContainer.jointPosition);
map_repeatedDouble(FRI_MANAGER_NANOPB_ENCODE, m_nNum,
&m_pMessage->commandData.jointTorque.value,
&m_tRecvContainer.jointTorque);
// nanopb encoding needs to know how many elements the static array contains
// a Cartesian wrench feed forward vector always contains 6 elements
m_pMessage->commandData.cartesianWrenchFeedForward.element_count = 6;
}
//******************************************************************************
bool CommandMessageEncoder::encode(char* buffer, int& size)
{
// generate stream for encoding
pb_ostream_t stream = pb_ostream_from_buffer((uint8_t*)buffer, FRI_COMMAND_MSG_MAX_SIZE);
// encode monitoring Message to stream
bool status = pb_encode(&stream, FRICommandMessage_fields, m_pMessage);
size = stream.bytes_written;
if (!status)
{
printf("!!encoding error: %s!!\n", PB_GET_ERROR(&stream));
}
return status;
}
@@ -0,0 +1,118 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#ifndef _KUKA_FRI_COMMANDMESSAGEENCODER_H
#define _KUKA_FRI_COMMANDMESSAGEENCODER_H
#include "FRIMessages.pb.h"
#include "pb_frimessages_callbacks.h"
namespace KUKA
{
namespace FRI
{
static const int FRI_COMMAND_MSG_MAX_SIZE = 1500; //!< max size of a FRI command message
class CommandMessageEncoder
{
public:
CommandMessageEncoder(FRICommandMessage* pMessage, int num);
~CommandMessageEncoder();
bool encode(char* buffer, int& size);
private:
struct LocalCommandDataContainer
{
tRepeatedDoubleArguments jointPosition;
tRepeatedDoubleArguments jointTorque;
LocalCommandDataContainer()
{
init_repeatedDouble(&jointPosition);
init_repeatedDouble(&jointTorque);
}
~LocalCommandDataContainer()
{
free_repeatedDouble(&jointPosition);
free_repeatedDouble(&jointTorque);
}
};
int m_nNum;
LocalCommandDataContainer m_tRecvContainer;
FRICommandMessage* m_pMessage;
void initMessage();
};
}
}
#endif // _KUKA_FRI_COMMANDMESSAGEENCODER_H
@@ -0,0 +1,145 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#include <cstdio>
#include "friMonitoringMessageDecoder.h"
#include "pb_decode.h"
using namespace KUKA::FRI;
//******************************************************************************
MonitoringMessageDecoder::MonitoringMessageDecoder(FRIMonitoringMessage* pMessage, int num)
: m_nNum(num), m_pMessage(pMessage)
{
initMessage();
}
//******************************************************************************
MonitoringMessageDecoder::~MonitoringMessageDecoder()
{
}
//******************************************************************************
void MonitoringMessageDecoder::initMessage()
{
// set initial data
// it is assumed that no robot information and monitoring data is available and therefore the
// optional fields are initialized with false
m_pMessage->has_robotInfo = false;
m_pMessage->has_monitorData = false;
m_pMessage->has_connectionInfo = true;
m_pMessage->has_ipoData = false;
m_pMessage->requestedTransformations_count = 0;
m_pMessage->has_endOfMessageData = false;
m_pMessage->header.messageIdentifier = 0;
m_pMessage->header.reflectedSequenceCounter = 0;
m_pMessage->header.sequenceCounter = 0;
m_pMessage->connectionInfo.sessionState = FRISessionState_IDLE;
m_pMessage->connectionInfo.quality = FRIConnectionQuality_POOR;
m_pMessage->monitorData.readIORequest_count = 0;
// allocate and map memory for protobuf repeated structures
map_repeatedDouble(FRI_MANAGER_NANOPB_DECODE, m_nNum,
&m_pMessage->monitorData.measuredJointPosition.value,
&m_tSendContainer.m_AxQMsrLocal);
map_repeatedDouble(FRI_MANAGER_NANOPB_DECODE, m_nNum,
&m_pMessage->monitorData.measuredTorque.value,
&m_tSendContainer.m_AxTauMsrLocal);
map_repeatedDouble(FRI_MANAGER_NANOPB_DECODE, m_nNum,
&m_pMessage->monitorData.commandedJointPosition.value,
&m_tSendContainer.m_AxQCmdT1mLocal);
map_repeatedDouble(FRI_MANAGER_NANOPB_DECODE, m_nNum,
&m_pMessage->monitorData.commandedTorque.value,
&m_tSendContainer.m_AxTauCmdLocal);
map_repeatedDouble(FRI_MANAGER_NANOPB_DECODE, m_nNum,
&m_pMessage->monitorData.externalTorque.value,
&m_tSendContainer.m_AxTauExtMsrLocal);
map_repeatedDouble(FRI_MANAGER_NANOPB_DECODE,m_nNum,
&m_pMessage->ipoData.jointPosition.value,
&m_tSendContainer.m_AxQCmdIPO);
map_repeatedInt(FRI_MANAGER_NANOPB_DECODE, m_nNum,
&m_pMessage->robotInfo.driveState,
&m_tSendContainer.m_AxDriveStateLocal);
}
//******************************************************************************
bool MonitoringMessageDecoder::decode(char* buffer, int size)
{
pb_istream_t stream = pb_istream_from_buffer((uint8_t*)buffer, size);
bool status = pb_decode(&stream, FRIMonitoringMessage_fields, m_pMessage);
if (!status)
{
printf("!!decoding error: %s!!\n", PB_GET_ERROR(&stream));
}
return status;
}
@@ -0,0 +1,133 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#ifndef _KUKA_FRI_MONITORINGMESSAGEDECODER_H
#define _KUKA_FRI_MONITORINGMESSAGEDECODER_H
#include "FRIMessages.pb.h"
#include "pb_frimessages_callbacks.h"
namespace KUKA
{
namespace FRI
{
static const int FRI_MONITOR_MSG_MAX_SIZE = 1500; //!< max size of a FRI monitoring message
class MonitoringMessageDecoder
{
public:
MonitoringMessageDecoder(FRIMonitoringMessage* pMessage, int num);
~MonitoringMessageDecoder();
bool decode(char* buffer, int size);
private:
struct LocalMonitoringDataContainer
{
tRepeatedDoubleArguments m_AxQMsrLocal;
tRepeatedDoubleArguments m_AxTauMsrLocal;
tRepeatedDoubleArguments m_AxQCmdT1mLocal;
tRepeatedDoubleArguments m_AxTauCmdLocal;
tRepeatedDoubleArguments m_AxTauExtMsrLocal;
tRepeatedIntArguments m_AxDriveStateLocal;
tRepeatedDoubleArguments m_AxQCmdIPO;
LocalMonitoringDataContainer()
{
init_repeatedDouble(&m_AxQMsrLocal);
init_repeatedDouble(&m_AxTauMsrLocal);
init_repeatedDouble(&m_AxQCmdT1mLocal);
init_repeatedDouble(&m_AxTauCmdLocal);
init_repeatedDouble(&m_AxTauExtMsrLocal);
init_repeatedDouble(&m_AxQCmdIPO);
init_repeatedInt(&m_AxDriveStateLocal);
}
~LocalMonitoringDataContainer()
{
free_repeatedDouble(&m_AxQMsrLocal);
free_repeatedDouble(&m_AxTauMsrLocal);
free_repeatedDouble(&m_AxQCmdT1mLocal);
free_repeatedDouble(&m_AxTauCmdLocal);
free_repeatedDouble(&m_AxTauExtMsrLocal);
free_repeatedDouble(&m_AxQCmdIPO);
free_repeatedInt(&m_AxDriveStateLocal);
}
};
int m_nNum;
LocalMonitoringDataContainer m_tSendContainer;
FRIMonitoringMessage* m_pMessage;
void initMessage();
};
}
}
#endif // _KUKA_FRI_MONITORINGMESSAGEDECODER_H
@@ -0,0 +1,267 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#include <stdio.h>
#include <stdlib.h>
#include "pb_frimessages_callbacks.h"
#include "pb_encode.h"
#include "pb_decode.h"
bool encode_repeatedDouble(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
size_t i = 0;
tRepeatedDoubleArguments* arguments = 0;
size_t count = 0;
double* values = 0;
if (arg == NULL || *arg == NULL)
{
return false;
}
arguments = ((tRepeatedDoubleArguments*) (*arg));
count = arguments->max_size;
values = arguments->value;
for (i = 0; i < count; i++)
{
if (!pb_encode_tag_for_field(stream, field))
{
return false;
}
if (!pb_encode_fixed64(stream, &values[i]))
{
return false;
}
}
return true;
}
bool decode_repeatedDouble(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
tRepeatedDoubleArguments* arguments = 0;
size_t i = 0;
double* values = 0;
if (arg == NULL || *arg == NULL)
{
return false;
}
arguments = (tRepeatedDoubleArguments*) *arg;
i = arguments->size;
values = arguments->value;
if (values == NULL)
{
return true;
}
if (!pb_decode_fixed64(stream, &values[i]))
{
return false;
}
arguments->size++;
if (arguments->size >= arguments->max_size)
{
arguments->size = 0;
}
return true;
}
bool encode_repeatedInt(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
int i = 0;
tRepeatedIntArguments* arguments = 0;
int count = 0;
int64_t* values = 0;
if (arg == NULL || *arg == NULL)
{
return false;
}
arguments = (tRepeatedIntArguments*) *arg;
count = arguments->max_size;
values = arguments->value;
for (i = 0; i < count; i++)
{
if (!pb_encode_tag_for_field(stream, field))
{
return false;
}
if (!pb_encode_varint(stream, values[i]))
{
return false;
}
}
return true;
}
bool decode_repeatedInt(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
tRepeatedIntArguments* arguments = 0;
size_t i = 0;
uint64_t* values = 0;
if (arg == NULL || *arg == NULL)
{
return false;
}
arguments = (tRepeatedIntArguments*) *arg;
i = arguments->size;
values = (uint64_t*) arguments->value;
if (values == NULL)
{
return true;
}
if (!pb_decode_varint(stream, &values[i]))
{
return false;
}
arguments->size++;
if (arguments->size >= arguments->max_size)
{
arguments->size = 0;
}
return true;
}
void map_repeatedDouble(eNanopbCallbackDirection dir, int numDOF, pb_callback_t *values, tRepeatedDoubleArguments *arg)
{
// IMPORTANT: the callbacks are stored in a union, therefor a message object
// must be exclusive defined for transmission or reception
if (dir == FRI_MANAGER_NANOPB_ENCODE)
{
values->funcs.encode = &encode_repeatedDouble;
}
else
{
values->funcs.decode = &decode_repeatedDouble;
}
// map the local container data to the message data fields
arg->max_size = numDOF;
arg->size = 0;
if (numDOF > 0)
{
arg->value = (double*) malloc(numDOF * sizeof(double));
}
values->arg = arg;
}
void map_repeatedInt(eNanopbCallbackDirection dir, int numDOF, pb_callback_t *values, tRepeatedIntArguments *arg)
{
// IMPORTANT: the callbacks are stored in a union, therefor a message object
// must be exclusive defined for transmission or reception
if (dir == FRI_MANAGER_NANOPB_ENCODE)
{
// set the encode callback function
values->funcs.encode = &encode_repeatedInt;
}
else
{
// set the decode callback function
values->funcs.decode = &decode_repeatedInt;
}
// map the robot drive state from the container to message field
arg->max_size = numDOF;
arg->size = 0;
if (numDOF > 0)
{
arg->value = (int64_t*) malloc(numDOF * sizeof(int64_t));
}
values->arg = arg;
}
void init_repeatedDouble(tRepeatedDoubleArguments *arg)
{
arg->size = 0;
arg->max_size = 0;
arg->value = NULL;
}
void init_repeatedInt(tRepeatedIntArguments *arg)
{
arg->size = 0;
arg->max_size = 0;
arg->value = NULL;
}
void free_repeatedDouble(tRepeatedDoubleArguments *arg)
{
if (arg->value != NULL)
free(arg->value);
}
void free_repeatedInt(tRepeatedIntArguments *arg)
{
if (arg->value != NULL)
free(arg->value);
}
@@ -0,0 +1,121 @@
/**
The following license terms and conditions apply, unless a redistribution
agreement or other license is obtained by KUKA Deutschland GmbH, Augsburg, Germany.
SCOPE
The software “KUKA Sunrise.Connectivity FRI Client SDK” is targeted to work in
conjunction with the “KUKA Sunrise.Connectivity FastRobotInterface” toolkit.
In the following, the term “software” refers to all material directly
belonging to the provided SDK “Software development kit”, particularly source
code, libraries, binaries, manuals and technical documentation.
COPYRIGHT
All Rights Reserved
Copyright (C) 2014-2018
KUKA Deutschland GmbH
Augsburg, Germany
LICENSE
Redistribution and use of the software in source and binary forms, with or
without modification, are permitted provided that the following conditions are
met:
a) The software is used in conjunction with KUKA products only.
b) Redistributions of source code must retain the above copyright notice, this
list of conditions and the disclaimer.
c) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the disclaimer in the documentation and/or other
materials provided with the distribution. Altered source code of the
redistribution must be made available upon request with the distribution.
d) Modification and contributions to the original software provided by KUKA
must be clearly marked and the authorship must be stated.
e) Neither the name of KUKA nor the trademarks owned by KUKA may be used to
endorse or promote products derived from this software without specific prior
written permission.
DISCLAIMER OF WARRANTY
The Software is provided "AS IS" and "WITH ALL FAULTS," without warranty of
any kind, including without limitation the warranties of merchantability,
fitness for a particular purpose and non-infringement.
KUKA makes no warranty that the Software is free of defects or is suitable for
any particular purpose. In no event shall KUKA be responsible for loss or
damages arising from the installation or use of the Software, including but
not limited to any indirect, punitive, special, incidental or consequential
damages of any character including, without limitation, damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and all other
commercial damages or losses.
The entire risk to the quality and performance of the Software is not borne by
KUKA. Should the Software prove defective, KUKA is not liable for the entire
cost of any service and repair.
\file
\version {1.16}
*/
#ifndef _pb_frimessages_callbacks_H
#define _pb_frimessages_callbacks_H
#ifdef __cplusplus
extern "C" {
#endif
#include "pb.h"
#include "FRIMessages.pb.h"
/** container for repeated double elements */
typedef struct repeatedDoubleArguments {
size_t size;
size_t max_size;
double* value;
} tRepeatedDoubleArguments;
/** container for repeated integer elements */
typedef struct repeatedIntArguments {
size_t size;
size_t max_size;
int64_t* value;
} tRepeatedIntArguments;
/** enumeration for direction (encoding/decoding) */
typedef enum DIRECTION {
FRI_MANAGER_NANOPB_DECODE = 0, //!< Argument um eine
FRI_MANAGER_NANOPB_ENCODE = 1 //!<
} eNanopbCallbackDirection;
bool encode_repeatedDouble(pb_ostream_t *stream, const pb_field_t *field,
void * const *arg);
bool decode_repeatedDouble(pb_istream_t *stream, const pb_field_t *field,
void **arg);
bool encode_repeatedInt(pb_ostream_t *stream, const pb_field_t *field,
void * const *arg);
bool decode_repeatedInt(pb_istream_t *stream, const pb_field_t *field,
void **arg);
void map_repeatedDouble(eNanopbCallbackDirection dir, int numDOF,
pb_callback_t *values, tRepeatedDoubleArguments *arg);
void map_repeatedInt(eNanopbCallbackDirection dir, int numDOF,
pb_callback_t *values, tRepeatedIntArguments *arg);
void init_repeatedDouble(tRepeatedDoubleArguments *arg);
void init_repeatedInt(tRepeatedIntArguments *arg);
void free_repeatedDouble(tRepeatedDoubleArguments *arg);
void free_repeatedInt(tRepeatedIntArguments *arg);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
@@ -0,0 +1,151 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.2.8 at Tue Feb 14 12:42:03 2017. */
#include "FRIMessages.pb.h"
const pb_field_t JointValues_fields[2] = {
PB_FIELD2( 1, DOUBLE , REPEATED, CALLBACK, FIRST, JointValues, value, value, 0),
PB_LAST_FIELD
};
const pb_field_t TimeStamp_fields[3] = {
PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, TimeStamp, sec, sec, 0),
PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, TimeStamp, nanosec, sec, 0),
PB_LAST_FIELD
};
const pb_field_t CartesianVector_fields[2] = {
PB_FIELD2( 1, DOUBLE , REPEATED, STATIC , FIRST, CartesianVector, element, element, 0),
PB_LAST_FIELD
};
const pb_field_t Checksum_fields[2] = {
PB_FIELD2( 1, INT32 , OPTIONAL, STATIC , FIRST, Checksum, crc32, crc32, 0),
PB_LAST_FIELD
};
const pb_field_t Transformation_fields[4] = {
PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, Transformation, name, name, 0),
PB_FIELD2( 2, DOUBLE , REPEATED, STATIC , OTHER, Transformation, matrix, name, 0),
PB_FIELD2( 3, MESSAGE , OPTIONAL, STATIC , OTHER, Transformation, timestamp, matrix, &TimeStamp_fields),
PB_LAST_FIELD
};
const pb_field_t FriIOValue_fields[6] = {
PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, FriIOValue, name, name, 0),
PB_FIELD2( 2, ENUM , REQUIRED, STATIC , OTHER, FriIOValue, type, name, 0),
PB_FIELD2( 3, ENUM , REQUIRED, STATIC , OTHER, FriIOValue, direction, type, 0),
PB_FIELD2( 4, UINT64 , OPTIONAL, STATIC , OTHER, FriIOValue, digitalValue, direction, 0),
PB_FIELD2( 5, DOUBLE , OPTIONAL, STATIC , OTHER, FriIOValue, analogValue, digitalValue, 0),
PB_LAST_FIELD
};
const pb_field_t MessageHeader_fields[4] = {
PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, MessageHeader, messageIdentifier, messageIdentifier, 0),
PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, MessageHeader, sequenceCounter, messageIdentifier, 0),
PB_FIELD2( 3, UINT32 , REQUIRED, STATIC , OTHER, MessageHeader, reflectedSequenceCounter, sequenceCounter, 0),
PB_LAST_FIELD
};
const pb_field_t ConnectionInfo_fields[5] = {
PB_FIELD2( 1, ENUM , REQUIRED, STATIC , FIRST, ConnectionInfo, sessionState, sessionState, 0),
PB_FIELD2( 2, ENUM , REQUIRED, STATIC , OTHER, ConnectionInfo, quality, sessionState, 0),
PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, ConnectionInfo, sendPeriod, quality, 0),
PB_FIELD2( 4, UINT32 , OPTIONAL, STATIC , OTHER, ConnectionInfo, receiveMultiplier, sendPeriod, 0),
PB_LAST_FIELD
};
const pb_field_t RobotInfo_fields[6] = {
PB_FIELD2( 1, INT32 , OPTIONAL, STATIC , FIRST, RobotInfo, numberOfJoints, numberOfJoints, 0),
PB_FIELD2( 2, ENUM , OPTIONAL, STATIC , OTHER, RobotInfo, safetyState, numberOfJoints, 0),
PB_FIELD2( 5, ENUM , REPEATED, CALLBACK, OTHER, RobotInfo, driveState, safetyState, 0),
PB_FIELD2( 6, ENUM , OPTIONAL, STATIC , OTHER, RobotInfo, operationMode, driveState, 0),
PB_FIELD2( 7, ENUM , OPTIONAL, STATIC , OTHER, RobotInfo, controlMode, operationMode, 0),
PB_LAST_FIELD
};
const pb_field_t MessageMonitorData_fields[8] = {
PB_FIELD2( 1, MESSAGE , OPTIONAL, STATIC , FIRST, MessageMonitorData, measuredJointPosition, measuredJointPosition, &JointValues_fields),
PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, MessageMonitorData, measuredTorque, measuredJointPosition, &JointValues_fields),
PB_FIELD2( 3, MESSAGE , OPTIONAL, STATIC , OTHER, MessageMonitorData, commandedJointPosition, measuredTorque, &JointValues_fields),
PB_FIELD2( 4, MESSAGE , OPTIONAL, STATIC , OTHER, MessageMonitorData, commandedTorque, commandedJointPosition, &JointValues_fields),
PB_FIELD2( 5, MESSAGE , OPTIONAL, STATIC , OTHER, MessageMonitorData, externalTorque, commandedTorque, &JointValues_fields),
PB_FIELD2( 8, MESSAGE , REPEATED, STATIC , OTHER, MessageMonitorData, readIORequest, externalTorque, &FriIOValue_fields),
PB_FIELD2( 15, MESSAGE , OPTIONAL, STATIC , OTHER, MessageMonitorData, timestamp, readIORequest, &TimeStamp_fields),
PB_LAST_FIELD
};
const pb_field_t MessageIpoData_fields[5] = {
PB_FIELD2( 1, MESSAGE , OPTIONAL, STATIC , FIRST, MessageIpoData, jointPosition, jointPosition, &JointValues_fields),
PB_FIELD2( 10, ENUM , OPTIONAL, STATIC , OTHER, MessageIpoData, clientCommandMode, jointPosition, 0),
PB_FIELD2( 11, ENUM , OPTIONAL, STATIC , OTHER, MessageIpoData, overlayType, clientCommandMode, 0),
PB_FIELD2( 12, DOUBLE , OPTIONAL, STATIC , OTHER, MessageIpoData, trackingPerformance, overlayType, 0),
PB_LAST_FIELD
};
const pb_field_t MessageCommandData_fields[6] = {
PB_FIELD2( 1, MESSAGE , OPTIONAL, STATIC , FIRST, MessageCommandData, jointPosition, jointPosition, &JointValues_fields),
PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, MessageCommandData, cartesianWrenchFeedForward, jointPosition, &CartesianVector_fields),
PB_FIELD2( 3, MESSAGE , OPTIONAL, STATIC , OTHER, MessageCommandData, jointTorque, cartesianWrenchFeedForward, &JointValues_fields),
PB_FIELD2( 4, MESSAGE , REPEATED, STATIC , OTHER, MessageCommandData, commandedTransformations, jointTorque, &Transformation_fields),
PB_FIELD2( 5, MESSAGE , REPEATED, STATIC , OTHER, MessageCommandData, writeIORequest, commandedTransformations, &FriIOValue_fields),
PB_LAST_FIELD
};
const pb_field_t MessageEndOf_fields[3] = {
PB_FIELD2( 1, INT32 , OPTIONAL, STATIC , FIRST, MessageEndOf, messageLength, messageLength, 0),
PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, MessageEndOf, messageChecksum, messageLength, &Checksum_fields),
PB_LAST_FIELD
};
const pb_field_t FRIMonitoringMessage_fields[8] = {
PB_FIELD2( 1, MESSAGE , REQUIRED, STATIC , FIRST, FRIMonitoringMessage, header, header, &MessageHeader_fields),
PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, FRIMonitoringMessage, robotInfo, header, &RobotInfo_fields),
PB_FIELD2( 3, MESSAGE , OPTIONAL, STATIC , OTHER, FRIMonitoringMessage, monitorData, robotInfo, &MessageMonitorData_fields),
PB_FIELD2( 4, MESSAGE , OPTIONAL, STATIC , OTHER, FRIMonitoringMessage, connectionInfo, monitorData, &ConnectionInfo_fields),
PB_FIELD2( 5, MESSAGE , OPTIONAL, STATIC , OTHER, FRIMonitoringMessage, ipoData, connectionInfo, &MessageIpoData_fields),
PB_FIELD2( 6, MESSAGE , REPEATED, STATIC , OTHER, FRIMonitoringMessage, requestedTransformations, ipoData, &Transformation_fields),
PB_FIELD2( 15, MESSAGE , OPTIONAL, STATIC , OTHER, FRIMonitoringMessage, endOfMessageData, requestedTransformations, &MessageEndOf_fields),
PB_LAST_FIELD
};
const pb_field_t FRICommandMessage_fields[4] = {
PB_FIELD2( 1, MESSAGE , REQUIRED, STATIC , FIRST, FRICommandMessage, header, header, &MessageHeader_fields),
PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, FRICommandMessage, commandData, header, &MessageCommandData_fields),
PB_FIELD2( 15, MESSAGE , OPTIONAL, STATIC , OTHER, FRICommandMessage, endOfMessageData, commandData, &MessageEndOf_fields),
PB_LAST_FIELD
};
/* Check that field information fits in pb_field_t */
#if !defined(PB_FIELD_32BIT)
/* If you get an error here, it means that you need to define PB_FIELD_32BIT
* compile-time option. You can do that in pb.h or on compiler command line.
*
* The reason you need to do this is that some of your messages contain tag
* numbers or field sizes that are larger than what can fit in 8 or 16 bit
* field descriptors.
*/
STATIC_ASSERT((pb_membersize(Transformation, timestamp) < 65536 && pb_membersize(MessageMonitorData, measuredJointPosition) < 65536 && pb_membersize(MessageMonitorData, measuredTorque) < 65536 && pb_membersize(MessageMonitorData, commandedJointPosition) < 65536 && pb_membersize(MessageMonitorData, commandedTorque) < 65536 && pb_membersize(MessageMonitorData, externalTorque) < 65536 && pb_membersize(MessageMonitorData, readIORequest[0]) < 65536 && pb_membersize(MessageMonitorData, timestamp) < 65536 && pb_membersize(MessageIpoData, jointPosition) < 65536 && pb_membersize(MessageCommandData, jointPosition) < 65536 && pb_membersize(MessageCommandData, cartesianWrenchFeedForward) < 65536 && pb_membersize(MessageCommandData, jointTorque) < 65536 && pb_membersize(MessageCommandData, commandedTransformations[0]) < 65536 && pb_membersize(MessageCommandData, writeIORequest[0]) < 65536 && pb_membersize(MessageEndOf, messageChecksum) < 65536 && pb_membersize(FRIMonitoringMessage, header) < 65536 && pb_membersize(FRIMonitoringMessage, connectionInfo) < 65536 && pb_membersize(FRIMonitoringMessage, robotInfo) < 65536 && pb_membersize(FRIMonitoringMessage, monitorData) < 65536 && pb_membersize(FRIMonitoringMessage, ipoData) < 65536 && pb_membersize(FRIMonitoringMessage, requestedTransformations[0]) < 65536 && pb_membersize(FRIMonitoringMessage, endOfMessageData) < 65536 && pb_membersize(FRICommandMessage, header) < 65536 && pb_membersize(FRICommandMessage, commandData) < 65536 && pb_membersize(FRICommandMessage, endOfMessageData) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_JointValues_TimeStamp_CartesianVector_Checksum_Transformation_FriIOValue_MessageHeader_ConnectionInfo_RobotInfo_MessageMonitorData_MessageIpoData_MessageCommandData_MessageEndOf_FRIMonitoringMessage_FRICommandMessage)
#endif
#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
/* If you get an error here, it means that you need to define PB_FIELD_16BIT
* compile-time option. You can do that in pb.h or on compiler command line.
*
* The reason you need to do this is that some of your messages contain tag
* numbers or field sizes that are larger than what can fit in the default
* 8 bit descriptors.
*/
STATIC_ASSERT((pb_membersize(Transformation, timestamp) < 256 && pb_membersize(MessageMonitorData, measuredJointPosition) < 256 && pb_membersize(MessageMonitorData, measuredTorque) < 256 && pb_membersize(MessageMonitorData, commandedJointPosition) < 256 && pb_membersize(MessageMonitorData, commandedTorque) < 256 && pb_membersize(MessageMonitorData, externalTorque) < 256 && pb_membersize(MessageMonitorData, readIORequest[0]) < 256 && pb_membersize(MessageMonitorData, timestamp) < 256 && pb_membersize(MessageIpoData, jointPosition) < 256 && pb_membersize(MessageCommandData, jointPosition) < 256 && pb_membersize(MessageCommandData, cartesianWrenchFeedForward) < 256 && pb_membersize(MessageCommandData, jointTorque) < 256 && pb_membersize(MessageCommandData, commandedTransformations[0]) < 256 && pb_membersize(MessageCommandData, writeIORequest[0]) < 256 && pb_membersize(MessageEndOf, messageChecksum) < 256 && pb_membersize(FRIMonitoringMessage, header) < 256 && pb_membersize(FRIMonitoringMessage, connectionInfo) < 256 && pb_membersize(FRIMonitoringMessage, robotInfo) < 256 && pb_membersize(FRIMonitoringMessage, monitorData) < 256 && pb_membersize(FRIMonitoringMessage, ipoData) < 256 && pb_membersize(FRIMonitoringMessage, requestedTransformations[0]) < 256 && pb_membersize(FRIMonitoringMessage, endOfMessageData) < 256 && pb_membersize(FRICommandMessage, header) < 256 && pb_membersize(FRICommandMessage, commandData) < 256 && pb_membersize(FRICommandMessage, endOfMessageData) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_JointValues_TimeStamp_CartesianVector_Checksum_Transformation_FriIOValue_MessageHeader_ConnectionInfo_RobotInfo_MessageMonitorData_MessageIpoData_MessageCommandData_MessageEndOf_FRIMonitoringMessage_FRICommandMessage)
#endif
/* On some platforms (such as AVR), double is really float.
* These are not directly supported by nanopb, but see example_avr_double.
* To get rid of this error, remove any double fields from your .proto.
*/
STATIC_ASSERT(sizeof(double) == 8, DOUBLE_MUST_BE_8_BYTES)
@@ -0,0 +1,303 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.2.8 at Tue Feb 14 12:42:03 2017. */
#ifndef _PB_FRIMESSAGES_PB_H_
#define _PB_FRIMESSAGES_PB_H_
#include <pb.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Enum definitions */
typedef enum _FRISessionState {
FRISessionState_IDLE = 0,
FRISessionState_MONITORING_WAIT = 1,
FRISessionState_MONITORING_READY = 2,
FRISessionState_COMMANDING_WAIT = 3,
FRISessionState_COMMANDING_ACTIVE = 4
} FRISessionState;
typedef enum _FRIConnectionQuality {
FRIConnectionQuality_POOR = 0,
FRIConnectionQuality_FAIR = 1,
FRIConnectionQuality_GOOD = 2,
FRIConnectionQuality_EXCELLENT = 3
} FRIConnectionQuality;
typedef enum _SafetyState {
SafetyState_NORMAL_OPERATION = 0,
SafetyState_SAFETY_STOP_LEVEL_0 = 1,
SafetyState_SAFETY_STOP_LEVEL_1 = 2,
SafetyState_SAFETY_STOP_LEVEL_2 = 3
} SafetyState;
typedef enum _OperationMode {
OperationMode_TEST_MODE_1 = 0,
OperationMode_TEST_MODE_2 = 1,
OperationMode_AUTOMATIC_MODE = 2
} OperationMode;
typedef enum _DriveState {
DriveState_OFF = 0,
DriveState_TRANSITIONING = 1,
DriveState_ACTIVE = 2
} DriveState;
typedef enum _ControlMode {
ControlMode_POSITION_CONTROLMODE = 0,
ControlMode_CARTESIAN_IMPEDANCE_CONTROLMODE = 1,
ControlMode_JOINT_IMPEDANCE_CONTROLMODE = 2,
ControlMode_NO_CONTROLMODE = 3
} ControlMode;
typedef enum _ClientCommandMode {
ClientCommandMode_NO_COMMAND_MODE = 0,
ClientCommandMode_POSITION = 1,
ClientCommandMode_WRENCH = 2,
ClientCommandMode_TORQUE = 3
} ClientCommandMode;
typedef enum _OverlayType {
OverlayType_NO_OVERLAY = 0,
OverlayType_JOINT = 1,
OverlayType_CARTESIAN = 2
} OverlayType;
typedef enum _FriIOType {
FriIOType_BOOLEAN = 0,
FriIOType_DIGITAL = 1,
FriIOType_ANALOG = 2
} FriIOType;
typedef enum _FriIODirection {
FriIODirection_INPUT = 0,
FriIODirection_OUTPUT = 1
} FriIODirection;
/* Struct definitions */
typedef struct _CartesianVector {
size_t element_count;
double element[6];
} CartesianVector;
typedef struct _Checksum {
bool has_crc32;
int32_t crc32;
} Checksum;
typedef struct _ConnectionInfo {
FRISessionState sessionState;
FRIConnectionQuality quality;
bool has_sendPeriod;
uint32_t sendPeriod;
bool has_receiveMultiplier;
uint32_t receiveMultiplier;
} ConnectionInfo;
typedef struct _FriIOValue {
char name[64];
FriIOType type;
FriIODirection direction;
bool has_digitalValue;
uint64_t digitalValue;
bool has_analogValue;
double analogValue;
} FriIOValue;
typedef struct _JointValues {
pb_callback_t value;
} JointValues;
typedef struct _MessageHeader {
uint32_t messageIdentifier;
uint32_t sequenceCounter;
uint32_t reflectedSequenceCounter;
} MessageHeader;
typedef struct _RobotInfo {
bool has_numberOfJoints;
int32_t numberOfJoints;
bool has_safetyState;
SafetyState safetyState;
pb_callback_t driveState;
bool has_operationMode;
OperationMode operationMode;
bool has_controlMode;
ControlMode controlMode;
} RobotInfo;
typedef struct _TimeStamp {
uint32_t sec;
uint32_t nanosec;
} TimeStamp;
typedef struct _MessageEndOf {
bool has_messageLength;
int32_t messageLength;
bool has_messageChecksum;
Checksum messageChecksum;
} MessageEndOf;
typedef struct _MessageIpoData {
bool has_jointPosition;
JointValues jointPosition;
bool has_clientCommandMode;
ClientCommandMode clientCommandMode;
bool has_overlayType;
OverlayType overlayType;
bool has_trackingPerformance;
double trackingPerformance;
} MessageIpoData;
typedef struct _MessageMonitorData {
bool has_measuredJointPosition;
JointValues measuredJointPosition;
bool has_measuredTorque;
JointValues measuredTorque;
bool has_commandedJointPosition;
JointValues commandedJointPosition;
bool has_commandedTorque;
JointValues commandedTorque;
bool has_externalTorque;
JointValues externalTorque;
size_t readIORequest_count;
FriIOValue readIORequest[10];
bool has_timestamp;
TimeStamp timestamp;
} MessageMonitorData;
typedef struct _Transformation {
char name[64];
size_t matrix_count;
double matrix[12];
bool has_timestamp;
TimeStamp timestamp;
} Transformation;
typedef struct _FRIMonitoringMessage {
MessageHeader header;
bool has_robotInfo;
RobotInfo robotInfo;
bool has_monitorData;
MessageMonitorData monitorData;
bool has_connectionInfo;
ConnectionInfo connectionInfo;
bool has_ipoData;
MessageIpoData ipoData;
size_t requestedTransformations_count;
Transformation requestedTransformations[5];
bool has_endOfMessageData;
MessageEndOf endOfMessageData;
} FRIMonitoringMessage;
typedef struct _MessageCommandData {
bool has_jointPosition;
JointValues jointPosition;
bool has_cartesianWrenchFeedForward;
CartesianVector cartesianWrenchFeedForward;
bool has_jointTorque;
JointValues jointTorque;
size_t commandedTransformations_count;
Transformation commandedTransformations[5];
size_t writeIORequest_count;
FriIOValue writeIORequest[10];
} MessageCommandData;
typedef struct _FRICommandMessage {
MessageHeader header;
bool has_commandData;
MessageCommandData commandData;
bool has_endOfMessageData;
MessageEndOf endOfMessageData;
} FRICommandMessage;
/* Default values for struct fields */
/* Field tags (for use in manual encoding/decoding) */
#define CartesianVector_element_tag 1
#define Checksum_crc32_tag 1
#define ConnectionInfo_sessionState_tag 1
#define ConnectionInfo_quality_tag 2
#define ConnectionInfo_sendPeriod_tag 3
#define ConnectionInfo_receiveMultiplier_tag 4
#define FriIOValue_name_tag 1
#define FriIOValue_type_tag 2
#define FriIOValue_direction_tag 3
#define FriIOValue_digitalValue_tag 4
#define FriIOValue_analogValue_tag 5
#define JointValues_value_tag 1
#define MessageHeader_messageIdentifier_tag 1
#define MessageHeader_sequenceCounter_tag 2
#define MessageHeader_reflectedSequenceCounter_tag 3
#define RobotInfo_numberOfJoints_tag 1
#define RobotInfo_safetyState_tag 2
#define RobotInfo_driveState_tag 5
#define RobotInfo_operationMode_tag 6
#define RobotInfo_controlMode_tag 7
#define TimeStamp_sec_tag 1
#define TimeStamp_nanosec_tag 2
#define MessageEndOf_messageLength_tag 1
#define MessageEndOf_messageChecksum_tag 2
#define MessageIpoData_jointPosition_tag 1
#define MessageIpoData_clientCommandMode_tag 10
#define MessageIpoData_overlayType_tag 11
#define MessageIpoData_trackingPerformance_tag 12
#define MessageMonitorData_measuredJointPosition_tag 1
#define MessageMonitorData_measuredTorque_tag 2
#define MessageMonitorData_commandedJointPosition_tag 3
#define MessageMonitorData_commandedTorque_tag 4
#define MessageMonitorData_externalTorque_tag 5
#define MessageMonitorData_readIORequest_tag 8
#define MessageMonitorData_timestamp_tag 15
#define Transformation_name_tag 1
#define Transformation_matrix_tag 2
#define Transformation_timestamp_tag 3
#define FRIMonitoringMessage_header_tag 1
#define FRIMonitoringMessage_connectionInfo_tag 4
#define FRIMonitoringMessage_robotInfo_tag 2
#define FRIMonitoringMessage_monitorData_tag 3
#define FRIMonitoringMessage_ipoData_tag 5
#define FRIMonitoringMessage_requestedTransformations_tag 6
#define FRIMonitoringMessage_endOfMessageData_tag 15
#define MessageCommandData_jointPosition_tag 1
#define MessageCommandData_cartesianWrenchFeedForward_tag 2
#define MessageCommandData_jointTorque_tag 3
#define MessageCommandData_commandedTransformations_tag 4
#define MessageCommandData_writeIORequest_tag 5
#define FRICommandMessage_header_tag 1
#define FRICommandMessage_commandData_tag 2
#define FRICommandMessage_endOfMessageData_tag 15
/* Struct field encoding specification for nanopb */
extern const pb_field_t JointValues_fields[2];
extern const pb_field_t TimeStamp_fields[3];
extern const pb_field_t CartesianVector_fields[2];
extern const pb_field_t Checksum_fields[2];
extern const pb_field_t Transformation_fields[4];
extern const pb_field_t FriIOValue_fields[6];
extern const pb_field_t MessageHeader_fields[4];
extern const pb_field_t ConnectionInfo_fields[5];
extern const pb_field_t RobotInfo_fields[6];
extern const pb_field_t MessageMonitorData_fields[8];
extern const pb_field_t MessageIpoData_fields[5];
extern const pb_field_t MessageCommandData_fields[6];
extern const pb_field_t MessageEndOf_fields[3];
extern const pb_field_t FRIMonitoringMessage_fields[8];
extern const pb_field_t FRICommandMessage_fields[4];
/* Maximum encoded size of messages (where known) */
#define TimeStamp_size 12
#define CartesianVector_size 54
#define Checksum_size 11
#define Transformation_size 188
#define FriIOValue_size 98
#define MessageHeader_size 18
#define ConnectionInfo_size 24
#define MessageEndOf_size 24
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
@@ -0,0 +1,15 @@
BASE_DIR = ../..
include $(BASE_DIR)/build/GNUMake/paths.mak
include $(BASE_DIR)/build/GNUMake/$(TOOLS_MAK)
CC_SRC = FRIMessages.pb.c
INC_DIR += $(NANOPB_DIR)
CFLAGS +=
LDFLAGS +=
################################################################################
### Include general makefile (at the end)
################################################################################
include $(BASE_DIR)/build/GNUMake/rules.mak
@@ -0,0 +1,6 @@
<library path="iiwa_controller">
<class name="iiwa_controller/IIWAHardwareInterface"
type="iiwa_controller::IIWAHardwareInterface"
base_class_type="hardware_interface::SystemInterface"/>
</library>
@@ -0,0 +1,29 @@
#pragma once
#include <friLBRClient.h>
#include <vector>
#include <array>
#include <cstring>
class FRIClient : public KUKA::FRI::LBRClient {
public:
FRIClient();
void monitor() override;
void waitForCommand() override;
void command() override;
void onStateChange(KUKA::FRI::ESessionState oldState,
KUKA::FRI::ESessionState newState) override;
std::array<double, 7> getMeasuredJointPositions() const;
std::array<double, 7> getMeasuredTorque() const;
void setTargetJointPositions(const std::array<double, 7> target_pos);
private:
std::array<double, 7> measuredJointPositions_;
std::array<double, 7> measuredTorque_;
std::array<double, 7> targetJointPositions_;
};
@@ -0,0 +1,57 @@
#ifndef IIWA_HARDWARE_INTERFACE_HPP
#define IIWA_HARDWARE_INTERFACE_HPP
#include <memory>
#include <string>
#include <vector>
#include "hardware_interface/handle.hpp"
#include "hardware_interface/hardware_info.hpp"
#include "hardware_interface/system_interface.hpp"
#include "hardware_interface/types/hardware_interface_return_values.hpp"
#include "hardware_interface/types/hardware_interface_type_values.hpp"
#include "rclcpp_lifecycle/state.hpp"
#include "rclcpp/macros.hpp"
#include "FRIClient.h"
#include "friUdpConnection.h"
#include "friClientApplication.h"
using CallbackReturn = rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn;
using namespace KUKA::FRI;
namespace iiwa_controller
{
class IIWAHardwareInterface : public hardware_interface::SystemInterface {
public:
CallbackReturn on_init(const hardware_interface::HardwareInfo & info) override;
std::vector<hardware_interface::StateInterface> export_state_interfaces() override;
std::vector<hardware_interface::CommandInterface> export_command_interfaces() override;
CallbackReturn on_activate(const rclcpp_lifecycle::State & previous_state) override;
CallbackReturn on_deactivate(const rclcpp_lifecycle::State & previous_state) override;
hardware_interface::return_type read(const rclcpp::Time & time, const rclcpp::Duration & period) override;
hardware_interface::return_type write(const rclcpp::Time & time, const rclcpp::Duration & period) override;
private:
// TODO: append robotClient FRI
std::unique_ptr<FRIClient> fri_client_;
std::unique_ptr<ClientApplication> app_;
std::unique_ptr<UdpConnection> connection_;
bool simulate_;
std::string hw_command_mode_;
std::vector<double> hw_commands_;
std::vector<double> hw_states_position_;
std::vector<double> hw_states_velocity_;
std::vector<double> hw_states_effort_;
std::vector<double> internal_command_position;
std::vector<double> prev_measured_pos_;
bool safety_override_active_ = true;
};
}
#endif
+22
View File
@@ -0,0 +1,22 @@
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>iiwa_controller</name>
<version>0.1.0</version>
<description>Own controller for controlling the KUKA aiwa 7 collaborative robot using the FRI library</description>
<maintainer email="daniell@example.com">Daniell</maintainer>
<license>Apache-2.0</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<depend>hardware_interface</depend>
<depend>pluginlib</depend>
<depend>rclcpp</depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>
+79
View File
@@ -0,0 +1,79 @@
#include "iiwa_controller/FRIClient.h"
#include "rclcpp/rclcpp.hpp"
using namespace KUKA::FRI;
inline const char* to_string(KUKA::FRI::ESessionState s)
{
using namespace KUKA::FRI;
switch (s)
{
case IDLE: return "IDLE";
case MONITORING_WAIT: return "MONITORING_WAIT";
case MONITORING_READY: return "MONITORING_READY";
case COMMANDING_WAIT: return "COMMANDING_WAIT";
case COMMANDING_ACTIVE: return "COMMANDING_ACTIVE";
default: return "UNKNOWN";
}
}
FRIClient::FRIClient() {
targetJointPositions_.fill(0.0);
measuredJointPositions_.fill(0.0);
measuredTorque_.fill(0.0);
};
void FRIClient::monitor()
{
std::memcpy(measuredJointPositions_.data(),
robotState().getMeasuredJointPosition(),
7 * sizeof(double));
std::memcpy(measuredTorque_.data(),
robotState().getMeasuredTorque(),
7 * sizeof(double));
}
void FRIClient::setTargetJointPositions(const std::array<double, 7> target_pos) {
targetJointPositions_ = target_pos;
}
std::array<double, 7> FRIClient::getMeasuredJointPositions() const {
return measuredJointPositions_;
}
std::array<double, 7> FRIClient::getMeasuredTorque() const {
return measuredTorque_;
}
void FRIClient::onStateChange(ESessionState oldState, ESessionState newState) {
RCLCPP_INFO_STREAM(
rclcpp::get_logger("FRIClient"),
"[FRI Client] FRI state: " << to_string(oldState) << " --> " << to_string(newState));
}
void FRIClient::waitForCommand()
{
std::memcpy(targetJointPositions_.data(),
robotState().getMeasuredJointPosition(),
7 * sizeof(double));
std::memcpy(measuredJointPositions_.data(),
robotState().getMeasuredJointPosition(),
7 * sizeof(double));
std::memcpy(measuredTorque_.data(),
robotState().getMeasuredTorque(),
7 * sizeof(double));
robotCommand().setJointPosition(targetJointPositions_.data());
}
void FRIClient::command() {
std::memcpy(measuredJointPositions_.data(),
robotState().getMeasuredJointPosition(),
7 * sizeof(double));
robotCommand().setJointPosition(targetJointPositions_.data());
}
@@ -0,0 +1,318 @@
#include "iiwa_controller/IIWAHardwareInterface.hpp"
#include "rclcpp/rclcpp.hpp"
using namespace KUKA::FRI;
namespace iiwa_controller {
template<typename T>
constexpr const T& clamp(const T& v, const T& lo, const T& hi)
{
return (v < lo) ? lo : (hi < v) ? hi : v;
}
CallbackReturn IIWAHardwareInterface::on_init(const hardware_interface::HardwareInfo & info) {
if (hardware_interface::SystemInterface::on_init(info) != CallbackReturn::SUCCESS)
return CallbackReturn::ERROR;
simulate_ = false;
hw_states_position_.resize(info_.joints.size(), 0.0);
hw_states_velocity_.resize(info_.joints.size(), 0.0);
hw_states_effort_.resize(info_.joints.size(), 0.0);
hw_commands_.resize(info_.joints.size(), 0.0);
prev_measured_pos_.resize(info_.joints.size(), 0.0);
internal_command_position.resize(info_.joints.size(), 0.0);
// пробегаемся по всем интерфейсам и смотрим какой режим управления установлен
for (const hardware_interface::ComponentInfo & joint : info_.joints) {
// проверка, на то что все суставы используют один и тот же тип управления
if (joint.command_interfaces.size() != 1) {
RCLCPP_FATAL(
rclcpp::get_logger("IiwaFRIHardwareInterface"),
"Joint '%s' has %li command interfaces found. 1 expected.", joint.name.c_str(),
joint.command_interfaces.size());
return CallbackReturn::ERROR;
}
// что у каждого сустава ровно 3 интерфейса состояния:
if (hw_command_mode_.empty()) {
hw_command_mode_ = joint.command_interfaces[0].name;
if (hw_command_mode_ != hardware_interface::HW_IF_POSITION &&
hw_command_mode_ != hardware_interface::HW_IF_VELOCITY &&
hw_command_mode_ != hardware_interface::HW_IF_EFFORT)
{
RCLCPP_FATAL(
rclcpp::get_logger("IiwaFRIHardwareInterface"),
"Joint '%s' have %s unknown command interfaces.", joint.name.c_str(),
joint.command_interfaces[0].name.c_str());
return CallbackReturn::ERROR;
}
}
//
if (hw_command_mode_ != joint.command_interfaces[0].name) {
RCLCPP_FATAL(
rclcpp::get_logger("IiwaFRIHardwareInterface"),
"Joint '%s' has %s command interfaces. Expected %s.", joint.name.c_str(),
joint.command_interfaces[0].name.c_str(), hw_command_mode_.c_str());
return CallbackReturn::ERROR;
}
if (joint.state_interfaces.size() != 3) {
RCLCPP_FATAL(
rclcpp::get_logger("IiwaFRIHardwareInterface"),
"Joint '%s' has %li state interface. 3 expected.", joint.name.c_str(),
joint.state_interfaces.size());
return CallbackReturn::ERROR;
}
if (joint.state_interfaces[0].name != hardware_interface::HW_IF_POSITION) {
RCLCPP_FATAL(
rclcpp::get_logger("IiwaFRIHardwareInterface"),
"Joint '%s' have %s state interface. '%s' expected.", joint.name.c_str(),
joint.state_interfaces[0].name.c_str(), hardware_interface::HW_IF_POSITION);
return CallbackReturn::ERROR;
}
if (joint.state_interfaces[1].name != hardware_interface::HW_IF_VELOCITY) {
RCLCPP_FATAL(
rclcpp::get_logger("IiwaFRIHardwareInterface"),
"Joint '%s' have %s state interface. '%s' expected.", joint.name.c_str(),
joint.state_interfaces[0].name.c_str(), hardware_interface::HW_IF_VELOCITY);
return CallbackReturn::ERROR;
}
if (joint.state_interfaces[2].name != hardware_interface::HW_IF_EFFORT) {
RCLCPP_FATAL(
rclcpp::get_logger("IiwaFRIHardwareInterface"),
"Joint '%s' have %s state interface. '%s' expected.", joint.name.c_str(),
joint.state_interfaces[0].name.c_str(), hardware_interface::HW_IF_EFFORT);
return CallbackReturn::ERROR;
}
}
return CallbackReturn::SUCCESS;
}
std::vector<hardware_interface::StateInterface> IIWAHardwareInterface::export_state_interfaces() {
std::vector<hardware_interface::StateInterface> state_interfaces;
for (uint i = 0; i < info_.joints.size(); i++) {
state_interfaces.emplace_back(
hardware_interface::StateInterface(
info_.joints[i].name, hardware_interface::HW_IF_POSITION, &hw_states_position_[i]));
}
for (uint i = 0; i < info_.joints.size(); i++) {
state_interfaces.emplace_back(
hardware_interface::StateInterface(
info_.joints[i].name, hardware_interface::HW_IF_VELOCITY, &hw_states_velocity_[i]));
}
for (uint i = 0; i < info_.joints.size(); i++) {
state_interfaces.emplace_back(
hardware_interface::StateInterface(
info_.joints[i].name, hardware_interface::HW_IF_EFFORT, &hw_states_effort_[i]));
}
return state_interfaces;
}
std::vector<hardware_interface::CommandInterface> IIWAHardwareInterface::export_command_interfaces() {
std::vector<hardware_interface::CommandInterface> command_interfaces;
for (uint i = 0; i < info_.joints.size(); i++) {
if (hw_command_mode_ == hardware_interface::HW_IF_POSITION) {
command_interfaces.emplace_back(
hardware_interface::CommandInterface(
info_.joints[i].name, hardware_interface::HW_IF_POSITION, &hw_commands_[i]));
} else if (hw_command_mode_ == hardware_interface::HW_IF_VELOCITY) {
command_interfaces.emplace_back(
hardware_interface::CommandInterface(
info_.joints[i].name, hardware_interface::HW_IF_VELOCITY, &hw_commands_[i]));
} else if (hw_command_mode_ == hardware_interface::HW_IF_EFFORT) {
command_interfaces.emplace_back(
hardware_interface::CommandInterface(
info_.joints[i].name, hardware_interface::HW_IF_EFFORT, &hw_commands_[i]));
}
}
return command_interfaces;
}
CallbackReturn IIWAHardwareInterface::on_activate(const rclcpp_lifecycle::State& ) {
RCLCPP_INFO(rclcpp::get_logger("IiwaFRIHardwareInterface"), "Starting ...please wait...");
auto it = info_.hardware_parameters.find("simulate");
if (it != info_.hardware_parameters.end()) {
std::string sim_str = it->second;
std::transform(sim_str.begin(), sim_str.end(), sim_str.begin(), ::tolower);
simulate_ = (sim_str == "true");
}
if (!simulate_) {
std::string ip = info_.hardware_parameters.at("robot_ip");
int port = std::stoi(info_.hardware_parameters.at("robot_port"));
fri_client_ = std::make_unique<FRIClient>();
connection_ = std::make_unique<UdpConnection>();
app_ = std::make_unique<ClientApplication>(*connection_, *fri_client_);
app_->connect(port, ip.c_str());
rclcpp::Time now = rclcpp::Clock().now();
rclcpp::Duration period = rclcpp::Duration::from_seconds(0.01);
this->read(now, period);
safety_override_active_ = true;
hw_commands_ = hw_states_position_;
RCLCPP_INFO(rclcpp::get_logger("IiwaFRIHardwareInterface"), "Connecting FRI to port= %i and ip= %s", port, ip.c_str());
}
RCLCPP_INFO(rclcpp::get_logger("IiwaFRIHardwareInterface"), "System Successfully started!");
return CallbackReturn::SUCCESS;
}
CallbackReturn IIWAHardwareInterface::on_deactivate(const rclcpp_lifecycle::State& ) {
RCLCPP_INFO(rclcpp::get_logger("IiwaFRIHardwareInterface"), "Stopping ...please wait...");
if (!simulate_) {
app_->disconnect();
}
std::fill(hw_commands_.begin(), hw_commands_.end(), 0.0);
RCLCPP_INFO(rclcpp::get_logger("IiwaFRIHardwareInterface"), "hw_commands_ reset to zero.");
RCLCPP_INFO(rclcpp::get_logger("IiwaFRIHardwareInterface"), "System successfully stopped!");
return CallbackReturn::SUCCESS;
}
hardware_interface::return_type IIWAHardwareInterface::read(const rclcpp::Time&, const rclcpp::Duration& period) {
if (!simulate_) {
if (!app_ || !app_->step()) // session порвалась?
{
RCLCPP_ERROR(rclcpp::get_logger("IIWAHardwareInterface"),
"FRI session lost");
return hardware_interface::return_type::ERROR;
}
/* ---------- 2. Считываем измеренные данные ---------- */
const auto pos_meas = fri_client_->getMeasuredJointPositions();
const auto tau_meas = fri_client_->getMeasuredTorque();
/* ---------- 3. Копируем в ros2_control ---------- */
for (size_t i = 0; i < hw_states_position_.size(); ++i)
{
hw_states_position_[i] = pos_meas[i];
// простая численная производная = (dq) / dt
hw_states_velocity_[i] =
(pos_meas[i] - prev_measured_pos_[i]) / period.seconds();
hw_states_effort_[i] = tau_meas[i];
prev_measured_pos_[i] = pos_meas[i];
}
return hardware_interface::return_type::OK;
}
for (size_t i = 0; i < hw_states_position_.size(); ++i) {
hw_states_position_[i] = hw_commands_[i];
hw_states_velocity_[i] = 0.0;
hw_states_effort_[i] = 0.0;
}
return hardware_interface::return_type::OK;
}
hardware_interface::return_type IIWAHardwareInterface::write(const rclcpp::Time&, const rclcpp::Duration&)
{
if (simulate_)
{
RCLCPP_DEBUG(
rclcpp::get_logger("IIWAHardwareInterface"),
"Simulated write to robot (echo commands)");
return hardware_interface::return_type::OK;
}
// ---------- 1. Подготовка массивов команд ----------
std::array<double, 7> cmd_position{};
std::array<double, 7> cmd_torque{};
for (size_t i = 0; i < hw_commands_.size(); ++i)
{
if (hw_command_mode_ == hardware_interface::HW_IF_POSITION)
cmd_position[i] = hw_commands_[i];
else if (hw_command_mode_ == hardware_interface::HW_IF_EFFORT)
cmd_torque[i] = hw_commands_[i];
}
// ---------- 2. Проверка на "нулевые" команды ----------
double sum = std::accumulate(
hw_commands_.begin(), hw_commands_.end(), 0.0,
[](double a, double b) { return a + std::abs(b); });
if (sum > 1e-3 && safety_override_active_)
{
RCLCPP_WARN_ONCE(
rclcpp::get_logger("IIWAHardwareInterface"),
"Command ignored: hw_commands_ are effectively zero (likely startup or stale)");
return hardware_interface::return_type::OK;
}
safety_override_active_ = false;
// ---------- 3. Защита по лимитам углов ----------
const double joint_limits[7][2] = {
{-2.95, 2.95}, {-2.03, 2.03}, {-2.95, 2.95},
{-2.03, 2.03}, {-2.95, 2.95}, {-2.03, 2.03}, {-3.0, 3.0}};
if (hw_command_mode_ == hardware_interface::HW_IF_POSITION)
{
for (size_t i = 0; i < 7; ++i)
{
cmd_position[i] = clamp(cmd_position[i], joint_limits[i][0], joint_limits[i][1]);
}
}
// ---------- 4. Отправка команды в FRI-клиент ----------
if (hw_command_mode_ == hardware_interface::HW_IF_POSITION)
{
fri_client_->setTargetJointPositions(cmd_position);
}
else if (hw_command_mode_ == hardware_interface::HW_IF_EFFORT)
{
// TODO: реализовать setTargetTorque при необходимости
}
else if (hw_command_mode_ == hardware_interface::HW_IF_VELOCITY)
{
// Velocity mode не реализован в FRI
}
RCLCPP_DEBUG(
rclcpp::get_logger("IIWAHardwareInterface"),
"Command sent to FRI");
return hardware_interface::return_type::OK;
}
}
#include <pluginlib/class_list_macros.hpp>
PLUGINLIB_EXPORT_CLASS(iiwa_controller::IIWAHardwareInterface, hardware_interface::SystemInterface)