diff --git a/.gitmodules b/.gitmodules index d90926e..2556791 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "firos/include/FiwareObjectConverter"] path = firos/include/FiwareObjectConverter url = https://github.com/iml130/FiwareObjectConverter.git +[submodule "firos/include/genpy"] + path = firos/include/genpy + url = https://github.com/ros/genpy.git diff --git a/README.md b/README.md index d8d46d7..e1a6e02 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,35 @@ # FIROS [![FIWARE Robotics](https://nexus.lab.fiware.org/static/badges/chapters/robotics.svg)](https://www.fiware.org/developers/catalogue/) -[![License: MIT](https://img.shields.io/github/license/iml130/firos.svg)](https://opensource.org/licenses/MIT) [![](https://img.shields.io/badge/tag-firos-orange.svg?logo=stackoverflow)](https://stackoverflow.com/questions/tagged/fiware+ros) +[![License: MIT](https://img.shields.io/github/license/iml130/firos.svg)](https://opensource.org/licenses/MIT) +[![](https://img.shields.io/badge/tag-firos-orange.svg?logo=stackoverflow)](https://stackoverflow.com/questions/tagged/fiware+ros)
[![Documentation badge](https://img.shields.io/readthedocs/firos.svg)](https://firos.rtfd.io) -[![Build badge](https://img.shields.io/travis/iml130/firos.svg)](https://travis-ci.org/iml130/firos/) ![Status](https://nexus.lab.fiware.org/repository/raw/public/badges/statuses/incubating.svg) +[![Build Status](https://travis-ci.com/iml130/firos.svg?branch=master)](https://travis-ci.com/iml130/firos) +![Status](https://nexus.lab.fiware.org/repository/raw/public/badges/statuses/incubating.svg) -FIROS works as a translator between the robotics field and the cloud world, transforming ROS messages into NGSI v2 to publish them in the cloud, and vice versa. The following figure depicts the integration of FIROS inside the FIWARE platform. +FIROS works as a translator between the robotics field and the cloud world, transforming ROS messages into NGSI v2 to +publish them in the cloud, and vice versa. The following figure depicts the integration of FIROS inside the FIWARE +platform. ![alt text](doc/firos.png "FIROS Integration") -FIROS is a tool that helps connecting robots to the cloud. For this purpose it uses the [Robot Operating System (ROS)](http://www.ros.org/) and the [FIWARE Context Broker](http://catalogue.fiware.org/enablers/publishsubscribe-context-broker-orion-context-broker) as a way to publish and listen robot's data. +FIROS is a tool that helps connecting robots to the cloud. For this purpose it uses the +[Robot Operating System (ROS)](http://www.ros.org/) and the +[FIWARE Context Broker](http://catalogue.fiware.org/enablers/publishsubscribe-context-broker-orion-context-broker) as a +way to publish and listen robot's data. -FIROS works as a translator between the robotics field and the cloud world, transforming ROS messages into NGSI to publish them in the cloud, and vice versa. +FIROS works as a translator between the robotics field and the cloud world, transforming ROS messages into NGSI to +publish them in the cloud, and vice versa. -This project is a fork from the **outdated** [Ikergunes FIROS package](https://github.com/Ikergune/firos). +This project is a fork from the **outdated** [Ikergunes FIROS package](https://github.com/Ikergune/firos). -This project is part of [FIWARE](https://www.fiware.org/). For more information check the FIWARE Catalogue entry for the [Robotics](https://github.com/Fiware/catalogue/tree/master/robotics). +This project is part of [FIWARE](https://www.fiware.org/). For more information check the FIWARE Catalogue entry for the +[Robotics](https://github.com/Fiware/catalogue/tree/master/robotics). | :books: [Documentation](https://firos.rtfd.io) | :dart: [Roadmap](doc/roadmap.md) | -| ------------------------------------- | ------------------------------- | +| ---------------------------------------------- | -------------------------------- | + ## Contents @@ -30,11 +40,12 @@ This project is part of [FIWARE](https://www.fiware.org/). For more information - [Contributors](#Contributors) - [Additional Resources](#Additional%20Resources) +## Install -## Install Refer to the Installation-Guide [here](doc/install/install.md) ## Usage + Refer to the User-Guide [here](doc/user/introduction.md) ## Troubleshooting @@ -42,13 +53,17 @@ Refer to the User-Guide [here](doc/user/introduction.md) TBD ## License + FIROS is licensed under [MIT License](https://opensource.org/licenses/MIT). ## Contributors + Dominik Lux, Peter Detzner ## Additional Resources + ### Presentations + FIROS-Helping Robots to be Context Aware ([Slideshare](https://de.slideshare.net/FI-WARE/fiware-global-summit-FIROS-helping-robots-to-be-context-aware), 28.11.2018 FIWARE Global Summit, Malaga) diff --git a/doc/install/configuration-files.md b/doc/install/configuration-files.md index 487f32e..a7ce02d 100644 --- a/doc/install/configuration-files.md +++ b/doc/install/configuration-files.md @@ -1,6 +1,6 @@ # Configuration-Files -Firos needs 3 different configuration files inside the Configuration-Folder. An example Configuration-Folder can be +FIROS needs 3 different configuration files inside the Configuration-Folder. An example Configuration-Folder can be found in the `config`-Folder at the base of this repository. It needs to contain the files `config.json`, `robots.json` and `whitelist.json` (optionally: `robotdescriptions.json`). @@ -47,7 +47,7 @@ Here is the list of all possibilities for a configuration: | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------: | | "interface" | Can be `"public"` or another string of one of the interfaces given by `ip link` or by `ifconfig`. If set to `"public"`, the public IP-address is set for the Map-Server (via [this](http://ip.42.pl/raw)). Otherwise the (specified) interface IP-address is used. | x | | "log_level" | Can be either `"INFO"` (Default), `"DEBUG"`, `"WARNING"`, `"ERROR"` or `"CRITICAL"`. | | -| "node_name" | This sets the ROS-Node-Name for this firos instance. the default is `"firos"`. | +| "node_name" | This sets the ROS-Node-Name for this FIROS instance. the default is `"firos"`. | | "ros_subscriber_queue" | The queue-size of the `rospy.Publisher`. See more [here](http://wiki.ros.org/rospy/Overview/Publishers%20and%20Subscribers). Default is `10` | | | "context_type" | This sets the context type of an entity (the `type`-value of the base-entity). Default is `"ROBOT"` but can be changed if necessary | | | "rosbridge_port" | Changes the ROS-Port, where to listen. Default is `9090` | | @@ -131,11 +131,36 @@ needed ones, which need to be displayed from/or need to obtain information on th } ``` +The Information given by the `robots.json` is appended/replaced to the `whitelist.json` which is described below. + --- ## `whitelist.json` -TODO WIP +As the name suggests, the `whitelist.json` functions as a whitelist to let FIROS know which messages it should keep +track of. Given an environment where already ROS-Applications are running, FIROS will automatically subscribe to all +available topics if no `whitelist.json` is given. In a small ROS-World with few ROS-Applications, this can be desirable. +But this can cause problems in a ROS-World, where many ROS-Applications are running. To let FIROS only subscribe to +specific topics, the following configuration can be used: + +```json +{ + "turtle2": { + "publisher": ["cmd_vel"], + "subscriber": ["pose"] + } +} +``` + +This only allows FIROS to subscribe/publish to `"/turtle2/pose"` and `"turtle2/cmd_vel"` plus the extra-configuration +given in `robots.json` which in the above example would also be `"/turtle1/pose"` and `"turtle1/cmd_vel"`. + +**Note**, that an empty configuration of `whitelist.json` (`-> {}`) will also behave as an +non-existent-configuration-file. Usually for normal usecases, the `whitelist.json` contains the same information as the +`robots.json` and should be sufficient. + +**Note:** The FIROS only captures running ROS-Applications at the startup. All applications started after FIROS will not +be recognized. --- diff --git a/doc/install/install.md b/doc/install/install.md index 13c4998..ca0b079 100644 --- a/doc/install/install.md +++ b/doc/install/install.md @@ -1,9 +1,9 @@ # Installion From Scratch With ROS and catkin To Install Firos you first need to follow this [Installaion Instuctions](http://wiki.ros.org/ROS/Installation). ROS is -needed for FIROS, since it imports `ROS-messages`. You also need to -[create a catkin-workspace](http://wiki.ros.org/catkin/Tutorials/create_a_workspace) to be able to create a ROS-Node out -of FIROS. +needed for FIROS, since it imports `ROS-messages` and uses other specific `ROS-Executables` like `rospy` or `rostopic`. +You need to [create a catkin-workspace](http://wiki.ros.org/catkin/Tutorials/create_a_workspace) to be able to create a +ROS-Node out of FIROS. You might also consider to set up a [contextbroker](https://fiware-orion.readthedocs.io/en/master/), so that FIROS can publish and subscribe on it. If a contextbroker is not available you can quickly set one up via @@ -24,10 +24,10 @@ catkin_make **Note**: -- FIROS uses a git submodule (which is required to run properly). Newer versions of git can clone submodules via the +- FIROS uses git submodules (which is required to run properly). Newer versions of git can clone submodules via the `--recursive` option -- Also check whether your local submodule-folder (currently in `firos/include`) contains files to be sure that - everything was cloned. +- Also check whether your local submodule-folder (currently in `firos/include/FiwareObjectConvert` amd + `firos/include/genpy`) contains files to be sure that everything was cloned. ## Basic Configuration of FIROS @@ -86,11 +86,9 @@ or to execute FIROS with Python2 -**Optionally:** to execute FIROS with PYTHON3 you need to add: +Firos should function via Python3. You can try it via: -> PYTHONPATH+=:/FULL_PATH_TO_THIS_REPO/firos/include/genpy/ - -**NOTE:** We try to omit this appending in the future, for an easier access to FIROS with python3 +> python3 firos/core.py ## Troubleshooting @@ -102,152 +100,96 @@ it installed. If not use your package-manager like `apt`, `pacman`, `pip` , `... # Installation via Docker -## WIP - ---- - -# Old Installation-Information - -# Cloning This Project +There exists a FIROS-Docker-Version which currently can be build locally. This installation only requires +[Docker](https://docs.docker.com/install/). -This project uses a submodule. Depending on your git version you might need to do the following: +## Cloning this Project -Clone this project via: +During or after the Docker-Installation you need to clone this repository via: -```sh +```shell git clone --recursive https://github.com/iml130/firos.git -# If the Folder firos/include/FiwareObjectConverter is still empty do: -git submodule update --init --recursive ``` -or +Please check whether the folders `firos/include/FiwareObjectConverter` and `firos/include/genpy` contains any content. +If not, the submodules were not initialized successfully and you might need to take a look at +[this](https://git-scm.com/docs/git-submodule) -```sh -git clone https://github.com/iml130/firos.git -git submodule update --init --recursive -``` +After you cloned this repository you have two options to start up FIROS: -The `FiwareObejctConverter` is our own `Python-Object<->Fiware-JSON`-Converter. +### Using `docker build` -Also, make sure you are using the correct version of the submodule. You can read more about git submodules -[here](https://git-scm.com/book/en/v2/Git-Tools-Submodules). +Beginning from the base of this repository, FIROS can be built via docker using: -# Installing FIROS via `catkin_make` +> docker build -f ./docker/Dockerfile --tag firos:localbuild . -## Requirements +This will create an image with a pre-configured `config.json` which requires the Orion-ContextBroker. Before running +this image, you need to specify a `robots.json`. Information on how to create the configuration-files can be found in +[Configuration-Files](configuration-files.md) or in the [Turtlesim-Example](turtlesim-example.md). An +example-pre-configured configuration for docker can be found in `firos/docker/docker-config` -- Ubuntu -- Python 2.7 or greater -- ROS Hydro or greater +Assuming you have a network `finet` (`-> "firos-net"`): You need to start a roscore, MongoDB, the Orion-ContextBroker +and afterwards FIROS like this: -## Installation +```shell +# Starting roscore +docker run -it --net finet --name rosmaster ros:melodic-ros-core roscore + +# Starting mongodb +docker run --net finet --name mongodb mongo:3.4 + +# Starting Orion-ContextBroker and link to mongodb +docker run -it --rm --net finet --name orion --link mongodb -p 1026:1026 fiware/orion -dbhost mongodb + +# Starting firos (Set the paths for the needed Configuration-Files here!) +docker run -it --net finet --name firos \ + -p 10100:10100 \ + --env ROS_MASTER_URI=http://rosmaster:11311 \ + -v CONFIG_FILE_ROBOTS:/catkin_ws/src/firos/config/robots.json \ + -v CONFIG_FILE_WHITELIST:/catkin_ws/src/firos/config/whitelist.json \ + firos:localbuild +``` -1. Make sure you have set - [your working space](http://wiki.ros.org/ROS/Tutorials/InstallingandConfiguringROSEnvironment) -2. Open a Terminal and navigate to the ROS workspace you want to use. If you just followed the ROS environment - tutorial, it will be ~/catkin_ws. +After this FIROS is ready to publish data and subscribe onto the local Orion-ContextBroker. -> cd ~/catkin_ws/src +### Using `docker-compose` -3. Clone the FIROS git repository into your ROS workspace. +The `docker-compose.yml` can be located inside the `docker`-folder at the base of this repository. Before executing the +compose-file you need to configure the configurations-files, which this docker-image uses in +`firos/docker/docker-config`. Please have a look at [Configuration-Files](configuration-files.md) or the +[Turtlesim-Example](turtlesim-example.md). The folder contains a basic example with `turtlesim` and can be used as is. -> git clone --recursive git@github.com:iml130/firos.git +If everything is set up, execute inside the `docker`-folder: -4. Build the FIROS package with the following commands. This will create a devel and build folder under your workspace. +> docker-compose up -> cd ~/catkin_ws catkin_make +This launches the Orion-Context-Broker (named `orion`), a `roscore`-Instance (named `rosmaster`) and FIROS (named +`firos`) with its specific configuration inside `docker-config` with a netowrk (like `docker_default`). The Ports: +`10100` and `1026` are also exposed to the host-machine. -5. For convenience, you may wish to source your setup.sh script from your .bashrc so that your environment is ready as - soon as you log in. e.g. +### Adding another ROS-Application into this Environment -> echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc +In order to add another ROS-Application into this environment you can either write another `docker-compose.yml` which +includes the environment-variable `"ROS_MASTER_URI=http://rosmaster:11311"` with its correspoding network +`net: "docker_default"` or call the correspoding `docker run` command: -If you don't want to edit you `.bashrc`, you can also just execute: +```shell +docker run --net docker_default --name YOUR_NAME --env ROS_MASTER_URI=http://rosmaster:11311 YOUR_IMAGE:NAME_HERE +``` -> source ~/catkin_ws/devel/setup.bash +--- -6. Execute "source devel/setup.bash" to allow the current command-line instance to setup the sources you have inside - yout `catkin_ws` +# Old Installation-Information + +Below are the old Installation and Configuration-Information of FIROS which were taken and partially appended from +[the old FIROS](https://github.com/Ikergune/firos). -FIROS is now ready to be used! +**Note:** This Information is out-dated and only exists, because not all information has been migrated. # Configuring FIROS FIROS has several configuration files located at _src/FIROS/config_. -## config.json - -This file contains the configuration related to FIROS launching environment. Here is a description of each parameter: - -- _environment_: This parameter distinguishes which configuration set inside this json should be used. FIROS will use - an environment's configuration based this value, but there can be as many environments as you want. -- _server_: This contains the Port of the FirosServer (The Port, where the `GET`- and `POST`-Operations can be - executed) -- _contextbroker_: Contains information related to the Context broker configuration - - _address_: Context broker's (IP-) address - - _port_: Context broker's port - - _subscription_: Context broker's subscription information - - _throttling_: The throttling in seconds. The contextbroker sends another update of the entity after the - `throttling`-seconds have passed - - _subscription_length_: The subscription expiration time (in seconds) - - _subscription_refresh_delay_: The subscription refresh delay (between 0 and 1) to re-subscribe to the - contextbroker -> After _subscription_length_ \* _subscription_refresh_delay_ seconds the subscription is - refreshed. -- _interface_: Network configuration of the card in use - - _public_: Public IP. Do not forget to redirect the proper ports in your network - - _wlan0, et0, tun0_, etc: Different network interface configuration. - - If you experience problems with the public interface, feel free to set the interface-name directly, like - _wlan0_, _enp0_, _eth0_. etc.. -- _log_level_: It represents the verbosity of the logging system for FIROS. Available options are as follows: _"NONE", - "INFO", "DEBUG" ,"WARNING", "ERROR"_ and _"CRITICAL"_ - -Here is an example of a _config.json_ file for a _local_ environment: - -```json -{ - "environment": "local", - - "local": { - "server": { - "port": 10100 - }, - "contextbroker": { - "address": "192.168.0.101", - "port": 1026, - "subscription": { - "throttling": 3, - "subscription_length": 300, - "subscription_refresh_delay": 0.9 - } - }, - "log_level": "INFO", - "interface": "public" - } -} -``` - -## robotdescriptions.json - -Robots may have some public files so users can understand some characteristics or even use their devices. All the -references contained in this file can be published on the Context Broker; to do so, just follow the next example: - -```json -{ - "turtle1": { - "descriptions": [ - "http://wiki.ros.org/ROS/Tutorials/UsingRxconsoleRoslaunch", - "http://wiki.ros.org/ROS/Tutorials/UnderstandingNodes" - ] - }, - "youbot": { - "descriptions": [ - "http://wiki.ros.org/ROS/Tutorials/UnderstandingServicesParams", - "http://wiki.ros.org/ROS/Tutorials/UsingRqtconsoleRoslaunch" - ] - } -} -``` - ## whitelist.json Every time FIROS is launched or whenever it gets a notification about a new robot being connected, it looks the @@ -270,75 +212,6 @@ is an example: } ``` -## robots.json - -It is also possible to force some robot connections. This is done by adding the robot name, its topics and roles to the -_robots.json_ file. The role parameter must be the same as the on in the _whitelist.json_ file and each topic must also -contain a _type_ parameter to define its role. The next file is an example of this configuration: - -```json -{ - "robot1": { - "topics": { - "cmd_vel_mux/input/teleop": { - "msg": "geometry_msgs.msg.Twist", - "type": "publisher" - }, - "move_base/goal": { - "msg": "move_base_msgs.msg.MoveBaseActionGoal", - "type": "publisher" - }, - "move_base/result": { - "msg": "move_base_msgs.msg.MoveBaseActionResult", - "type": "subscriber" - } - } - }, - "turtle1": { - "topics": { - "cmd_vel": { - "msg": "geometry_msgs.msg.Twist", - "type": "publisher" - }, - "pose": { - "msg": "turtlesim.msg.Pose", - "type": "subscriber" - } - } - } -} -``` - -The `type`'s Publish and Subscribe are always from Context Broker's point of view. If subscribed, the framework pushes -ROS-Information to the Context-Broker. ROS-Messages to the robots are sent to the contextbroker by the `type` publish. -Thus a communication betweeen robots can be established through the Context-Broker. Even Other Non-ROS-Application can -control robots via the Context-Broker. - -Here is an Example-Configuration between the communication of `turtlesim` on _Machine1_ and `teleop_twist_keyboard` on -_Machine2_: - -```json -Machine1: -{ - "turtle1": { - "topics": { - "cmd_vel": { - "msg": "geometry_msgs.msg.Twist", - "type": "publisher" - } -} -Machine2: -{ - "turtle1": { - "topics": { - "cmd_vel": { - "msg": "geometry_msgs.msg.Twist", - "type": "Subscriber" - } -} - -``` - # Getting Topic Types There is also a way to request the topic type, which is useful in order to add them to the previous _robots.json_ file. diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..d81d562 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,52 @@ +FROM ros:melodic-ros-core-bionic + +RUN mkdir catkin_ws \ + && mkdir catkin_ws/src \ + && mkdir catkin_ws/src/firos \ + && mkdir catkin_ws/devel \ + && mkdir catkin_ws/build + +COPY . /catkin_ws/src/firos +WORKDIR /catkin_ws + +# Standard 'config.json'-Configuration for Docker +RUN echo '{\n\ + "environment":"docker",\n\ + "docker":{\n\ + "server":{\n\ + "port":10100\n\ + },\n\ + "contextbroker":{\n\ + "address":"orion",\n\ + "port":1026,\n\ + "subscription":{\n\ + "throttling":0,\n\ + "subscription_length":300,\n\ + "subscription_refresh_delay":0.5\n\ + }\n\ + },\n\ + "log_level":"INFO",\n\ + "interface":"eth0"\n\ + }\n\ +}\n' > /catkin_ws/src/firos/config/config.json + +# remove descriptions/whitelist and robots configuration, since those need to be added by the user +RUN rm -f /catkin_ws/src/firos/config/robots.json && \ + rm -f /catkin_ws/src/firos/config/robotdescriptions.json && \ + rm -f /catkin_ws/src/firos/config/whitelist.json + + + +# install ros packages +RUN apt-get update && apt-get install -y ros-melodic-ros-base python python-pip +RUN pip install -r ./src/firos/requirements.txt +RUN /bin/bash -c '. /opt/ros/melodic/setup.bash; catkin_make' + + +EXPOSE 10100 +CMD /bin/bash -c '. /opt/ros/melodic/setup.bash; . /catkin_ws/devel/setup.bash; rosrun firos core.py' + + + + + diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..8cd190f --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,44 @@ +services: + firos: + build: + context: ".." + dockerfile: docker/Dockerfile + container_name: firos + depends_on: + - orion + - rosmaster + environment: + - PYTHONUNBUFFERED=1 + - "ROS_MASTER_URI=http://rosmaster:11311" + image: "firos:localbuild" + ports: + - "10100:10100" + volumes: + - "./docker-config/robots.json:/catkin_ws/src/firos/config/robots.json" + - "./docker-config/whitelist.json:/catkin_ws/src/firos/config/whitelist.json" + + mongo: + command: "--nojournal" + container_name: mongo + image: "mongo:3.4" + + orion: + command: "-dbhost mongo" + container_name: orion + image: fiware/orion + links: + - mongo + ports: + - "1026:1026" + + rosmaster: + command: + - roscore + container_name: rosmaster + hostname: rosmaster + image: "ros:melodic-ros-core" + ports: + - "11311:11311" + + +version: "3" diff --git a/docker/docker-config/robots.json b/docker/docker-config/robots.json new file mode 100644 index 0000000..0e2d616 --- /dev/null +++ b/docker/docker-config/robots.json @@ -0,0 +1,14 @@ +{ + "turtle1": { + "topics": { + "cmd_vel": { + "msg": "geometry_msgs.msg.Twist", + "type": "publisher" + }, + "pose": { + "msg": "turtlesim.msg.Pose", + "type": "subscriber" + } + } + } +} diff --git a/docker/docker-config/whitelist.json b/docker/docker-config/whitelist.json new file mode 100644 index 0000000..083ce25 --- /dev/null +++ b/docker/docker-config/whitelist.json @@ -0,0 +1,7 @@ +{ + "turtle1": { + "publisher": ["cmd_vel"], + "subscriber": ["pose"] + } + +} diff --git a/firos/core.py b/firos/core.py index 106e30f..61c73ff 100755 --- a/firos/core.py +++ b/firos/core.py @@ -78,8 +78,6 @@ # Importing firos specific scripts - from setup import launchSetup - from include import confManager from include.logger import Log, initLog from include.server.firosServer import FirosServer @@ -128,14 +126,12 @@ def signal_handler(signal, frame): signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) - launchSetup() - Log("INFO", "\nStarting Firos...") Log("INFO", "---------------------------------\n") #Topic Handler Routine: initPubAndSub() - loadMsgHandlers(confManager.getRobots(True, True)) + loadMsgHandlers(confManager.getRobots(True)) createConnectionListeners() Log("INFO", "\nPress Ctrl+C to Exit\n") diff --git a/firos/include/confManager.py b/firos/include/confManager.py index 3bd5631..c364ced 100644 --- a/firos/include/confManager.py +++ b/firos/include/confManager.py @@ -14,6 +14,7 @@ # FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +import sys import json import copy import traceback @@ -23,27 +24,38 @@ from include.constants import Constants as C -def getRobots(refresh=False, withJson=True): - ## \brief Get robots managed by firos - # \param Refresh the robot list - # \param Merge the robots with the configurtation JSON +def getRobots(refresh=False): + ''' This retrieves the current configuration from FIROS. + Here we load the `robots.json` and the 'whitelist.json' + + In case the `whitelist.json` is Empty: We do get the current robots + from ROS and are adding them as subscribers (by default). In a small + ROS-World this usually is no problem. But in an environment with many + robots we might send a lot of data. + ''' try: - robots = copy.deepcopy(RosConfigurator.systemTopics(refresh)) - if withJson: - robots_json = getRobotsByJson() - for robot_name in robots_json: - robot_name = str(robot_name) - if robot_name not in robots: - robots[robot_name] = { - "topics": {} - } - for topic_name in robots_json[robot_name]["topics"]: - topic = robots_json[robot_name]["topics"][topic_name] - - robots[robot_name]["topics"][str(topic_name)] = { - "msg": str(topic["msg"]) if type(topic["msg"]) is str else topic["msg"], - "type": str(topic["type"]) - } + #Retrieves the whitelist.json. If it does not exists, it returns all topics. + robots = copy.deepcopy(RosConfigurator.systemTopics(refresh)) + #Retrieves the robots.json. + robots_json = getRobotsByJson() + if len(robots_json) == 0: + Log("ERROR", "The file 'robots.json' is either empty or does not exist!\n\nExiting") + sys.exit(1) + + # Merge robots.json into whitelist.json (overwrite if neccessary) + for robot_name in robots_json: + robot_name = str(robot_name) + if robot_name not in robots: + robots[robot_name] = { + "topics": {} + } + for topic_name in robots_json[robot_name]["topics"]: + topic = robots_json[robot_name]["topics"][topic_name] + + robots[robot_name]["topics"][str(topic_name)] = { + "msg": str(topic["msg"]) if type(topic["msg"]) is str else topic["msg"], + "type": str(topic["type"]) + } return robots except Exception as e: @@ -53,7 +65,8 @@ def getRobots(refresh=False, withJson=True): def getRobotsByJson(): - ## \brief Get robots in the JSON file + ''' Load the 'robots.json'-File + ''' try: json_path = C.PATH + "/robots.json" return json.load(open(json_path)) diff --git a/firos/include/contextbroker/cbSubscriber.py b/firos/include/contextbroker/cbSubscriber.py index abb6fbf..40c46d5 100644 --- a/firos/include/contextbroker/cbSubscriber.py +++ b/firos/include/contextbroker/cbSubscriber.py @@ -54,10 +54,8 @@ class CbSubscriber(object): # Saves the subscriptions IDs returned from ContextBroker. # Follwoing Structure: subscriptionIds[ROBOT_ID][TOPIC] returns a sub-Id in String subscriptionIds = {} - CB_BASE_URL = None FIROS_NOTIFY_URL = None - def __init__(self): ''' Lazy Initialization of CB_BASE_URL and FIROS_NOTIFY_URL ''' @@ -74,7 +72,7 @@ def subscribeToCB(self, robotID, topicList): # If not already subscribed, start a new thread which handles the subscription for each topic for an robot. # And only If the topic list is not empty! if robotID not in self.subscriptionIds and topicList: - Log("INFO", "Subscribing on Context-Broker to " + robotID + " and topics: " + str(topicList)) + Log("INFO", "Subscribing on Context-Broker to " + robotID + " and topics: " + str(list(topicList))) self.subscriptionIds[robotID] = {} for topic in topicList: thread.start_new_thread(self.subscribeThread, (robotID, topic)) #Start Thread via subscription @@ -102,7 +100,10 @@ def subscribeThread(self, robotID, topic): response = requests.post(self.CB_BASE_URL + "/v2/subscriptions", data=jsonData, headers={'Content-Type': 'application/json'}) self._checkResponse(response, created=True, robTop=(robotID, topic)) - newSubID = response.headers['Location'] # <- get subscription-ID + if 'Location' in response.headers: + newSubID = response.headers['Location'] # <- get subscription-ID + else: + Log("WARNING", "Firos was not able to subscribe to topic: {} for robot {}".format(topic, robotID)) # Unsubscribe if robotID in self.subscriptionIds and topic in self.subscriptionIds[robotID]: @@ -114,7 +115,7 @@ def subscribeThread(self, robotID, topic): # Wait time.sleep(int(C.CB_SUB_LENGTH * C.CB_SUB_REFRESH)) # sleep Length * Refresh-Rate (where 0 < Refresh-Rate < 1) - Log("INFO", "Refreshing Subscription for " + robotID + " and topics: " + str(topic)) + Log("INFO", "Refreshing Subscription for " + robotID + " and topic: " + str(topic)) def subscribeJSONGenerator(self, robotID, topic): diff --git a/firos/include/genpy b/firos/include/genpy new file mode 160000 index 0000000..4f9fd0f --- /dev/null +++ b/firos/include/genpy @@ -0,0 +1 @@ +Subproject commit 4f9fd0f0d1481414bf59384470fc341f434d64f7 diff --git a/firos/include/genpy/__init__.py b/firos/include/genpy/__init__.py deleted file mode 100644 index b5d9079..0000000 --- a/firos/include/genpy/__init__.py +++ /dev/null @@ -1,37 +0,0 @@ -# Software License Agreement (BSD License) -# -# Copyright (c) 2011, Willow Garage, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Willow Garage, Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -from . rostime import Time, Duration, TVal -from . message import Message, SerializationError, DeserializationError, MessageException, struct_I - -__all__ = ['Time', 'Duration', 'TVal', - 'Message', 'SerializationError', 'DeserializationError', 'MessageException', 'struct_I'] diff --git a/firos/include/genpy/base.py b/firos/include/genpy/base.py deleted file mode 100644 index 46f54f9..0000000 --- a/firos/include/genpy/base.py +++ /dev/null @@ -1,65 +0,0 @@ -# Software License Agreement (BSD License) -# -# Copyright (c) 2008, Willow Garage, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Willow Garage, Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -################################################################################ -# Primitive type handling for ROS builtin types - -SIMPLE_TYPES_DICT = { #see python module struct - 'int8': 'b', - 'uint8': 'B', - # Python 2.6 adds in '?' for C99 _Bool, which appears equivalent to an uint8, - # thus, we use uint8 - 'bool': 'B', - 'int16' : 'h', - 'uint16' : 'H', - 'int32' : 'i', - 'uint32' : 'I', - 'int64' : 'q', - 'uint64' : 'Q', - 'float32': 'f', - 'float64': 'd', - # deprecated - 'char' : 'B', #unsigned - 'byte' : 'b', #signed - } - -## Simple types are primitives with fixed-serialization length -SIMPLE_TYPES = list(SIMPLE_TYPES_DICT.keys()) #py3k - -def is_simple(type_): - """ - :returns: ``True`` if type is a 'simple' type, i.e. is of - fixed/known serialization length. This is effectively all primitive - types except for string, ``bool`` - """ - return type_ in SIMPLE_TYPES - diff --git a/firos/include/genpy/dynamic.py b/firos/include/genpy/dynamic.py deleted file mode 100644 index 02edeb3..0000000 --- a/firos/include/genpy/dynamic.py +++ /dev/null @@ -1,192 +0,0 @@ -# Software License Agreement (BSD License) -# -# Copyright (c) 2008, Willow Garage, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Willow Garage, Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -""" -dynamic generation of deserializer -""" - -from __future__ import print_function - -try: - from cStringIO import StringIO # Python 2.x -except ImportError: - from io import StringIO # Python 3.x - -import atexit -import os -import shutil -import sys -import tempfile - -import genmsg -import genmsg.msg_loader -from genmsg import MsgContext, MsgGenerationException - -from generator import msg_generator - -def _generate_dynamic_specs(msg_context, specs, dep_msg): - """ - :param dep_msg: text of dependent .msg definition, ``str`` - :returns: type name, message spec, ``str, MsgSpec`` - :raises: MsgGenerationException If dep_msg is improperly formatted - """ - line1 = dep_msg.find('\n') - msg_line = dep_msg[:line1] - if not msg_line.startswith("MSG: "): - raise MsgGenerationException("invalid input to generate_dynamic: dependent type is missing 'MSG:' type declaration header") - dep_type = msg_line[5:].strip() - dep_pkg, dep_base_type = genmsg.package_resource_name(dep_type) - dep_spec = genmsg.msg_loader.load_msg_from_string(msg_context, dep_msg[line1+1:], dep_type) - return dep_type, dep_spec - -def _gen_dyn_name(pkg, base_type): - """ - Modify pkg/base_type name so that it can safely co-exist with - statically generated files. - - :returns: name to use for pkg/base_type for dynamically generated message class. - @rtype: str - """ - return "_%s__%s"%(pkg, base_type) - -def _gen_dyn_modify_references(py_text, types): - """ - Modify the generated code to rewrite names such that the code can - safely co-exist with messages of the same name. - - :param py_text: genmsg_py-generated Python source code, ``str`` - :returns: updated text, ``str`` - """ - for t in types: - pkg, base_type = genmsg.package_resource_name(t) - gen_name = _gen_dyn_name(pkg, base_type) - - # Several things we have to rewrite: - # - remove any import statements - py_text = py_text.replace("import %s.msg"%pkg, '') - # - rewrite any references to class - py_text = py_text.replace("%s.msg.%s"%(pkg, base_type), gen_name) - # - class declaration - py_text = py_text.replace('class %s('%base_type, 'class %s('%gen_name) - # - super() references for __init__ - py_text = py_text.replace('super(%s,'%base_type, 'super(%s,'%gen_name) - # std_msgs/Header also has to be rewritten to be a local reference - py_text = py_text.replace('std_msgs.msg._Header.Header', _gen_dyn_name('std_msgs', 'Header')) - return py_text - -def generate_dynamic(core_type, msg_cat): - """ - Dymamically generate message classes from msg_cat .msg text - gendeps dump. This method modifies sys.path to include a temp file - directory. - :param core_type str: top-level ROS message type of concatenanted .msg text - :param msg_cat str: concatenation of full message text (output of gendeps --cat) - :raises: MsgGenerationException If dep_msg is improperly formatted - """ - msg_context = MsgContext.create_default() - core_pkg, core_base_type = genmsg.package_resource_name(core_type) - - # REP 100: pretty gross hack to deal with the fact that we moved - # Header. Header is 'special' because it can be used w/o a package - # name, so the lookup rules end up failing. We are committed to - # never changing std_msgs/Header, so this is generally fine. - msg_cat = msg_cat.replace('roslib/Header', 'std_msgs/Header') - - # separate msg_cat into the core message and dependencies - splits = msg_cat.split('\n'+'='*80+'\n') - core_msg = splits[0] - deps_msgs = splits[1:] - - # create MsgSpec representations of .msg text - specs = { core_type: genmsg.msg_loader.load_msg_from_string(msg_context, core_msg, core_type) } - # - dependencies - for dep_msg in deps_msgs: - # dependencies require more handling to determine type name - dep_type, dep_spec = _generate_dynamic_specs(msg_context, specs, dep_msg) - specs[dep_type] = dep_spec - - # clear the message registration table and register loaded - # types. The types have to be registered globally in order for - # message generation of dependents to work correctly. - msg_context = genmsg.msg_loader.MsgContext.create_default() - search_path = {} # no ability to dynamically load - for t, spec in specs.items(): - msg_context.register(t, spec) - - # process actual MsgSpecs: we accumulate them into a single file, - # rewriting the generated text as needed - buff = StringIO() - for t, spec in specs.items(): - pkg, s_type = genmsg.package_resource_name(t) - # dynamically generate python message code - for l in msg_generator(msg_context, spec, search_path): - l = _gen_dyn_modify_references(l, list(specs.keys())) - buff.write(l + '\n') - full_text = buff.getvalue() - - # Create a temporary directory - tmp_dir = tempfile.mkdtemp(prefix='genpy_') - - # Afterwards, we are going to remove the directory so that the .pyc file gets cleaned up if it's still around - atexit.register(shutil.rmtree, tmp_dir) - - # write the entire text to a file and import it (it will get deleted when tmp_dir goes - above) - tmp_file = tempfile.NamedTemporaryFile(suffix=".py",dir=tmp_dir,delete=False) - tmp_file.file.write(full_text.encode()) - tmp_file.file.close() - - # import our temporary file as a python module, which requires modifying sys.path - sys.path.append(os.path.dirname(tmp_file.name)) - - # - strip the prefix to turn it into the python module name - try: - mod = __import__(os.path.basename(tmp_file.name)[:-3]) - except: - #TODOXXX:REMOVE - with open(tmp_file.name) as f: - text = f.read() - with open('/tmp/foo', 'w') as f2: - f2.write(text) - raise - - # finally, retrieve the message classes from the dynamic module - messages = {} - for t in specs.keys(): - pkg, s_type = genmsg.package_resource_name(t) - try: - messages[t] = getattr(mod, _gen_dyn_name(pkg, s_type)) - except AttributeError: - raise MsgGenerationException("cannot retrieve message class for %s/%s: %s"%(pkg, s_type, _gen_dyn_name(pkg, s_type))) - - return messages - - diff --git a/firos/include/genpy/generate_initpy.py b/firos/include/genpy/generate_initpy.py deleted file mode 100644 index 2774b18..0000000 --- a/firos/include/genpy/generate_initpy.py +++ /dev/null @@ -1,83 +0,0 @@ -# Software License Agreement (BSD License) -# -# Copyright (c) 2008, Willow Garage, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Willow Garage, Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -from __future__ import print_function - -import os - -from genmsg import MsgGenerationException - -## :param type_name str: Name of message type sans package, -## e.g. 'String' -## :returns str: name of python module for auto-generated code -def _module_name(type_name): - return "_"+type_name - -def write_modules(outdir): - if not os.path.isdir(outdir): - #TODO: warn? - return 0 - types_in_dir = set([f[1:-3] for f in os.listdir(outdir) - if f.endswith('.py') and f != '__init__.py']) - generated_modules = [_module_name(f) for f in types_in_dir] - write_module(outdir, generated_modules) - return 0 - -def write_module(basedir, generated_modules): - """ - Create a module file to mark directory for python - - :param base_dir: path to package, ``str`` - :param package: name of package to write module for, ``str`` - :param generated_modules: list of generated message modules, - i.e. the names of the .py files that were generated for each - .msg file. ``[str]`` - """ - if not os.path.exists(basedir): - os.makedirs(basedir) - elif not os.path.isdir(basedir): - raise MsgGenerationException("file preventing the creating of module directory: %s"%dir) - p = os.path.join(basedir, '__init__.py') - with open(p, 'w') as f: - for mod in generated_modules: - f.write('from .%s import *\n'%mod) - - parent_init = os.path.dirname(basedir) -# p = os.path.join(parent_init, '__init__.py') -# if not os.path.exists(p): -# #touch __init__.py in the parent package -# with open(p, 'w') as f: -# print("import pkgutil, os.path", file=f) -# print("__path__ = pkgutil.extend_path(__path__, __name__)", file=f) -# if srcdir is not None: -# staticinit = '%s/%s/__init__.py' % (srcdir, package) -# print("if os.path.isfile('%s'): execfile('%s')" % (staticinit, staticinit), file=f) diff --git a/firos/include/genpy/generate_numpy.py b/firos/include/genpy/generate_numpy.py deleted file mode 100644 index add6414..0000000 --- a/firos/include/genpy/generate_numpy.py +++ /dev/null @@ -1,71 +0,0 @@ -# Software License Agreement (BSD License) -# -# Copyright (c) 2008, Willow Garage, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Willow Garage, Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -""" -numpy support -""" - -from generate_struct import serialize - -# this could obviously be directly generated, but it's nice to abstract - -## maps ros msg types to numpy types -NUMPY_DTYPE = { - 'float32': 'numpy.float32', - 'float64': 'numpy.float64', - 'bool': 'numpy.bool', - 'int8': 'numpy.int8', - 'int16': 'numpy.int16', - 'int32': 'numpy.int32', - 'int64': 'numpy.int64', - 'uint8': 'numpy.uint8', - 'uint16': 'numpy.uint16', - 'uint32': 'numpy.uint32', - 'uint64': 'numpy.uint64', - # deprecated type - 'char' : 'numpy.uint8', - 'byte' : 'numpy.int8', - } -# TODO: this doesn't explicitly specify little-endian byte order on the numpy data instance -def unpack_numpy(var, count, dtype, buff): - """ - create numpy deserialization code - """ - return var + " = numpy.frombuffer(%s, dtype=%s, count=%s)"%(buff, dtype, count) - -def pack_numpy(var): - """ - create numpy serialization code - :param vars: name of variables to pack - """ - return serialize("%s.tostring()"%var) - diff --git a/firos/include/genpy/generate_struct.py b/firos/include/genpy/generate_struct.py deleted file mode 100644 index c29678d..0000000 --- a/firos/include/genpy/generate_struct.py +++ /dev/null @@ -1,152 +0,0 @@ -# Software License Agreement (BSD License) -# -# Copyright (c) 2008, Willow Garage, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Willow Garage, Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -from base import SIMPLE_TYPES_DICT - -_context_patterns = [] -def add_pattern(p): - """ - Record struct pattern that's been used for (de)serialization - """ - _context_patterns.append(p) -def clear_patterns(): - """ - Clear record of struct pattern that have been used for (de)serialization - """ - del _context_patterns[:] -def get_patterns(): - """ - :returns: record of struct pattern that have been used for (de)serialization - """ - return _context_patterns[:] - -def compute_struct_pattern(types): - """ - :param types: type names, ``[str]`` - :returns: format string for struct if types are all simple. Otherwise, return None, ``str`` - """ - if not types: #important to filter None and empty first - return None - try: - return ''.join([SIMPLE_TYPES_DICT[t] for t in types]) - except: - return None - -def reduce_pattern(pattern): - """ - Optimize the struct format pattern. - :param pattern: struct pattern, ``str`` - :returns: optimized struct pattern, ``str`` - """ - if not pattern or len(pattern) == 1 or '%' in pattern: - return pattern - prev = pattern[0] - count = 1 - new_pattern = '' - nums = [str(i) for i in range(0, 9)] - for c in pattern[1:]: - if c == prev and not c in nums: - count += 1 - else: - if count > 1: - new_pattern = new_pattern + str(count) + prev - else: - new_pattern = new_pattern + prev - prev = c - count = 1 - if count > 1: - new_pattern = new_pattern + str(count) + c - else: - new_pattern = new_pattern + prev - return new_pattern - -## :param expr str: string python expression that is evaluated for serialization -## :returns str: python call to write value returned by expr to serialization buffer -def serialize(expr): - return "buff.write(%s)"%expr - -# int32 is very common due to length serialization, so it is special cased -def int32_pack(var): - """ - :param var: variable name, ``str`` - :returns: struct packing code for an int32 - """ - return serialize('_struct_I.pack(%s)'%var) - -# int32 is very common due to length serialization, so it is special cased -def int32_unpack(var, buff): - """ - :param var: variable name, ``str`` - :returns: struct unpacking code for an int32 - """ - return '(%s,) = _struct_I.unpack(%s)'%(var, buff) - -#NOTE: '<' = little endian -def pack(pattern, vars): - """ - create struct.pack call for when pattern is a string pattern - :param pattern: pattern for pack, ``str`` - :param vars: name of variables to pack, ``str`` - """ - # - store pattern in context - pattern = reduce_pattern(pattern) - add_pattern(pattern) - return serialize("_struct_%s.pack(%s)"%(pattern, vars)) -def pack2(pattern, vars): - """ - create struct.pack call for when pattern is the name of a variable - :param pattern: name of variable storing string pattern, ``struct`` - :param vars: name of variables to pack, ``str`` - """ - return serialize("struct.pack(%s, %s)"%(pattern, vars)) - -def unpack(var, pattern, buff): - """ - create struct.unpack call for when pattern is a string pattern - :param var: name of variable to unpack, ``str`` - :param pattern: pattern for pack, ``str`` - :param buff: buffer to unpack from, ``str`` - """ - # - store pattern in context - pattern = reduce_pattern(pattern) - add_pattern(pattern) - return var + " = _struct_%s.unpack(%s)"%(pattern, buff) - -def unpack2(var, pattern, buff): - """ - Create struct.unpack call for when pattern refers to variable - :param var: variable the stores the result of unpack call, ``str`` - :param pattern: name of variable that unpack will read from, ``str`` - :param buff: buffer that the unpack reads from, ``StringIO`` - """ - return "%s = struct.unpack(%s, %s)"%(var, pattern, buff) - diff --git a/firos/include/genpy/generator.py b/firos/include/genpy/generator.py deleted file mode 100644 index a05e573..0000000 --- a/firos/include/genpy/generator.py +++ /dev/null @@ -1,1046 +0,0 @@ -# Software License Agreement (BSD License) -# -# Copyright (c) 2008, Willow Garage, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Willow Garage, Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -""" -Library for Python message generation. - -The structure of the serialization descends several levels of serializers: - - msg_generator: generator for an individual msg file - - serialize_fn_generator: generator for msg.serialize() - - serializer_generator - - field-type-specific serializers - raise MsgGenerationException("unknown file extension: %s"%f) - - - deserialize_fn_generator: generator for msg.deserialize() - - serializer_generator - - field-type-specific serializers -""" - -from __future__ import print_function - -import os -import keyword -import itertools -import sys -import traceback -import struct - -import genmsg -import genmsg.msgs -import genmsg.msg_loader -import genmsg.gentools - -from genmsg import InvalidMsgSpec, MsgContext, MsgSpec, MsgGenerationException -from genmsg.base import log - -from base import is_simple, SIMPLE_TYPES, SIMPLE_TYPES_DICT -from generate_numpy import unpack_numpy, pack_numpy, NUMPY_DTYPE -from generate_struct import reduce_pattern, serialize, \ - int32_pack, int32_unpack, pack, pack2, unpack, unpack2, compute_struct_pattern, \ - clear_patterns, add_pattern, get_patterns - -# indent width -INDENT = ' ' - -def get_registered_ex(msg_context, type_): - """ - wrapper for get_registered that wraps unknown types with a MsgGenerationException - :param type_: ROS message type, ``str`` - """ - try: - return msg_context.get_registered(type_) - except: - raise MsgGenerationException("Unknown type [%s]. Please check that the manifest.xml correctly declares dependencies."%type_) - -################################################################################ -# Special type handling for ROS builtin types that are not primitives - -class Special: - - def __init__(self, constructor, post_deserialize, import_str): - """ - :param constructor: expression to instantiate new type instance for deserialization, ``str`` - :param post_Deserialize: format string for expression to evaluate on type instance after deserialization is complete., ``str`` - variable name will be passed in as the single argument to format string. - :param import_str: import to include if type is present, ``str`` - """ - self.constructor = constructor - self.post_deserialize = post_deserialize - self.import_str = import_str - - def get_post_deserialize(self, varname): - """ - :returns: Post-deserialization code to executed (unindented) or - ``None`` if no post-deserialization is required, ``str`` - """ - if self.post_deserialize: - return self.post_deserialize%varname - else: - return None - -_SPECIAL_TYPES = { - genmsg.HEADER: Special('std_msgs.msg._Header.Header()', None, 'import std_msgs.msg'), - genmsg.TIME: Special('genpy.Time()', '%s.canon()', 'import genpy'), - genmsg.DURATION: Special('genpy.Duration()', '%s.canon()', 'import genpy'), - } - -def is_special(type_): - """ - :returns: ``True` if *type_* is a special type (i.e. builtin represented as a class instead of a primitive), ``bool`` - """ - return type_ in _SPECIAL_TYPES - -def get_special(type_): - """ - :returns: special type handler for *type_* or ``None``, ``Special`` - """ - return _SPECIAL_TYPES.get(type_, None) - -################################################################################ -# utilities - -# #671 -def default_value(msg_context, field_type, default_package): - """ - Compute default value for field_type - - :param default_package: default package, ``str`` - :param field_type: ROS .msg field type, ``str`` - :returns: default value encoded in Python string representation, ``str`` - """ - if field_type in ['byte', 'int8', 'int16', 'int32', 'int64',\ - 'char', 'uint8', 'uint16', 'uint32', 'uint64']: - return '0' - elif field_type in ['float32', 'float64']: - return '0.' - elif field_type == 'string': - # strings, char[], and uint8s are all optimized to be strings - return "''" - elif field_type == 'bool': - return 'False' - elif field_type.endswith(']'): # array type - base_type, is_array, array_len = genmsg.msgs.parse_type(field_type) - if base_type in ['char', 'uint8']: - # strings, char[], and uint8s are all optimized to be strings - if array_len is not None: - return "chr(0)*%s"%array_len - else: - return "''" - elif array_len is None: #var-length - return '[]' - else: # fixed-length, fill values - def_val = default_value(msg_context, base_type, default_package) - return '[' + ','.join(itertools.repeat(def_val, array_len)) + ']' - else: - return compute_constructor(msg_context, default_package, field_type) - -def flatten(msg_context, msg): - """ - Flattens the msg spec so that embedded message fields become - direct references. The resulting MsgSpec isn't a true/legal - :class:`MsgSpec` and should only be used for serializer generation. - :param msg: MsgSpec to flatten - :returns: flattened MsgSpec message - """ - new_types = [] - new_names = [] - for t, n in zip(msg.types, msg.names): - # Parse type to make sure we don't flatten an array - msg_type, is_array, _ = genmsg.msgs.parse_type(t) - #flatten embedded types - note: bug #59 - if not is_array and msg_context.is_registered(t): - msg_spec = flatten(msg_context, msg_context.get_registered(t)) - new_types.extend(msg_spec.types) - for n2 in msg_spec.names: - new_names.append(n+'.'+n2) - else: - #I'm not sure if it's a performance win to flatten fixed-length arrays - #as you get n __getitems__ method calls vs. a single *array call - new_types.append(t) - new_names.append(n) - return MsgSpec(new_types, new_names, msg.constants, msg.text, msg.full_name) - -def make_python_safe(spec): - """ - Remap field/constant names in spec to avoid collision with Python reserved words. - - :param spec: msg spec to map to new, python-safe field names, ``MsgSpec`` - :returns: python-safe message specification, ``MsgSpec`` - """ - new_c = [genmsg.Constant(c.type, _remap_reserved(c.name), c.val, c.val_text) for c in spec.constants] - return MsgSpec(spec.types, [_remap_reserved(n) for n in spec.names], new_c, spec.text, spec.full_name) - -def _remap_reserved(field_name): - """ - Map field_name to a python-safe representation, if necessary - :param field_name: msg field name, ``str`` - :returns: remapped name, ``str`` - """ - # include 'self' as well because we are within a class instance - idx = field_name.rfind('.') - if idx > 0: - prefix = field_name[:idx+1] - sub_field_name = field_name[idx+1:] - else: - prefix = '' - sub_field_name = field_name - - if sub_field_name in keyword.kwlist + ['self']: - sub_field_name = sub_field_name + "_" - return prefix + sub_field_name - -################################################################################ -# (de)serialization routines - -def compute_post_deserialize(type_, varname): - """ - Compute post-deserialization code for type_, if necessary - :returns: code to execute post-deserialization (unindented), or None if not necessary. ``str`` - """ - s = get_special(type_) - if s is not None: - return s.get_post_deserialize(varname) - -def compute_constructor(msg_context, package, type_): - """ - Compute python constructor expression for specified message type implementation - :param package str: package that type is being imported into. Used - to resolve type_ if package is not specified. ``str`` - :param type_: message type, ``str`` - """ - if is_special(type_): - return get_special(type_).constructor - elif genmsg.msgs.bare_msg_type(type_) != type_: - # array or other weird type - return None - else: - base_pkg, base_type_ = compute_pkg_type(package, type_) - if not msg_context.is_registered("%s/%s"%(base_pkg,base_type_)): - return None - else: - return '%s.msg.%s()'%(base_pkg, base_type_) - -def compute_pkg_type(package, type_): - """ - :param package: package that type is being imported into, ``str`` - :param type: message type (package resource name), ``str`` - :returns: python package and type name, ``(str, str)`` - """ - splits = type_.split(genmsg.SEP) - if len(splits) == 1: - return package, splits[0] - elif len(splits) == 2: - return tuple(splits) - else: - raise MsgGenerationException("illegal message type: %s"%type_) - -def compute_import(msg_context, package, type_): - """ - Compute python import statement for specified message type implementation - :param package: package that type is being imported into, ``str`` - :param type_: message type (package resource name), ``str`` - :returns: list of import statements (no newline) required to use type_ from package, ``[str]`` - """ - # orig_base_type is the unresolved type - orig_base_type = genmsg.msgs.bare_msg_type(type_) # strip array-suffix - # resolve orig_base_type based on the current package context. - # base_type is the resolved type stripped of any package name. - # pkg is the actual package of type_. - pkg, base_type = compute_pkg_type(package, orig_base_type) - full_msg_type = "%s/%s"%(pkg, base_type) # compute fully-qualified type - # important: have to do is_builtin check first. We do this check - # against the unresolved type builtins/specials are never - # relative. This requires some special handling for Header, which has - # two names (Header and std_msgs/Header). - if genmsg.msgs.is_builtin(orig_base_type) or \ - genmsg.msgs.is_header_type(orig_base_type): - # of the builtin types, only special types require import - # handling. we switch to base_type as special types do not - # include package names. - if is_special(base_type): - retval = [get_special(base_type).import_str] - else: - retval = [] - elif not msg_context.is_registered(full_msg_type): - retval = [] - else: - retval = ['import %s.msg'%pkg] - iter_types = get_registered_ex(msg_context, full_msg_type).types - for t in iter_types: - assert t != full_msg_type, "msg [%s] has circular self-dependencies"%(full_msg_type) - full_sub_type = "%s/%s"%(package, t) - log("compute_import", full_msg_type, package, t) - sub = compute_import(msg_context, package, t) - retval.extend([x for x in sub if not x in retval]) - return retval - -def compute_full_text_escaped(msg_context, spec): - """ - Same as genmsg.compute_full_text, except that the - resulting text is escaped to be safe for Python's triple-quote string - quoting - - :param get_deps_dict: dictionary returned by load_dependencies call, ``dict`` - :returns: concatenated text for msg/srv file and embedded msg/srv types. Text will be escaped for triple-quote, ``str`` - """ - msg_definition = genmsg.compute_full_text(msg_context, spec) - msg_definition.replace('"""', r'\"\"\"') - return msg_definition - -################################################################################ -# (De)serialization generators - -_serial_context = '' -_context_stack = [] - -_counter = 0 -def next_var(): - # we could optimize this by reusing vars once the context is popped - global _counter - _counter += 1 - return '_v%s'%_counter - -def reset_var(): - global _counter - _counter = 0 - -def push_context(context): - """ - Push new variable context onto context stack. The context stack - manages field-reference context for serialization, e.g. 'self.foo' - vs. 'self.bar.foo' vs. 'var.foo' - """ - global _serial_context, _context_stack - _context_stack.append(_serial_context) - _serial_context = context - -def pop_context(): - """ - Pop variable context from context stack. The context stack manages - field-reference context for serialization, e.g. 'self.foo' - vs. 'self.bar.foo' vs. 'var.foo' - """ - global _serial_context - _serial_context = _context_stack.pop() - -# These are the workhorses of the message generation. The generators -# are implemented as iterators, where each iteration value is a line -# of Python code. The generators will invoke underlying generators, -# using the context stack to manage any changes in variable-naming, so -# that code can be reused as much as possible. - -def len_serializer_generator(var, is_string, serialize): - """ - Generator for array-length serialization (32-bit, little-endian unsigned integer) - :param var: variable name, ``str`` - :param is_string: if True, variable is a string type, ``bool`` - :param serialize bool: if True, generate code for - serialization. Other, generate code for deserialization, ``bool`` - """ - if serialize: - yield "length = len(%s)"%var - # NOTE: it's more difficult to save a call to struct.pack with - # the array length as we are already using *array_val to pass - # into struct.pack as *args. Although it's possible that - # Python is not optimizing it, it is potentially worse for - # performance to attempt to combine - if not is_string: - yield int32_pack("length") - else: - yield "start = end" - yield "end += 4" - yield int32_unpack('length', 'str[start:end]') #4 = struct.calcsize(' 1 and _serial_context.endswith('.'): - yield '_x = '+_serial_context[:-1] - vars_ = '_x.' + (', _x.').join(spec.names[start:end]) - else: - vars_ = _serial_context + (', '+_serial_context).join(spec.names[start:end]) - - pattern = compute_struct_pattern(spec.types[start:end]) - if serialize: - yield pack(pattern, vars_) - else: - yield "start = end" - yield "end += %s"%struct.calcsize('<%s'%reduce_pattern(pattern)) - yield unpack('(%s,)'%vars_, pattern, 'str[start:end]') - - # convert uint8 to bool. this doesn't add much value as Python - # equality test on a field will return that True == 1, but I - # want to be consistent with bool - bool_vars = [(f, t) for f, t in zip(spec.names[start:end], spec.types[start:end]) if t == 'bool'] - for f, t in bool_vars: - #TODO: could optimize this as well - var = _serial_context+f - yield "%s = bool(%s)"%(var, var) - -def serializer_generator(msg_context, spec, serialize, is_numpy): - """ - Python generator that yields un-indented python code for - (de)serializing MsgSpec. The code this yields is meant to be - included in a class method and cannot be used - standalone. serialize_fn_generator and deserialize_fn_generator - wrap method to provide appropriate class field initializations. - - :param serialize: if True, yield serialization - code. Otherwise, yield deserialization code. ``bool`` - :param is_numpy: if True, generate serializer code for numpy datatypes instead of Python lists. ``bool`` - """ - # Break spec into chunks of simple (primitives) vs. complex (arrays, etc...) - # Simple types are batch serialized using the python struct module. - # Complex types are individually serialized - if spec is None: - raise MsgGenerationException("spec is none") - names, types = spec.names, spec.types - if serialize and not len(names): #Empty - yield "pass" - return - - _max_chunk = 255 - # iterate through types. whenever we encounter a non-simple type, - # yield serializer for any simple types we've encountered until - # then, then yield the complex type serializer - curr = 0 - for (i, full_type) in enumerate(types): - if not is_simple(full_type): - if i != curr: #yield chunk of simples - for _start in range(curr, i, _max_chunk): - _end = min(_start + _max_chunk, i) - for y in simple_serializer_generator(msg_context, spec, _start, _end, serialize): - yield y - curr = i+1 - for y in complex_serializer_generator(msg_context, spec.package, full_type, names[i], serialize, is_numpy): - yield y - if curr < len(types): #yield rest of simples - for _start in range(curr, len(types), _max_chunk): - _end = min(_start + _max_chunk, len(types)) - for y in simple_serializer_generator(msg_context, spec, _start, _end, serialize): - yield y - -def serialize_fn_generator(msg_context, spec, is_numpy=False): - """ - generator for body of serialize() function - :param is_numpy: if True, generate serializer code for numpy - datatypes instead of Python lists, ``bool`` - """ - # method-var context ######### - yield "try:" - push_context('self.') - #NOTE: we flatten the spec for optimal serialization - # #3741: make sure to have sub-messages python safe - flattened = make_python_safe(flatten(msg_context, spec)) - for y in serializer_generator(msg_context, flattened, True, is_numpy): - yield " "+y - pop_context() - yield "except struct.error as se: self._check_types(struct.error(\"%s: '%s' when writing '%s'\" % (type(se), str(se), str(_x))))" - yield "except TypeError as te: self._check_types(ValueError(\"%s: '%s' when writing '%s'\" % (type(te), str(te), str(_x))))" - # done w/ method-var context # - -def deserialize_fn_generator(msg_context, spec, is_numpy=False): - """ - generator for body of deserialize() function - :param is_numpy: if True, generate serializer code for numpy - datatypes instead of Python lists, ``bool`` - """ - yield "try:" - package = spec.package - #Instantiate embedded type classes - for type_, name in spec.fields(): - if msg_context.is_registered(type_): - yield " if self.%s is None:"%name - yield " self.%s = %s"%(name, compute_constructor(msg_context, package, type_)) - yield " end = 0" #initialize var - - # method-var context ######### - push_context('self.') - #NOTE: we flatten the spec for optimal serialization - # #3741: make sure to have sub-messages python safe - flattened = make_python_safe(flatten(msg_context, spec)) - for y in serializer_generator(msg_context, flattened, False, is_numpy): - yield " "+y - pop_context() - # done w/ method-var context # - - # generate post-deserialization code - for type_, name in spec.fields(): - code = compute_post_deserialize(type_, "self.%s"%name) - if code: - yield " %s"%code - - yield " return self" - yield "except struct.error as e:" - yield " raise genpy.DeserializationError(e) #most likely buffer underfill" - -def msg_generator(msg_context, spec, search_path): - """ - Python code generator for .msg files. Generates a Python from a - :class:`genmsg.MsgSpec`. - - :param spec: parsed .msg :class:`genmsg.MsgSpec` instance - :param search_path: dictionary mapping message namespaces to a directory locations - """ - - # #2990: have to compute md5sum before any calls to make_python_safe - - # generate dependencies dictionary. omit files calculation as we - # rely on in-memory MsgSpecs instead so that we can generate code - # for older versions of msg files - try: - genmsg.msg_loader.load_depends(msg_context, spec, search_path) - except InvalidMsgSpec as e: - raise MsgGenerationException("Cannot generate .msg for %s/%s: %s"%(package, name, str(e))) - md5sum = genmsg.compute_md5(msg_context, spec) - - # remap spec names to be Python-safe - spec = make_python_safe(spec) - spec_names = spec.names - - # #1807 : this will be much cleaner when msggenerator library is - # rewritten to not use globals - clear_patterns() - - yield '"""autogenerated by genpy from %s.msg. Do not edit."""'%spec.full_name - yield 'import sys' - yield 'python3 = True if sys.hexversion > 0x03000000 else False' - yield 'import genpy\nimport struct\n' - import_strs = [] - for t in spec.types: - import_strs.extend(compute_import(msg_context, spec.package, t)) - import_strs = set(import_strs) - for i in import_strs: - if i: - yield i - - yield '' - - fulltype = spec.full_name - name = spec.short_name - - #Yield data class first, e.g. Point2D - yield 'class %s(genpy.Message):'%spec.short_name - yield ' _md5sum = "%s"'%(md5sum) - yield ' _type = "%s"'%(fulltype) - yield ' _has_header = %s #flag to mark the presence of a Header object'%spec.has_header() - # note: we introduce an extra newline to protect the escaping from quotes in the message - yield ' _full_text = """%s\n"""'%compute_full_text_escaped(msg_context, spec) - - if spec.constants: - yield ' # Pseudo-constants' - for c in spec.constants: - if c.type == 'string': - val = c.val - if '"' in val and "'" in val: - # crude escaping of \ and " - escaped = c.val.replace('\\', '\\\\') - escaped = escaped.replace('\"', '\\"') - yield ' %s = "%s"'%(c.name, escaped) - elif '"' in val: #use raw encoding for prettiness - yield " %s = r'%s'"%(c.name, val) - elif "'" in val: #use raw encoding for prettiness - yield ' %s = r"%s"'%(c.name, val) - else: - yield " %s = '%s'"%(c.name, val) - else: - yield ' %s = %s'%(c.name, c.val) - yield '' - - if len(spec_names): - yield " __slots__ = ['"+"','".join(spec_names)+"']" - yield " _slot_types = ['"+"','".join(spec.types)+"']" - else: - yield " __slots__ = []" - yield " _slot_types = []" - - yield """ - def __init__(self, *args, **kwds): - \"\"\" - Constructor. Any message fields that are implicitly/explicitly - set to None will be assigned a default value. The recommend - use is keyword arguments as this is more robust to future message - changes. You cannot mix in-order arguments and keyword arguments. - - The available fields are: - %s - - :param args: complete set of field values, in .msg order - :param kwds: use keyword arguments corresponding to message field names - to set specific fields. - \"\"\" - if args or kwds: - super(%s, self).__init__(*args, **kwds)"""%(','.join(spec_names), name) - - if len(spec_names): - yield " #message fields cannot be None, assign default values for those that are" - for (t, s) in zip(spec.types, spec_names): - yield " if self.%s is None:"%s - yield " self.%s = %s"%(s, default_value(msg_context, t, spec.package)) - if len(spec_names) > 0: - yield " else:" - for (t, s) in zip(spec.types, spec_names): - yield " self.%s = %s"%(s, default_value(msg_context, t, spec.package)) - - yield """ - def _get_types(self): - \"\"\" - internal API method - \"\"\" - return self._slot_types - - def serialize(self, buff): - \"\"\" - serialize message into buffer - :param buff: buffer, ``StringIO`` - \"\"\"""" - for y in serialize_fn_generator(msg_context, spec): - yield " "+ y - yield """ - def deserialize(self, str): - \"\"\" - unpack serialized message in str into this message instance - :param str: byte array of serialized message, ``str`` - \"\"\"""" - for y in deserialize_fn_generator(msg_context, spec): - yield " " + y - yield "" - - yield """ - def serialize_numpy(self, buff, numpy): - \"\"\" - serialize message with numpy array types into buffer - :param buff: buffer, ``StringIO`` - :param numpy: numpy python module - \"\"\"""" - for y in serialize_fn_generator(msg_context, spec, is_numpy=True): - yield " "+ y - yield """ - def deserialize_numpy(self, str, numpy): - \"\"\" - unpack serialized message in str into this message instance using numpy for array types - :param str: byte array of serialized message, ``str`` - :param numpy: numpy python module - \"\"\"""" - for y in deserialize_fn_generator(msg_context, spec, is_numpy=True): - yield " " + y - yield "" - - - # #1807 : this will be much cleaner when msggenerator library is - # rewritten to not use globals - yield '_struct_I = genpy.struct_I' - patterns = get_patterns() - for p in set(patterns): - # I patterns are already optimized - if p == 'I': - continue - var_name = '_struct_%s'%(p.replace('<','')) - yield '%s = struct.Struct("<%s")'%(var_name, p) - clear_patterns() - -def srv_generator(msg_context, spec, search_path): - for mspec in (spec.request, spec.response): - for l in msg_generator(msg_context, mspec, search_path): - yield l - - name = spec.short_name - req, resp = ["%s%s"%(name, suff) for suff in ['Request', 'Response']] - - fulltype = spec.full_name - - genmsg.msg_loader.load_depends(msg_context, spec, search_path) - md5 = genmsg.compute_md5(msg_context, spec) - - yield "class %s(object):"%name - yield " _type = '%s'"%fulltype - yield " _md5sum = '%s'"%md5 - yield " _request_class = %s"%req - yield " _response_class = %s"%resp - -def _module_name(type_name): - """ - :param type_name str: Name of message type sans package, - e.g. 'String' - :returns str: name of python module for auto-generated code - """ - return "_"+type_name - -def compute_resource_name(filename, ext): - """ - Convert resource filename to ROS resource name - :param filename str: path to .msg/.srv file - :returns str: name of ROS resource - """ - return os.path.basename(filename)[:-len(ext)] - -def compute_outfile_name(outdir, infile_name, ext): - """ - :param outdir str: path to directory that files are generated to - :returns str: output file path based on input file name and output directory - """ - # Use leading _ so that module name does not collide with message name. It also - # makes it more clear that the .py file should not be imported directly - return os.path.join(outdir, _module_name(compute_resource_name(infile_name, ext))+".py") - -class Generator(object): - - def __init__(self, what, ext, spec_loader_fn, generator_fn): - self.what = what - self.ext = ext - self.spec_loader_fn = spec_loader_fn - self.generator_fn = generator_fn - - def firos_generate(self, msg_context, full_type, topic_data, outdir, search_path): - # generate message files for request/response - formatted_msg = "" - for data in topic_data['msg']: - formatted_msg += str(topic_data['msg'][data]) + " " + str(data) + "\n" - formatted_msg = formatted_msg[:-1] - spec = self.spec_loader_fn(msg_context, formatted_msg, full_type) - file_name = full_type.replace("/", "") - outfile = os.path.join(outdir, file_name + ".py") - - print("Generating message definition for " + full_type) - - with open(outfile, 'w') as f: - for l in self.generator_fn(msg_context, spec, search_path): - f.write(l+'\n') - f.close() - return outfile - - def generate(self, msg_context, full_type, f, outdir, search_path): - try: - # you can't just check first... race condition - os.makedirs(outdir) - except OSError as e: - if e.errno != 17: # file exists - raise - # generate message files for request/response - spec = self.spec_loader_fn(msg_context, f, full_type) - outfile = compute_outfile_name(outdir, os.path.basename(f), self.ext) - with open(outfile, 'w') as f: - for l in self.generator_fn(msg_context, spec, search_path): - f.write(l+'\n') - return outfile - - def generate_firos_messages(self, package, data, outdir, OUTPUT, search_path): - """ - :returns: return code, ``int`` - """ - if not genmsg.is_legal_resource_base_name(package): - raise MsgGenerationException("\nERROR: package name '%s' is illegal and cannot be used in message generation.\nPlease see http://ros.org/wiki/Names"%(package)) - - # package/src/package/msg for messages, packages/src/package/srv for services - msg_context = MsgContext.create_default() - retcode = 0 - try: - # you can't just check first... race condition - outdir = outdir + OUTPUT - os.makedirs(outdir) - f = open(os.path.join(outdir, "__init__.py"), 'w') - f.close() - except OSError as e: - if e.errno != 17: # file exists - raise - - for robotName in data: - try: - robot = data[robotName] - for topic_name in robot['topics']: - topic = robot['topics'][topic_name] - full_type = str(robotName) + '/' + str(topic_name) - if type(topic['msg']) is dict: - self.firos_generate(msg_context, full_type, topic, outdir, search_path) #actual generation - except Exception as e: - if not isinstance(e, MsgGenerationException) and not isinstance(e, genmsg.msgs.InvalidMsgSpec): - traceback.print_exc() - print("\nERROR: Unable to generate %s for package '%s': %s\n"%(self.what, package, e), file=sys.stderr) - retcode = 1 #flag error - return retcode - - def generate_messages(self, package, package_files, outdir, search_path): - """ - :returns: return code, ``int`` - """ - if not genmsg.is_legal_resource_base_name(package): - raise MsgGenerationException("\nERROR: package name '%s' is illegal and cannot be used in message generation.\nPlease see http://ros.org/wiki/Names"%(package)) - - # package/src/package/msg for messages, packages/src/package/srv for services - msg_context = MsgContext.create_default() - retcode = 0 - for f in package_files: - try: - f = os.path.abspath(f) - infile_name = os.path.basename(f) - full_type = genmsg.gentools.compute_full_type_name(package, infile_name); - outfile = self.generate(msg_context, full_type, f, outdir, search_path) #actual generation - except Exception as e: - if not isinstance(e, MsgGenerationException) and not isinstance(e, genmsg.msgs.InvalidMsgSpec): - traceback.print_exc() - print("\nERROR: Unable to generate %s for package '%s': while processing '%s': %s\n"%(self.what, package, f, e), file=sys.stderr) - retcode = 1 #flag error - return retcode - -class SrvGenerator(Generator): - - def __init__(self): - super(SrvGenerator, self).__init__('services', genmsg.EXT_SRV, - genmsg.msg_loader.load_srv_from_file, - srv_generator) - -class MsgGenerator(Generator): - """ - Generates Python message code for all messages in a - package. See genutil.Generator. In order to generator code for a - single .msg file, see msg_generator. - """ - def __init__(self, loader=genmsg.msg_loader.load_msg_from_file): - super(MsgGenerator, self).__init__('messages', genmsg.EXT_MSG, - loader, - msg_generator) - diff --git a/firos/include/genpy/genpy_firos.py b/firos/include/genpy/genpy_firos.py deleted file mode 100644 index 9166442..0000000 --- a/firos/include/genpy/genpy_firos.py +++ /dev/null @@ -1,66 +0,0 @@ -# Software License Agreement (BSD License) -# -# Copyright (c) 2008, Willow Garage, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Willow Garage, Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -from __future__ import print_function - -from optparse import OptionParser - -import os -import sys -import traceback -import genmsg -import genmsg.command_line - -from genmsg import MsgGenerationException -from generate_initpy import write_modules - -def usage(progname): - print("%(progname)s file(s)"%vars()) - -def genmain(data, gen, outdir=None): - OUTPUT = "topics" - PACKAGE = "package" # Currently not used - try: - search_path = {} - retcode = gen.generate_firos_messages("package", data, outdir, OUTPUT, search_path) - - except genmsg.InvalidMsgSpec as e: - print("ERROR: ", e, file=sys.stderr) - retcode = 1 - except MsgGenerationException as e: - print("ERROR: ", e, file=sys.stderr) - retcode = 2 - except Exception as e: - traceback.print_exc() - print("ERROR: ",e) - retcode = 3 - return(retcode or 0) diff --git a/firos/include/genpy/genpy_main.py b/firos/include/genpy/genpy_main.py deleted file mode 100644 index 218c7e9..0000000 --- a/firos/include/genpy/genpy_main.py +++ /dev/null @@ -1,87 +0,0 @@ -# Software License Agreement (BSD License) -# -# Copyright (c) 2008, Willow Garage, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Willow Garage, Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -from __future__ import print_function - -from optparse import OptionParser - -import os -import sys -import traceback -import genmsg -import genmsg.command_line - -from genmsg import MsgGenerationException -from generate_initpy import write_modules - -def usage(progname): - print("%(progname)s file(s)"%vars()) - -def genmain(argv, progname, gen): - parser = OptionParser("%s file"%(progname)) - parser.add_option('--initpy', dest='initpy', action='store_true', - default=False) - parser.add_option('-p', dest='package') - parser.add_option('-o', dest='outdir') - parser.add_option('-I', dest='includepath', action='append') - options, args = parser.parse_args(argv) - try: - if options.initpy: - if options.outdir: - retcode = write_modules(options.outdir) - else: - parser.error("Missing args") - else: - if len(args) < 2: - parser.error("please specify args") - if not os.path.exists(options.outdir): - # This script can be run multiple times in parallel. We - # don't mind if the makedirs call fails because somebody - # else snuck in and created the directory before us. - try: - os.makedirs(options.outdir) - except OSError as e: - if not os.path.exists(options.outdir): - raise - search_path = genmsg.command_line.includepath_to_dict(options.includepath) - retcode = gen.generate_messages(options.package, args[1:], options.outdir, search_path) - except genmsg.InvalidMsgSpec as e: - print("ERROR: ", e, file=sys.stderr) - retcode = 1 - except MsgGenerationException as e: - print("ERROR: ", e, file=sys.stderr) - retcode = 2 - except Exception as e: - traceback.print_exc() - print("ERROR: ",e) - retcode = 3 - sys.exit(retcode or 0) diff --git a/firos/include/genpy/message.py b/firos/include/genpy/message.py deleted file mode 100644 index c68634b..0000000 --- a/firos/include/genpy/message.py +++ /dev/null @@ -1,643 +0,0 @@ -# Software License Agreement (BSD License) -# -# Copyright (c) 2008, Willow Garage, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Willow Garage, Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -""" -Support library for Python autogenerated message files. This defines -the Message base class used by genpy as well as support -libraries for type checking and retrieving message classes by type -name. -""" - -import math -import itertools -import struct -import sys - -import genmsg - -from base import is_simple -from rostime import Time, Duration, TVal - -# common struct pattern singletons for msgs to use. Although this -# would better placed in a generator-specific module, we don't want to -# add another import to messages (which incurs higher import cost) - -if sys.version > '3': - long = int - -struct_I = struct.Struct('iter(str)`` - :returns: string (YAML) representation of message, ``str`` - """ - - type_ = type(val) - if type_ in (int, long, float) and fixed_numeric_width is not None: - if type_ is float: - num_str = ('%.' + str(fixed_numeric_width) + 'f') % val - return num_str[:max(num_str.find('.'), fixed_numeric_width)] - else: - return ('%' + str(fixed_numeric_width) + 'd') % val - elif type_ in (int, long, float, bool): - return str(val) - elif isstring(val): - #TODO: need to escape strings correctly - if not val: - return "''" - return val - elif isinstance(val, TVal): - - if time_offset is not None and isinstance(val, Time): - val = val-time_offset - - if fixed_numeric_width is not None: - format_str = '%' + str(fixed_numeric_width) + 'd' - sec_str = '\n%ssecs: ' % indent + (format_str % val.secs) - nsec_str = '\n%snsecs: ' % indent + (format_str % val.nsecs) - return sec_str + nsec_str - else: - return '\n%ssecs: %s\n%snsecs: %s'%(indent, val.secs, indent, val.nsecs) - - elif type_ in (list, tuple): - if len(val) == 0: - return "[]" - val0 = val[0] - if type(val0) in (int, float) and fixed_numeric_width is not None: - list_str = '[' + ''.join(strify_message(v, indent, time_offset, current_time, field_filter, fixed_numeric_width) + ', ' for v in val).rstrip(', ') + ']' - return list_str - elif type(val0) in (int, float, str, bool): - # TODO: escape strings properly - return str(list(val)) - else: - pref = indent + '- ' - indent = indent + ' ' - return '\n'+'\n'.join([pref+strify_message(v, indent, time_offset, current_time, field_filter, fixed_numeric_width) for v in val]) - elif isinstance(val, Message): - # allow caller to select which fields of message are strified - if field_filter is not None: - fields = list(field_filter(val)) - else: - fields = val.__slots__ - - p = '%s%%s: %%s'%(indent) - ni = ' '+indent - if sys.hexversion > 0x03000000: #Python3 - vals = '\n'.join([p%(f, - strify_message(_convert_getattr(val, f, t), ni, time_offset, current_time, field_filter, fixed_numeric_width)) for f,t in zip(val.__slots__, val._slot_types) if f in fields]) - else: #Python2 - vals = '\n'.join([p%(f, - strify_message(_convert_getattr(val, f, t), ni, time_offset, current_time, field_filter, fixed_numeric_width)) for f,t in itertools.izip(val.__slots__, val._slot_types) if f in fields]) - if indent: - return '\n'+vals - else: - return vals - - else: - return str(val) #punt - -def _convert_getattr(val, f, t): - """ - Convert atttribute types on the fly, if necessary. This is mainly - to convert uint8[] fields back to an array type. - """ - attr = getattr(val, f) - if isstring(attr) and 'uint8[' in t: - return [ord(x) for x in attr] - else: - return attr - -# check_type mildly violates some abstraction boundaries between .msg -# representation and the python Message representation. The -# alternative is to have the message generator map .msg types to -# python types beforehand, but that would make it harder to do -# width/signed checks. - -_widths = { - 'byte': 8, 'char': 8, 'int8': 8, 'uint8': 8, - 'int16': 16, 'uint16': 16, - 'int32': 32, 'uint32': 32, - 'int64': 64, 'uint64': 64, -} - -def check_type(field_name, field_type, field_val): - """ - Dynamic type checker that maps ROS .msg types to python types and - verifies the python value. check_type() is not designed to be - fast and is targeted at error diagnosis. This type checker is not - designed to run fast and is meant only for error diagnosis. - - :param field_name: ROS .msg field name, ``str`` - :param field_type: ROS .msg field type, ``str`` - :param field_val: field value, ``Any`` - :raises: :exc:`SerializationError` If typecheck fails - """ - if is_simple(field_type): - # check sign and width - if field_type in ['byte', 'int8', 'int16', 'int32', 'int64']: - if type(field_val) not in [long, int]: - raise SerializationError('field %s must be an integer type'%field_name) - maxval = int(math.pow(2, _widths[field_type]-1)) - if field_val >= maxval or field_val <= -maxval: - raise SerializationError('field %s exceeds specified width [%s]'%(field_name, field_type)) - elif field_type in ['char', 'uint8', 'uint16', 'uint32', 'uint64']: - if type(field_val) not in [long, int] or field_val < 0: - raise SerializationError('field %s must be unsigned integer type'%field_name) - maxval = int(math.pow(2, _widths[field_type])) - if field_val >= maxval: - raise SerializationError('field %s exceeds specified width [%s]'%(field_name, field_type)) - elif field_type == 'bool': - if field_val not in [True, False, 0, 1]: - raise SerializationError('field %s is not a bool'%(field_name)) - elif field_type == 'string': - if sys.hexversion > 0x03000000: - if type(field_val) == str: - try: - field_val.encode('ascii') - except UnicodeEncodeError: - raise SerializationError('field %s is a non-ascii string'%field_name) - elif not type(field_val) == bytes: - raise SerializationError('field %s must be of type bytes or an ascii string'%field_name) - else: - if type(field_val) == unicode: - raise SerializationError('field %s is a unicode string instead of an ascii string'%field_name) - elif not isstring(field_val): - raise SerializationError('field %s must be of type str'%field_name) - elif field_type == 'time': - if not isinstance(field_val, Time): - raise SerializationError('field %s must be of type Time'%field_name) - elif field_type == 'duration': - if not isinstance(field_val, Duration): - raise SerializationError('field %s must be of type Duration'%field_name) - - elif field_type.endswith(']'): # array type - # use index to generate error if '[' not present - base_type = field_type[:field_type.index('[')] - - if type(field_val) == str: - if not base_type in ['char', 'uint8']: - raise SerializationError('field %s must be a list or tuple type. Only uint8[] can be a string' % field_name); - else: - #It's a string so its already in byte format and we - #don't need to check the individual bytes in the - #string. - return - - if not type(field_val) in [list, tuple]: - raise SerializationError('field %s must be a list or tuple type'%field_name) - for v in field_val: - check_type(field_name+"[]", base_type, v) - else: - if isinstance(field_val, Message): - # roslib/Header is the old location of Header. We check it for backwards compat - if field_val._type in ['std_msgs/Header', 'roslib/Header']: - if field_type not in ['Header', 'std_msgs/Header', 'roslib/Header']: - raise SerializationError("field %s must be a Header instead of a %s"%(field_name, field_val._type)) - elif field_val._type != field_type: - raise SerializationError("field %s must be of type %s instead of %s"%(field_name, field_type, field_val._type)) - for n, t in zip(field_val.__slots__, field_val._get_types()): - check_type("%s.%s"%(field_name,n), t, getattr(field_val, n)) - else: - raise SerializationError("field %s must be of type [%s]"%(field_name, field_type)) - - #TODO: dynamically load message class and do instance compare - -class Message(object): - """Base class of Message data classes auto-generated from msg files. """ - - # slots is explicitly both for data representation and - # performance. Higher-level code assumes that there is a 1-to-1 - # mapping between __slots__ and message fields. In terms of - # performance, explicitly settings slots eliminates dictionary for - # new-style object. - __slots__ = ['_connection_header'] - - def __init__(self, *args, **kwds): - """ - Create a new Message instance. There are multiple ways of - initializing Message instances, either using a 1-to-1 - correspondence between constructor arguments and message - fields (*args), or using Python "keyword" arguments (**kwds) to initialize named field - and leave the rest with default values. - """ - if args and kwds: - raise TypeError("Message constructor may only use args OR keywords, not both") - if args: - if len(args) != len(self.__slots__): - raise TypeError("Invalid number of arguments, args should be %s"%str(self.__slots__)+" args are"+str(args)) - for i, k in enumerate(self.__slots__): - setattr(self, k, args[i]) - else: - # validate kwds - for k,v in kwds.items(): - if not k in self.__slots__: - raise AttributeError("%s is not an attribute of %s"%(k, self.__class__.__name__)) - # iterate through slots so all fields are initialized. - # this is important so that subclasses don't reference an - # uninitialized field and raise an AttributeError. - for k in self.__slots__: - if k in kwds: - setattr(self, k, kwds[k]) - else: - setattr(self, k, None) - - def __getstate__(self): - """ - support for Python pickling - """ - return [getattr(self, x) for x in self.__slots__] - - def __setstate__(self, state): - """ - support for Python pickling - """ - for x, val in zip(self.__slots__, state): - setattr(self, x, val) - - def _get_types(self): - raise Exception("must be overriden") - def _check_types(self, exc=None): - """ - Perform dynamic type-checking of Message fields. This is performance intensive - and is meant for post-error diagnosis - :param exc: underlying exception that gave cause for type check, ``Exception`` - :raises: exc:`genpy.SerializationError` If typecheck fails - """ - for n, t in zip(self.__slots__, self._get_types()): - check_type(n, t, getattr(self, n)) - if exc: # if exc is set and check_type could not diagnose, raise wrapped error - raise SerializationError(str(exc)) - - def serialize(self, buff): - """ - Serialize data into buffer - :param buff: buffer, ``StringIO`` - """ - pass - def deserialize(self, str): - """ - Deserialize data in str into this instance - :param str: serialized data, ``str`` - """ - pass - def __repr__(self): - return strify_message(self) - def __str__(self): - return strify_message(self) - # TODO: unit test - def __eq__(self, other): - if not isinstance(other, self.__class__): - return False - for f in self.__slots__: - try: - v1 = getattr(self, f) - v2 = getattr(other, f) - if type(v1) in (list, tuple) and type(v2) in (list, tuple): - # we treat tuples and lists as equivalent - if tuple(v1) != tuple(v2): - return False - elif not v1 == v2: - return False - except AttributeError: - return False - return True - - -def get_printable_message_args(msg, buff=None, prefix=''): - """ - Get string representation of msg arguments - :param msg: msg message to fill, ``Message`` - :param prefix: field name prefix (for verbose printing), ``str`` - :returns: printable representation of msg args, ``str`` - """ - try: - from cStringIO import StringIO # Python 2.x - python3 = 0 - except ImportError: - from io import BytesIO # Python 3.x - python3 = 1 - - if buff is None: - if python3 == 1: - buff = BytesIO() - else: - buff = StringIO() - for f in msg.__slots__: - if isinstance(getattr(msg, f), Message): - get_printable_message_args(getattr(msg, f), buff=buff, prefix=(prefix+f+'.')) - else: - buff.write(prefix+f+' ') - return buff.getvalue().rstrip() - -def _fill_val(msg, f, v, keys, prefix): - """ - Subroutine of L{_fill_message_args()}. Sets a particular field on a message - :param f: field name, ``str`` - :param v: field value - :param keys: keys to use as substitute values for messages and timestamps, ``dict`` - :raises: exc:`MessageException` - """ - if not f in msg.__slots__: - raise MessageException("No field name [%s%s]"%(prefix, f)) - def_val = getattr(msg, f) - if isinstance(def_val, Message) or isinstance(def_val, TVal): - # check for substitution key, e.g. 'now' - if type(v) == str: - if v in keys: - setattr(msg, f, keys[v]) - else: - raise MessageException("No key named [%s]"%(v)) - elif isinstance(def_val, TVal) and type(v) in (int, long): - #special case to handle time value represented as a single number - #TODO: this is a lossy conversion - if isinstance(def_val, Time): - setattr(msg, f, Time.from_sec(v/1e9)) - elif isinstance(def_val, Duration): - setattr(msg, f, Duration.from_sec(v/1e9)) - else: - raise MessageException("Cannot create time values of type [%s]"%(type(def_val))) - else: - _fill_message_args(def_val, v, keys, prefix=(prefix+f+'.')) - elif type(def_val) == list: - if not type(v) in [list, tuple]: - raise MessageException("Field [%s%s] must be a list or tuple instead of: %s"%(prefix, f, type(v).__name__)) - # determine base_type of field by looking at _slot_types - idx = msg.__slots__.index(f) - t = msg._slot_types[idx] - base_type, is_array, length = genmsg.msgs.parse_type(t) - # - for primitives, we just directly set (we don't - # type-check. we rely on serialization type checker) - if base_type in genmsg.msgs.PRIMITIVE_TYPES: - # 3785 - if length is not None and len(v) != length: - raise MessageException("Field [%s%s] has incorrect number of elements: %s != %s"%(prefix, f, len(v), length)) - setattr(msg, f, v) - - # - for complex types, we have to iteratively append to def_val - else: - # 3785 - if length is not None and len(v) != length: - raise MessageException("Field [%s%s] has incorrect number of elements: %s != %s"%(prefix, f, len(v), length)) - list_msg_class = get_message_class(base_type) - if list_msg_class is None: - raise MessageException("Cannot instantiate messages for field [%s%s] : cannot load class %s"%(prefix, f, base_type)) - del def_val[:] - for el in v: - inner_msg = list_msg_class() - if isinstance(inner_msg, TVal) and type(el) in (int, long): - #special case to handle time value represented as a single number - #TODO: this is a lossy conversion - if isinstance(inner_msg, Time): - inner_msg = Time.from_sec(el/1e9) - elif isinstance(inner_msg, Duration): - inner_msg = Duration.from_sec(el/1e9) - else: - raise MessageException("Cannot create time values of type [%s]"%(type(inner_msg))) - else: - _fill_message_args(inner_msg, el, keys, prefix) - def_val.append(inner_msg) - else: - setattr(msg, f, v) - - -def _fill_message_args(msg, msg_args, keys, prefix=''): - """ - Populate message with specified args. - - :param msg: message to fill, ``Message`` - :param msg_args: list of arguments to set fields to, ``[args]`` - :param keys: keys to use as substitute values for messages and timestamps. ``dict`` - :param prefix: field name prefix (for verbose printing), ``str`` - :returns: unused/leftover message arguments. ``[args]`` - :raise :exc:`MessageException` If not enough message arguments to fill message - :raises: :exc:`ValueError` If msg or msg_args is not of correct type - """ - if not isinstance(msg, (Message, TVal)): - raise ValueError("msg must be a Message instance: %s"%msg) - - if type(msg_args) == dict: - - #print "DICT ARGS", msg_args - #print "ACTIVE SLOTS",msg.__slots__ - - for f, v in msg_args.items(): - # assume that an empty key is actually an empty string - if v == None: - v = '' - _fill_val(msg, f, v, keys, prefix) - elif type(msg_args) == list: - - #print "LIST ARGS", msg_args - #print "ACTIVE SLOTS",msg.__slots__ - - if len(msg_args) > len(msg.__slots__): - raise MessageException("Too many arguments:\n * Given: %s\n * Expected: %s"%(msg_args, msg.__slots__)) - elif len(msg_args) < len(msg.__slots__): - raise MessageException("Not enough arguments:\n * Given: %s\n * Expected: %s"%(msg_args, msg.__slots__)) - - for f, v in zip(msg.__slots__, msg_args): - _fill_val(msg, f, v, keys, prefix) - else: - raise ValueError("invalid msg_args type: %s"%str(msg_args)) - -def fill_message_args(msg, msg_args, keys={}): - """ - Populate message with specified args. Args are assumed to be a - list of arguments from a command-line YAML parser. See - http://www.ros.org/wiki/ROS/YAMLCommandLine for specification on - how messages are filled. - - fill_message_args also takes in an optional 'keys' dictionary - which contain substitute values for message and time types. These - values must be of the correct instance type, i.e. a Message, Time, - or Duration. In a string key is encountered with these types, the - value from the keys dictionary will be used instead. This is - mainly used to provide values for the 'now' timestamp. - - :param msg: message to fill, ``Message`` - :param msg_args: list of arguments to set fields to, or - If None, msg_args will be made an empty list., ``[args]`` - :param keys: keys to use as substitute values for messages and timestamps, ``dict`` - :raises: :exc:`MessageException` If not enough/too many message arguments to fill message - """ - # a list of arguments is similar to python's - # *args, whereas dictionaries are like **kwds. - - # empty messages serialize as a None, which we make equivalent to - # an empty message - if msg_args is None: - msg_args = [] - - # msg_args is always a list, due to the fact it is parsed from a - # command-line argument list. We have to special-case handle a - # list with a single dictionary, which has precedence over the - # general list representation. We offer this precedence as there - # is no other way to do kwd assignments into the outer message. - if len(msg_args) == 1 and type(msg_args[0]) == dict: - # according to spec, if we only get one msg_arg and it's a dictionary, we - # use it directly - _fill_message_args(msg, msg_args[0], keys, '') - else: - _fill_message_args(msg, msg_args, keys, '') - -def _get_message_or_service_class(type_str, message_type, reload_on_error=False): - """ - Utility for retrieving message/service class instances. Used by - get_message_class and get_service_class. - :param type_str: 'msg' or 'srv', ``str`` - :param message_type: type name of message/service, ``str`` - :returns: Message/Service for message/service type or None, ``class`` - :raises: :exc:`ValueError` If message_type is invalidly specified - """ - if message_type == 'time': - return Time - if message_type == 'duration': - return Duration - ## parse package and local type name for import - package, base_type = genmsg.package_resource_name(message_type) - if not package: - if base_type == 'Header': - package = 'std_msgs' - else: - raise ValueError("message type is missing package name: %s"%str(message_type)) - pypkg = val = None - try: - # import the package - pypkg = __import__('%s.%s' % (package, type_str)) - except ImportError: - # try importing from dry package if available - try: - from roslib import load_manifest - from rospkg import ResourceNotFound - try: - load_manifest(package) - try: - pypkg = __import__('%s.%s' % (package, type_str)) - except ImportError: - pass - except ResourceNotFound: - pass - except ImportError: - pass - if pypkg: - try: - val = getattr(getattr(pypkg, type_str), base_type) - except AttributeError: - pass - - # this logic is mainly to support rosh, so that a user doesn't - # have to exit a shell just because a message wasn't built yet - if val is None and reload_on_error: - try: - if pypkg: - reload(pypkg) - val = getattr(getattr(pypkg, type_str), base_type) - except: - val = None - return val - -## cache for get_message_class -_message_class_cache = {} - -def get_message_class(message_type, reload_on_error=False): - """ - Get the message class. NOTE: this function maintains a - local cache of results to improve performance. - :param message_type: type name of message, ``str`` - :param reload_on_error: (optional). Attempt to reload the Python - module if unable to load message the first time. Defaults to - False. This is necessary if messages are built after the first load. - :returns: Message class for message/service type, ``Message class`` - :raises :exc:`ValueError`: if message_type is invalidly specified - """ - if message_type in _message_class_cache: - return _message_class_cache[message_type] - cls = _get_message_or_service_class('msg', message_type, reload_on_error=reload_on_error) - if cls: - _message_class_cache[message_type] = cls - return cls - -## cache for get_service_class -_service_class_cache = {} - -def get_service_class(service_type, reload_on_error=False): - """ - Get the service class. NOTE: this function maintains a - local cache of results to improve performance. - :param service_type: type name of service, ``str`` - :param reload_on_error: (optional). Attempt to reload the Python - module if unable to load message the first time. Defaults to - False. This is necessary if messages are built after the first load. - :returns: Service class for service type, ``Service class`` - :raises :exc:`Exception` If service_type is invalidly specified - """ - if service_type in _service_class_cache: - return _service_class_cache[service_type] - cls = _get_message_or_service_class('srv', service_type, reload_on_error=reload_on_error) - _service_class_cache[service_type] = cls - return cls - diff --git a/firos/include/genpy/msg/_TestFillEmbedTime.py b/firos/include/genpy/msg/_TestFillEmbedTime.py deleted file mode 100644 index b1c17ca..0000000 --- a/firos/include/genpy/msg/_TestFillEmbedTime.py +++ /dev/null @@ -1,232 +0,0 @@ -"""autogenerated by genpy from genpy/TestFillEmbedTime.msg. Do not edit.""" -import sys -python3 = True if sys.hexversion > 0x03000000 else False -import genpy -import struct - -import genpy -import genpy.msg - -class TestFillEmbedTime(genpy.Message): - _md5sum = "90e08039be001a899b8c20e680c289b0" - _type = "genpy/TestFillEmbedTime" - _has_header = False #flag to mark the presence of a Header object - _full_text = """time t -duration d -genpy/TestString str_msg -genpy/TestString[] str_msg_array -int32 i32 -================================================================================ -MSG: genpy/TestString -string data - -""" - __slots__ = ['t','d','str_msg','str_msg_array','i32'] - _slot_types = ['time','duration','genpy/TestString','genpy/TestString[]','int32'] - - def __init__(self, *args, **kwds): - """ - Constructor. Any message fields that are implicitly/explicitly - set to None will be assigned a default value. The recommend - use is keyword arguments as this is more robust to future message - changes. You cannot mix in-order arguments and keyword arguments. - - The available fields are: - t,d,str_msg,str_msg_array,i32 - - :param args: complete set of field values, in .msg order - :param kwds: use keyword arguments corresponding to message field names - to set specific fields. - """ - if args or kwds: - super(TestFillEmbedTime, self).__init__(*args, **kwds) - #message fields cannot be None, assign default values for those that are - if self.t is None: - self.t = genpy.Time() - if self.d is None: - self.d = genpy.Duration() - if self.str_msg is None: - self.str_msg = genpy.msg.TestString() - if self.str_msg_array is None: - self.str_msg_array = [] - if self.i32 is None: - self.i32 = 0 - else: - self.t = genpy.Time() - self.d = genpy.Duration() - self.str_msg = genpy.msg.TestString() - self.str_msg_array = [] - self.i32 = 0 - - def _get_types(self): - """ - internal API method - """ - return self._slot_types - - def serialize(self, buff): - """ - serialize message into buffer - :param buff: buffer, ``StringIO`` - """ - try: - _x = self - buff.write(_struct_2I2i.pack(_x.t.secs, _x.t.nsecs, _x.d.secs, _x.d.nsecs)) - _x = self.str_msg.data - length = len(_x) - if python3 or type(_x) == unicode: - _x = _x.encode('utf-8') - length = len(_x) - buff.write(struct.pack(' 0x03000000 else False -import genpy -import struct - - -class TestFillSimple(genpy.Message): - _md5sum = "da04a60d03fa22f7d301f9bd5f9a08ab" - _type = "genpy/TestFillSimple" - _has_header = False #flag to mark the presence of a Header object - _full_text = """int32 i32 -string str -int32[] i32_array -bool b -""" - __slots__ = ['i32','str','i32_array','b'] - _slot_types = ['int32','string','int32[]','bool'] - - def __init__(self, *args, **kwds): - """ - Constructor. Any message fields that are implicitly/explicitly - set to None will be assigned a default value. The recommend - use is keyword arguments as this is more robust to future message - changes. You cannot mix in-order arguments and keyword arguments. - - The available fields are: - i32,str,i32_array,b - - :param args: complete set of field values, in .msg order - :param kwds: use keyword arguments corresponding to message field names - to set specific fields. - """ - if args or kwds: - super(TestFillSimple, self).__init__(*args, **kwds) - #message fields cannot be None, assign default values for those that are - if self.i32 is None: - self.i32 = 0 - if self.str is None: - self.str = '' - if self.i32_array is None: - self.i32_array = [] - if self.b is None: - self.b = False - else: - self.i32 = 0 - self.str = '' - self.i32_array = [] - self.b = False - - def _get_types(self): - """ - internal API method - """ - return self._slot_types - - def serialize(self, buff): - """ - serialize message into buffer - :param buff: buffer, ``StringIO`` - """ - try: - buff.write(_struct_i.pack(self.i32)) - _x = self.str - length = len(_x) - if python3 or type(_x) == unicode: - _x = _x.encode('utf-8') - length = len(_x) - buff.write(struct.pack(' 0x03000000 else False -import genpy -import struct - - -class TestManyFields(genpy.Message): - _md5sum = "e95ce9e480ec14cc0488f63b5e806d93" - _type = "genpy/TestManyFields" - _has_header = False #flag to mark the presence of a Header object - _full_text = """int32 v1 -int32 v2 -int32 v3 -int32 v4 -int32 v5 -int32 v6 -int32 v7 -int32 v8 -int32 v9 -int32 v10 -int32 v11 -int32 v12 -int32 v13 -int32 v14 -int32 v15 -int32 v16 -int32 v17 -int32 v18 -int32 v19 -int32 v20 -int32 v21 -int32 v22 -int32 v23 -int32 v24 -int32 v25 -int32 v26 -int32 v27 -int32 v28 -int32 v29 -int32 v30 -int32 v31 -int32 v32 -int32 v33 -int32 v34 -int32 v35 -int32 v36 -int32 v37 -int32 v38 -int32 v39 -int32 v40 -int32 v41 -int32 v42 -int32 v43 -int32 v44 -int32 v45 -int32 v46 -int32 v47 -int32 v48 -int32 v49 -int32 v50 -int32 v51 -int32 v52 -int32 v53 -int32 v54 -int32 v55 -int32 v56 -int32 v57 -int32 v58 -int32 v59 -int32 v60 -int32 v61 -int32 v62 -int32 v63 -int32 v64 -int32 v65 -int32 v66 -int32 v67 -int32 v68 -int32 v69 -int32 v70 -int32 v71 -int32 v72 -int32 v73 -int32 v74 -int32 v75 -int32 v76 -int32 v77 -int32 v78 -int32 v79 -int32 v80 -int32 v81 -int32 v82 -int32 v83 -int32 v84 -int32 v85 -int32 v86 -int32 v87 -int32 v88 -int32 v89 -int32 v90 -int32 v91 -int32 v92 -int32 v93 -int32 v94 -int32 v95 -int32 v96 -int32 v97 -int32 v98 -int32 v99 -int32 v100 -int32 v101 -int32 v102 -int32 v103 -int32 v104 -int32 v105 -int32 v106 -int32 v107 -int32 v108 -int32 v109 -int32 v110 -int32 v111 -int32 v112 -int32 v113 -int32 v114 -int32 v115 -int32 v116 -int32 v117 -int32 v118 -int32 v119 -int32 v120 -int32 v121 -int32 v122 -int32 v123 -int32 v124 -int32 v125 -int32 v126 -int32 v127 -int32 v128 -int32 v129 -int32 v130 -int32 v131 -int32 v132 -int32 v133 -int32 v134 -int32 v135 -int32 v136 -int32 v137 -int32 v138 -int32 v139 -int32 v140 -int32 v141 -int32 v142 -int32 v143 -int32 v144 -int32 v145 -int32 v146 -int32 v147 -int32 v148 -int32 v149 -int32 v150 -int32 v151 -int32 v152 -int32 v153 -int32 v154 -int32 v155 -int32 v156 -int32 v157 -int32 v158 -int32 v159 -int32 v160 -int32 v161 -int32 v162 -int32 v163 -int32 v164 -int32 v165 -int32 v166 -int32 v167 -int32 v168 -int32 v169 -int32 v170 -int32 v171 -int32 v172 -int32 v173 -int32 v174 -int32 v175 -int32 v176 -int32 v177 -int32 v178 -int32 v179 -int32 v180 -int32 v181 -int32 v182 -int32 v183 -int32 v184 -int32 v185 -int32 v186 -int32 v187 -int32 v188 -int32 v189 -int32 v190 -int32 v191 -int32 v192 -int32 v193 -int32 v194 -int32 v195 -int32 v196 -int32 v197 -int32 v198 -int32 v199 -int32 v200 -int32 v201 -int32 v202 -int32 v203 -int32 v204 -int32 v205 -int32 v206 -int32 v207 -int32 v208 -int32 v209 -int32 v210 -int32 v211 -int32 v212 -int32 v213 -int32 v214 -int32 v215 -int32 v216 -int32 v217 -int32 v218 -int32 v219 -int32 v220 -int32 v221 -int32 v222 -int32 v223 -int32 v224 -int32 v225 -int32 v226 -int32 v227 -int32 v228 -int32 v229 -int32 v230 -int32 v231 -int32 v232 -int32 v233 -int32 v234 -int32 v235 -int32 v236 -int32 v237 -int32 v238 -int32 v239 -int32 v240 -int32 v241 -int32 v242 -int32 v243 -int32 v244 -int32 v245 -int32 v246 -int32 v247 -int32 v248 -int32 v249 -int32 v250 -int32 v251 -int32 v252 -int32 v253 -int32 v254 -int32 v255 -int32 v256 - -""" - __slots__ = ['v1','v2','v3','v4','v5','v6','v7','v8','v9','v10','v11','v12','v13','v14','v15','v16','v17','v18','v19','v20','v21','v22','v23','v24','v25','v26','v27','v28','v29','v30','v31','v32','v33','v34','v35','v36','v37','v38','v39','v40','v41','v42','v43','v44','v45','v46','v47','v48','v49','v50','v51','v52','v53','v54','v55','v56','v57','v58','v59','v60','v61','v62','v63','v64','v65','v66','v67','v68','v69','v70','v71','v72','v73','v74','v75','v76','v77','v78','v79','v80','v81','v82','v83','v84','v85','v86','v87','v88','v89','v90','v91','v92','v93','v94','v95','v96','v97','v98','v99','v100','v101','v102','v103','v104','v105','v106','v107','v108','v109','v110','v111','v112','v113','v114','v115','v116','v117','v118','v119','v120','v121','v122','v123','v124','v125','v126','v127','v128','v129','v130','v131','v132','v133','v134','v135','v136','v137','v138','v139','v140','v141','v142','v143','v144','v145','v146','v147','v148','v149','v150','v151','v152','v153','v154','v155','v156','v157','v158','v159','v160','v161','v162','v163','v164','v165','v166','v167','v168','v169','v170','v171','v172','v173','v174','v175','v176','v177','v178','v179','v180','v181','v182','v183','v184','v185','v186','v187','v188','v189','v190','v191','v192','v193','v194','v195','v196','v197','v198','v199','v200','v201','v202','v203','v204','v205','v206','v207','v208','v209','v210','v211','v212','v213','v214','v215','v216','v217','v218','v219','v220','v221','v222','v223','v224','v225','v226','v227','v228','v229','v230','v231','v232','v233','v234','v235','v236','v237','v238','v239','v240','v241','v242','v243','v244','v245','v246','v247','v248','v249','v250','v251','v252','v253','v254','v255','v256'] - _slot_types = ['int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32','int32'] - - def __init__(self, *args, **kwds): - """ - Constructor. Any message fields that are implicitly/explicitly - set to None will be assigned a default value. The recommend - use is keyword arguments as this is more robust to future message - changes. You cannot mix in-order arguments and keyword arguments. - - The available fields are: - v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25,v26,v27,v28,v29,v30,v31,v32,v33,v34,v35,v36,v37,v38,v39,v40,v41,v42,v43,v44,v45,v46,v47,v48,v49,v50,v51,v52,v53,v54,v55,v56,v57,v58,v59,v60,v61,v62,v63,v64,v65,v66,v67,v68,v69,v70,v71,v72,v73,v74,v75,v76,v77,v78,v79,v80,v81,v82,v83,v84,v85,v86,v87,v88,v89,v90,v91,v92,v93,v94,v95,v96,v97,v98,v99,v100,v101,v102,v103,v104,v105,v106,v107,v108,v109,v110,v111,v112,v113,v114,v115,v116,v117,v118,v119,v120,v121,v122,v123,v124,v125,v126,v127,v128,v129,v130,v131,v132,v133,v134,v135,v136,v137,v138,v139,v140,v141,v142,v143,v144,v145,v146,v147,v148,v149,v150,v151,v152,v153,v154,v155,v156,v157,v158,v159,v160,v161,v162,v163,v164,v165,v166,v167,v168,v169,v170,v171,v172,v173,v174,v175,v176,v177,v178,v179,v180,v181,v182,v183,v184,v185,v186,v187,v188,v189,v190,v191,v192,v193,v194,v195,v196,v197,v198,v199,v200,v201,v202,v203,v204,v205,v206,v207,v208,v209,v210,v211,v212,v213,v214,v215,v216,v217,v218,v219,v220,v221,v222,v223,v224,v225,v226,v227,v228,v229,v230,v231,v232,v233,v234,v235,v236,v237,v238,v239,v240,v241,v242,v243,v244,v245,v246,v247,v248,v249,v250,v251,v252,v253,v254,v255,v256 - - :param args: complete set of field values, in .msg order - :param kwds: use keyword arguments corresponding to message field names - to set specific fields. - """ - if args or kwds: - super(TestManyFields, self).__init__(*args, **kwds) - #message fields cannot be None, assign default values for those that are - if self.v1 is None: - self.v1 = 0 - if self.v2 is None: - self.v2 = 0 - if self.v3 is None: - self.v3 = 0 - if self.v4 is None: - self.v4 = 0 - if self.v5 is None: - self.v5 = 0 - if self.v6 is None: - self.v6 = 0 - if self.v7 is None: - self.v7 = 0 - if self.v8 is None: - self.v8 = 0 - if self.v9 is None: - self.v9 = 0 - if self.v10 is None: - self.v10 = 0 - if self.v11 is None: - self.v11 = 0 - if self.v12 is None: - self.v12 = 0 - if self.v13 is None: - self.v13 = 0 - if self.v14 is None: - self.v14 = 0 - if self.v15 is None: - self.v15 = 0 - if self.v16 is None: - self.v16 = 0 - if self.v17 is None: - self.v17 = 0 - if self.v18 is None: - self.v18 = 0 - if self.v19 is None: - self.v19 = 0 - if self.v20 is None: - self.v20 = 0 - if self.v21 is None: - self.v21 = 0 - if self.v22 is None: - self.v22 = 0 - if self.v23 is None: - self.v23 = 0 - if self.v24 is None: - self.v24 = 0 - if self.v25 is None: - self.v25 = 0 - if self.v26 is None: - self.v26 = 0 - if self.v27 is None: - self.v27 = 0 - if self.v28 is None: - self.v28 = 0 - if self.v29 is None: - self.v29 = 0 - if self.v30 is None: - self.v30 = 0 - if self.v31 is None: - self.v31 = 0 - if self.v32 is None: - self.v32 = 0 - if self.v33 is None: - self.v33 = 0 - if self.v34 is None: - self.v34 = 0 - if self.v35 is None: - self.v35 = 0 - if self.v36 is None: - self.v36 = 0 - if self.v37 is None: - self.v37 = 0 - if self.v38 is None: - self.v38 = 0 - if self.v39 is None: - self.v39 = 0 - if self.v40 is None: - self.v40 = 0 - if self.v41 is None: - self.v41 = 0 - if self.v42 is None: - self.v42 = 0 - if self.v43 is None: - self.v43 = 0 - if self.v44 is None: - self.v44 = 0 - if self.v45 is None: - self.v45 = 0 - if self.v46 is None: - self.v46 = 0 - if self.v47 is None: - self.v47 = 0 - if self.v48 is None: - self.v48 = 0 - if self.v49 is None: - self.v49 = 0 - if self.v50 is None: - self.v50 = 0 - if self.v51 is None: - self.v51 = 0 - if self.v52 is None: - self.v52 = 0 - if self.v53 is None: - self.v53 = 0 - if self.v54 is None: - self.v54 = 0 - if self.v55 is None: - self.v55 = 0 - if self.v56 is None: - self.v56 = 0 - if self.v57 is None: - self.v57 = 0 - if self.v58 is None: - self.v58 = 0 - if self.v59 is None: - self.v59 = 0 - if self.v60 is None: - self.v60 = 0 - if self.v61 is None: - self.v61 = 0 - if self.v62 is None: - self.v62 = 0 - if self.v63 is None: - self.v63 = 0 - if self.v64 is None: - self.v64 = 0 - if self.v65 is None: - self.v65 = 0 - if self.v66 is None: - self.v66 = 0 - if self.v67 is None: - self.v67 = 0 - if self.v68 is None: - self.v68 = 0 - if self.v69 is None: - self.v69 = 0 - if self.v70 is None: - self.v70 = 0 - if self.v71 is None: - self.v71 = 0 - if self.v72 is None: - self.v72 = 0 - if self.v73 is None: - self.v73 = 0 - if self.v74 is None: - self.v74 = 0 - if self.v75 is None: - self.v75 = 0 - if self.v76 is None: - self.v76 = 0 - if self.v77 is None: - self.v77 = 0 - if self.v78 is None: - self.v78 = 0 - if self.v79 is None: - self.v79 = 0 - if self.v80 is None: - self.v80 = 0 - if self.v81 is None: - self.v81 = 0 - if self.v82 is None: - self.v82 = 0 - if self.v83 is None: - self.v83 = 0 - if self.v84 is None: - self.v84 = 0 - if self.v85 is None: - self.v85 = 0 - if self.v86 is None: - self.v86 = 0 - if self.v87 is None: - self.v87 = 0 - if self.v88 is None: - self.v88 = 0 - if self.v89 is None: - self.v89 = 0 - if self.v90 is None: - self.v90 = 0 - if self.v91 is None: - self.v91 = 0 - if self.v92 is None: - self.v92 = 0 - if self.v93 is None: - self.v93 = 0 - if self.v94 is None: - self.v94 = 0 - if self.v95 is None: - self.v95 = 0 - if self.v96 is None: - self.v96 = 0 - if self.v97 is None: - self.v97 = 0 - if self.v98 is None: - self.v98 = 0 - if self.v99 is None: - self.v99 = 0 - if self.v100 is None: - self.v100 = 0 - if self.v101 is None: - self.v101 = 0 - if self.v102 is None: - self.v102 = 0 - if self.v103 is None: - self.v103 = 0 - if self.v104 is None: - self.v104 = 0 - if self.v105 is None: - self.v105 = 0 - if self.v106 is None: - self.v106 = 0 - if self.v107 is None: - self.v107 = 0 - if self.v108 is None: - self.v108 = 0 - if self.v109 is None: - self.v109 = 0 - if self.v110 is None: - self.v110 = 0 - if self.v111 is None: - self.v111 = 0 - if self.v112 is None: - self.v112 = 0 - if self.v113 is None: - self.v113 = 0 - if self.v114 is None: - self.v114 = 0 - if self.v115 is None: - self.v115 = 0 - if self.v116 is None: - self.v116 = 0 - if self.v117 is None: - self.v117 = 0 - if self.v118 is None: - self.v118 = 0 - if self.v119 is None: - self.v119 = 0 - if self.v120 is None: - self.v120 = 0 - if self.v121 is None: - self.v121 = 0 - if self.v122 is None: - self.v122 = 0 - if self.v123 is None: - self.v123 = 0 - if self.v124 is None: - self.v124 = 0 - if self.v125 is None: - self.v125 = 0 - if self.v126 is None: - self.v126 = 0 - if self.v127 is None: - self.v127 = 0 - if self.v128 is None: - self.v128 = 0 - if self.v129 is None: - self.v129 = 0 - if self.v130 is None: - self.v130 = 0 - if self.v131 is None: - self.v131 = 0 - if self.v132 is None: - self.v132 = 0 - if self.v133 is None: - self.v133 = 0 - if self.v134 is None: - self.v134 = 0 - if self.v135 is None: - self.v135 = 0 - if self.v136 is None: - self.v136 = 0 - if self.v137 is None: - self.v137 = 0 - if self.v138 is None: - self.v138 = 0 - if self.v139 is None: - self.v139 = 0 - if self.v140 is None: - self.v140 = 0 - if self.v141 is None: - self.v141 = 0 - if self.v142 is None: - self.v142 = 0 - if self.v143 is None: - self.v143 = 0 - if self.v144 is None: - self.v144 = 0 - if self.v145 is None: - self.v145 = 0 - if self.v146 is None: - self.v146 = 0 - if self.v147 is None: - self.v147 = 0 - if self.v148 is None: - self.v148 = 0 - if self.v149 is None: - self.v149 = 0 - if self.v150 is None: - self.v150 = 0 - if self.v151 is None: - self.v151 = 0 - if self.v152 is None: - self.v152 = 0 - if self.v153 is None: - self.v153 = 0 - if self.v154 is None: - self.v154 = 0 - if self.v155 is None: - self.v155 = 0 - if self.v156 is None: - self.v156 = 0 - if self.v157 is None: - self.v157 = 0 - if self.v158 is None: - self.v158 = 0 - if self.v159 is None: - self.v159 = 0 - if self.v160 is None: - self.v160 = 0 - if self.v161 is None: - self.v161 = 0 - if self.v162 is None: - self.v162 = 0 - if self.v163 is None: - self.v163 = 0 - if self.v164 is None: - self.v164 = 0 - if self.v165 is None: - self.v165 = 0 - if self.v166 is None: - self.v166 = 0 - if self.v167 is None: - self.v167 = 0 - if self.v168 is None: - self.v168 = 0 - if self.v169 is None: - self.v169 = 0 - if self.v170 is None: - self.v170 = 0 - if self.v171 is None: - self.v171 = 0 - if self.v172 is None: - self.v172 = 0 - if self.v173 is None: - self.v173 = 0 - if self.v174 is None: - self.v174 = 0 - if self.v175 is None: - self.v175 = 0 - if self.v176 is None: - self.v176 = 0 - if self.v177 is None: - self.v177 = 0 - if self.v178 is None: - self.v178 = 0 - if self.v179 is None: - self.v179 = 0 - if self.v180 is None: - self.v180 = 0 - if self.v181 is None: - self.v181 = 0 - if self.v182 is None: - self.v182 = 0 - if self.v183 is None: - self.v183 = 0 - if self.v184 is None: - self.v184 = 0 - if self.v185 is None: - self.v185 = 0 - if self.v186 is None: - self.v186 = 0 - if self.v187 is None: - self.v187 = 0 - if self.v188 is None: - self.v188 = 0 - if self.v189 is None: - self.v189 = 0 - if self.v190 is None: - self.v190 = 0 - if self.v191 is None: - self.v191 = 0 - if self.v192 is None: - self.v192 = 0 - if self.v193 is None: - self.v193 = 0 - if self.v194 is None: - self.v194 = 0 - if self.v195 is None: - self.v195 = 0 - if self.v196 is None: - self.v196 = 0 - if self.v197 is None: - self.v197 = 0 - if self.v198 is None: - self.v198 = 0 - if self.v199 is None: - self.v199 = 0 - if self.v200 is None: - self.v200 = 0 - if self.v201 is None: - self.v201 = 0 - if self.v202 is None: - self.v202 = 0 - if self.v203 is None: - self.v203 = 0 - if self.v204 is None: - self.v204 = 0 - if self.v205 is None: - self.v205 = 0 - if self.v206 is None: - self.v206 = 0 - if self.v207 is None: - self.v207 = 0 - if self.v208 is None: - self.v208 = 0 - if self.v209 is None: - self.v209 = 0 - if self.v210 is None: - self.v210 = 0 - if self.v211 is None: - self.v211 = 0 - if self.v212 is None: - self.v212 = 0 - if self.v213 is None: - self.v213 = 0 - if self.v214 is None: - self.v214 = 0 - if self.v215 is None: - self.v215 = 0 - if self.v216 is None: - self.v216 = 0 - if self.v217 is None: - self.v217 = 0 - if self.v218 is None: - self.v218 = 0 - if self.v219 is None: - self.v219 = 0 - if self.v220 is None: - self.v220 = 0 - if self.v221 is None: - self.v221 = 0 - if self.v222 is None: - self.v222 = 0 - if self.v223 is None: - self.v223 = 0 - if self.v224 is None: - self.v224 = 0 - if self.v225 is None: - self.v225 = 0 - if self.v226 is None: - self.v226 = 0 - if self.v227 is None: - self.v227 = 0 - if self.v228 is None: - self.v228 = 0 - if self.v229 is None: - self.v229 = 0 - if self.v230 is None: - self.v230 = 0 - if self.v231 is None: - self.v231 = 0 - if self.v232 is None: - self.v232 = 0 - if self.v233 is None: - self.v233 = 0 - if self.v234 is None: - self.v234 = 0 - if self.v235 is None: - self.v235 = 0 - if self.v236 is None: - self.v236 = 0 - if self.v237 is None: - self.v237 = 0 - if self.v238 is None: - self.v238 = 0 - if self.v239 is None: - self.v239 = 0 - if self.v240 is None: - self.v240 = 0 - if self.v241 is None: - self.v241 = 0 - if self.v242 is None: - self.v242 = 0 - if self.v243 is None: - self.v243 = 0 - if self.v244 is None: - self.v244 = 0 - if self.v245 is None: - self.v245 = 0 - if self.v246 is None: - self.v246 = 0 - if self.v247 is None: - self.v247 = 0 - if self.v248 is None: - self.v248 = 0 - if self.v249 is None: - self.v249 = 0 - if self.v250 is None: - self.v250 = 0 - if self.v251 is None: - self.v251 = 0 - if self.v252 is None: - self.v252 = 0 - if self.v253 is None: - self.v253 = 0 - if self.v254 is None: - self.v254 = 0 - if self.v255 is None: - self.v255 = 0 - if self.v256 is None: - self.v256 = 0 - else: - self.v1 = 0 - self.v2 = 0 - self.v3 = 0 - self.v4 = 0 - self.v5 = 0 - self.v6 = 0 - self.v7 = 0 - self.v8 = 0 - self.v9 = 0 - self.v10 = 0 - self.v11 = 0 - self.v12 = 0 - self.v13 = 0 - self.v14 = 0 - self.v15 = 0 - self.v16 = 0 - self.v17 = 0 - self.v18 = 0 - self.v19 = 0 - self.v20 = 0 - self.v21 = 0 - self.v22 = 0 - self.v23 = 0 - self.v24 = 0 - self.v25 = 0 - self.v26 = 0 - self.v27 = 0 - self.v28 = 0 - self.v29 = 0 - self.v30 = 0 - self.v31 = 0 - self.v32 = 0 - self.v33 = 0 - self.v34 = 0 - self.v35 = 0 - self.v36 = 0 - self.v37 = 0 - self.v38 = 0 - self.v39 = 0 - self.v40 = 0 - self.v41 = 0 - self.v42 = 0 - self.v43 = 0 - self.v44 = 0 - self.v45 = 0 - self.v46 = 0 - self.v47 = 0 - self.v48 = 0 - self.v49 = 0 - self.v50 = 0 - self.v51 = 0 - self.v52 = 0 - self.v53 = 0 - self.v54 = 0 - self.v55 = 0 - self.v56 = 0 - self.v57 = 0 - self.v58 = 0 - self.v59 = 0 - self.v60 = 0 - self.v61 = 0 - self.v62 = 0 - self.v63 = 0 - self.v64 = 0 - self.v65 = 0 - self.v66 = 0 - self.v67 = 0 - self.v68 = 0 - self.v69 = 0 - self.v70 = 0 - self.v71 = 0 - self.v72 = 0 - self.v73 = 0 - self.v74 = 0 - self.v75 = 0 - self.v76 = 0 - self.v77 = 0 - self.v78 = 0 - self.v79 = 0 - self.v80 = 0 - self.v81 = 0 - self.v82 = 0 - self.v83 = 0 - self.v84 = 0 - self.v85 = 0 - self.v86 = 0 - self.v87 = 0 - self.v88 = 0 - self.v89 = 0 - self.v90 = 0 - self.v91 = 0 - self.v92 = 0 - self.v93 = 0 - self.v94 = 0 - self.v95 = 0 - self.v96 = 0 - self.v97 = 0 - self.v98 = 0 - self.v99 = 0 - self.v100 = 0 - self.v101 = 0 - self.v102 = 0 - self.v103 = 0 - self.v104 = 0 - self.v105 = 0 - self.v106 = 0 - self.v107 = 0 - self.v108 = 0 - self.v109 = 0 - self.v110 = 0 - self.v111 = 0 - self.v112 = 0 - self.v113 = 0 - self.v114 = 0 - self.v115 = 0 - self.v116 = 0 - self.v117 = 0 - self.v118 = 0 - self.v119 = 0 - self.v120 = 0 - self.v121 = 0 - self.v122 = 0 - self.v123 = 0 - self.v124 = 0 - self.v125 = 0 - self.v126 = 0 - self.v127 = 0 - self.v128 = 0 - self.v129 = 0 - self.v130 = 0 - self.v131 = 0 - self.v132 = 0 - self.v133 = 0 - self.v134 = 0 - self.v135 = 0 - self.v136 = 0 - self.v137 = 0 - self.v138 = 0 - self.v139 = 0 - self.v140 = 0 - self.v141 = 0 - self.v142 = 0 - self.v143 = 0 - self.v144 = 0 - self.v145 = 0 - self.v146 = 0 - self.v147 = 0 - self.v148 = 0 - self.v149 = 0 - self.v150 = 0 - self.v151 = 0 - self.v152 = 0 - self.v153 = 0 - self.v154 = 0 - self.v155 = 0 - self.v156 = 0 - self.v157 = 0 - self.v158 = 0 - self.v159 = 0 - self.v160 = 0 - self.v161 = 0 - self.v162 = 0 - self.v163 = 0 - self.v164 = 0 - self.v165 = 0 - self.v166 = 0 - self.v167 = 0 - self.v168 = 0 - self.v169 = 0 - self.v170 = 0 - self.v171 = 0 - self.v172 = 0 - self.v173 = 0 - self.v174 = 0 - self.v175 = 0 - self.v176 = 0 - self.v177 = 0 - self.v178 = 0 - self.v179 = 0 - self.v180 = 0 - self.v181 = 0 - self.v182 = 0 - self.v183 = 0 - self.v184 = 0 - self.v185 = 0 - self.v186 = 0 - self.v187 = 0 - self.v188 = 0 - self.v189 = 0 - self.v190 = 0 - self.v191 = 0 - self.v192 = 0 - self.v193 = 0 - self.v194 = 0 - self.v195 = 0 - self.v196 = 0 - self.v197 = 0 - self.v198 = 0 - self.v199 = 0 - self.v200 = 0 - self.v201 = 0 - self.v202 = 0 - self.v203 = 0 - self.v204 = 0 - self.v205 = 0 - self.v206 = 0 - self.v207 = 0 - self.v208 = 0 - self.v209 = 0 - self.v210 = 0 - self.v211 = 0 - self.v212 = 0 - self.v213 = 0 - self.v214 = 0 - self.v215 = 0 - self.v216 = 0 - self.v217 = 0 - self.v218 = 0 - self.v219 = 0 - self.v220 = 0 - self.v221 = 0 - self.v222 = 0 - self.v223 = 0 - self.v224 = 0 - self.v225 = 0 - self.v226 = 0 - self.v227 = 0 - self.v228 = 0 - self.v229 = 0 - self.v230 = 0 - self.v231 = 0 - self.v232 = 0 - self.v233 = 0 - self.v234 = 0 - self.v235 = 0 - self.v236 = 0 - self.v237 = 0 - self.v238 = 0 - self.v239 = 0 - self.v240 = 0 - self.v241 = 0 - self.v242 = 0 - self.v243 = 0 - self.v244 = 0 - self.v245 = 0 - self.v246 = 0 - self.v247 = 0 - self.v248 = 0 - self.v249 = 0 - self.v250 = 0 - self.v251 = 0 - self.v252 = 0 - self.v253 = 0 - self.v254 = 0 - self.v255 = 0 - self.v256 = 0 - - def _get_types(self): - """ - internal API method - """ - return self._slot_types - - def serialize(self, buff): - """ - serialize message into buffer - :param buff: buffer, ``StringIO`` - """ - try: - _x = self - buff.write(_struct_255i.pack(_x.v1, _x.v2, _x.v3, _x.v4, _x.v5, _x.v6, _x.v7, _x.v8, _x.v9, _x.v10, _x.v11, _x.v12, _x.v13, _x.v14, _x.v15, _x.v16, _x.v17, _x.v18, _x.v19, _x.v20, _x.v21, _x.v22, _x.v23, _x.v24, _x.v25, _x.v26, _x.v27, _x.v28, _x.v29, _x.v30, _x.v31, _x.v32, _x.v33, _x.v34, _x.v35, _x.v36, _x.v37, _x.v38, _x.v39, _x.v40, _x.v41, _x.v42, _x.v43, _x.v44, _x.v45, _x.v46, _x.v47, _x.v48, _x.v49, _x.v50, _x.v51, _x.v52, _x.v53, _x.v54, _x.v55, _x.v56, _x.v57, _x.v58, _x.v59, _x.v60, _x.v61, _x.v62, _x.v63, _x.v64, _x.v65, _x.v66, _x.v67, _x.v68, _x.v69, _x.v70, _x.v71, _x.v72, _x.v73, _x.v74, _x.v75, _x.v76, _x.v77, _x.v78, _x.v79, _x.v80, _x.v81, _x.v82, _x.v83, _x.v84, _x.v85, _x.v86, _x.v87, _x.v88, _x.v89, _x.v90, _x.v91, _x.v92, _x.v93, _x.v94, _x.v95, _x.v96, _x.v97, _x.v98, _x.v99, _x.v100, _x.v101, _x.v102, _x.v103, _x.v104, _x.v105, _x.v106, _x.v107, _x.v108, _x.v109, _x.v110, _x.v111, _x.v112, _x.v113, _x.v114, _x.v115, _x.v116, _x.v117, _x.v118, _x.v119, _x.v120, _x.v121, _x.v122, _x.v123, _x.v124, _x.v125, _x.v126, _x.v127, _x.v128, _x.v129, _x.v130, _x.v131, _x.v132, _x.v133, _x.v134, _x.v135, _x.v136, _x.v137, _x.v138, _x.v139, _x.v140, _x.v141, _x.v142, _x.v143, _x.v144, _x.v145, _x.v146, _x.v147, _x.v148, _x.v149, _x.v150, _x.v151, _x.v152, _x.v153, _x.v154, _x.v155, _x.v156, _x.v157, _x.v158, _x.v159, _x.v160, _x.v161, _x.v162, _x.v163, _x.v164, _x.v165, _x.v166, _x.v167, _x.v168, _x.v169, _x.v170, _x.v171, _x.v172, _x.v173, _x.v174, _x.v175, _x.v176, _x.v177, _x.v178, _x.v179, _x.v180, _x.v181, _x.v182, _x.v183, _x.v184, _x.v185, _x.v186, _x.v187, _x.v188, _x.v189, _x.v190, _x.v191, _x.v192, _x.v193, _x.v194, _x.v195, _x.v196, _x.v197, _x.v198, _x.v199, _x.v200, _x.v201, _x.v202, _x.v203, _x.v204, _x.v205, _x.v206, _x.v207, _x.v208, _x.v209, _x.v210, _x.v211, _x.v212, _x.v213, _x.v214, _x.v215, _x.v216, _x.v217, _x.v218, _x.v219, _x.v220, _x.v221, _x.v222, _x.v223, _x.v224, _x.v225, _x.v226, _x.v227, _x.v228, _x.v229, _x.v230, _x.v231, _x.v232, _x.v233, _x.v234, _x.v235, _x.v236, _x.v237, _x.v238, _x.v239, _x.v240, _x.v241, _x.v242, _x.v243, _x.v244, _x.v245, _x.v246, _x.v247, _x.v248, _x.v249, _x.v250, _x.v251, _x.v252, _x.v253, _x.v254, _x.v255)) - buff.write(_struct_i.pack(self.v256)) - except struct.error as se: self._check_types(se) - except TypeError as te: self._check_types(te) - - def deserialize(self, str): - """ - unpack serialized message in str into this message instance - :param str: byte array of serialized message, ``str`` - """ - try: - end = 0 - _x = self - start = end - end += 1020 - (_x.v1, _x.v2, _x.v3, _x.v4, _x.v5, _x.v6, _x.v7, _x.v8, _x.v9, _x.v10, _x.v11, _x.v12, _x.v13, _x.v14, _x.v15, _x.v16, _x.v17, _x.v18, _x.v19, _x.v20, _x.v21, _x.v22, _x.v23, _x.v24, _x.v25, _x.v26, _x.v27, _x.v28, _x.v29, _x.v30, _x.v31, _x.v32, _x.v33, _x.v34, _x.v35, _x.v36, _x.v37, _x.v38, _x.v39, _x.v40, _x.v41, _x.v42, _x.v43, _x.v44, _x.v45, _x.v46, _x.v47, _x.v48, _x.v49, _x.v50, _x.v51, _x.v52, _x.v53, _x.v54, _x.v55, _x.v56, _x.v57, _x.v58, _x.v59, _x.v60, _x.v61, _x.v62, _x.v63, _x.v64, _x.v65, _x.v66, _x.v67, _x.v68, _x.v69, _x.v70, _x.v71, _x.v72, _x.v73, _x.v74, _x.v75, _x.v76, _x.v77, _x.v78, _x.v79, _x.v80, _x.v81, _x.v82, _x.v83, _x.v84, _x.v85, _x.v86, _x.v87, _x.v88, _x.v89, _x.v90, _x.v91, _x.v92, _x.v93, _x.v94, _x.v95, _x.v96, _x.v97, _x.v98, _x.v99, _x.v100, _x.v101, _x.v102, _x.v103, _x.v104, _x.v105, _x.v106, _x.v107, _x.v108, _x.v109, _x.v110, _x.v111, _x.v112, _x.v113, _x.v114, _x.v115, _x.v116, _x.v117, _x.v118, _x.v119, _x.v120, _x.v121, _x.v122, _x.v123, _x.v124, _x.v125, _x.v126, _x.v127, _x.v128, _x.v129, _x.v130, _x.v131, _x.v132, _x.v133, _x.v134, _x.v135, _x.v136, _x.v137, _x.v138, _x.v139, _x.v140, _x.v141, _x.v142, _x.v143, _x.v144, _x.v145, _x.v146, _x.v147, _x.v148, _x.v149, _x.v150, _x.v151, _x.v152, _x.v153, _x.v154, _x.v155, _x.v156, _x.v157, _x.v158, _x.v159, _x.v160, _x.v161, _x.v162, _x.v163, _x.v164, _x.v165, _x.v166, _x.v167, _x.v168, _x.v169, _x.v170, _x.v171, _x.v172, _x.v173, _x.v174, _x.v175, _x.v176, _x.v177, _x.v178, _x.v179, _x.v180, _x.v181, _x.v182, _x.v183, _x.v184, _x.v185, _x.v186, _x.v187, _x.v188, _x.v189, _x.v190, _x.v191, _x.v192, _x.v193, _x.v194, _x.v195, _x.v196, _x.v197, _x.v198, _x.v199, _x.v200, _x.v201, _x.v202, _x.v203, _x.v204, _x.v205, _x.v206, _x.v207, _x.v208, _x.v209, _x.v210, _x.v211, _x.v212, _x.v213, _x.v214, _x.v215, _x.v216, _x.v217, _x.v218, _x.v219, _x.v220, _x.v221, _x.v222, _x.v223, _x.v224, _x.v225, _x.v226, _x.v227, _x.v228, _x.v229, _x.v230, _x.v231, _x.v232, _x.v233, _x.v234, _x.v235, _x.v236, _x.v237, _x.v238, _x.v239, _x.v240, _x.v241, _x.v242, _x.v243, _x.v244, _x.v245, _x.v246, _x.v247, _x.v248, _x.v249, _x.v250, _x.v251, _x.v252, _x.v253, _x.v254, _x.v255,) = _struct_255i.unpack(str[start:end]) - start = end - end += 4 - (self.v256,) = _struct_i.unpack(str[start:end]) - return self - except struct.error as e: - raise genpy.DeserializationError(e) #most likely buffer underfill - - - def serialize_numpy(self, buff, numpy): - """ - serialize message with numpy array types into buffer - :param buff: buffer, ``StringIO`` - :param numpy: numpy python module - """ - try: - _x = self - buff.write(_struct_255i.pack(_x.v1, _x.v2, _x.v3, _x.v4, _x.v5, _x.v6, _x.v7, _x.v8, _x.v9, _x.v10, _x.v11, _x.v12, _x.v13, _x.v14, _x.v15, _x.v16, _x.v17, _x.v18, _x.v19, _x.v20, _x.v21, _x.v22, _x.v23, _x.v24, _x.v25, _x.v26, _x.v27, _x.v28, _x.v29, _x.v30, _x.v31, _x.v32, _x.v33, _x.v34, _x.v35, _x.v36, _x.v37, _x.v38, _x.v39, _x.v40, _x.v41, _x.v42, _x.v43, _x.v44, _x.v45, _x.v46, _x.v47, _x.v48, _x.v49, _x.v50, _x.v51, _x.v52, _x.v53, _x.v54, _x.v55, _x.v56, _x.v57, _x.v58, _x.v59, _x.v60, _x.v61, _x.v62, _x.v63, _x.v64, _x.v65, _x.v66, _x.v67, _x.v68, _x.v69, _x.v70, _x.v71, _x.v72, _x.v73, _x.v74, _x.v75, _x.v76, _x.v77, _x.v78, _x.v79, _x.v80, _x.v81, _x.v82, _x.v83, _x.v84, _x.v85, _x.v86, _x.v87, _x.v88, _x.v89, _x.v90, _x.v91, _x.v92, _x.v93, _x.v94, _x.v95, _x.v96, _x.v97, _x.v98, _x.v99, _x.v100, _x.v101, _x.v102, _x.v103, _x.v104, _x.v105, _x.v106, _x.v107, _x.v108, _x.v109, _x.v110, _x.v111, _x.v112, _x.v113, _x.v114, _x.v115, _x.v116, _x.v117, _x.v118, _x.v119, _x.v120, _x.v121, _x.v122, _x.v123, _x.v124, _x.v125, _x.v126, _x.v127, _x.v128, _x.v129, _x.v130, _x.v131, _x.v132, _x.v133, _x.v134, _x.v135, _x.v136, _x.v137, _x.v138, _x.v139, _x.v140, _x.v141, _x.v142, _x.v143, _x.v144, _x.v145, _x.v146, _x.v147, _x.v148, _x.v149, _x.v150, _x.v151, _x.v152, _x.v153, _x.v154, _x.v155, _x.v156, _x.v157, _x.v158, _x.v159, _x.v160, _x.v161, _x.v162, _x.v163, _x.v164, _x.v165, _x.v166, _x.v167, _x.v168, _x.v169, _x.v170, _x.v171, _x.v172, _x.v173, _x.v174, _x.v175, _x.v176, _x.v177, _x.v178, _x.v179, _x.v180, _x.v181, _x.v182, _x.v183, _x.v184, _x.v185, _x.v186, _x.v187, _x.v188, _x.v189, _x.v190, _x.v191, _x.v192, _x.v193, _x.v194, _x.v195, _x.v196, _x.v197, _x.v198, _x.v199, _x.v200, _x.v201, _x.v202, _x.v203, _x.v204, _x.v205, _x.v206, _x.v207, _x.v208, _x.v209, _x.v210, _x.v211, _x.v212, _x.v213, _x.v214, _x.v215, _x.v216, _x.v217, _x.v218, _x.v219, _x.v220, _x.v221, _x.v222, _x.v223, _x.v224, _x.v225, _x.v226, _x.v227, _x.v228, _x.v229, _x.v230, _x.v231, _x.v232, _x.v233, _x.v234, _x.v235, _x.v236, _x.v237, _x.v238, _x.v239, _x.v240, _x.v241, _x.v242, _x.v243, _x.v244, _x.v245, _x.v246, _x.v247, _x.v248, _x.v249, _x.v250, _x.v251, _x.v252, _x.v253, _x.v254, _x.v255)) - buff.write(_struct_i.pack(self.v256)) - except struct.error as se: self._check_types(se) - except TypeError as te: self._check_types(te) - - def deserialize_numpy(self, str, numpy): - """ - unpack serialized message in str into this message instance using numpy for array types - :param str: byte array of serialized message, ``str`` - :param numpy: numpy python module - """ - try: - end = 0 - _x = self - start = end - end += 1020 - (_x.v1, _x.v2, _x.v3, _x.v4, _x.v5, _x.v6, _x.v7, _x.v8, _x.v9, _x.v10, _x.v11, _x.v12, _x.v13, _x.v14, _x.v15, _x.v16, _x.v17, _x.v18, _x.v19, _x.v20, _x.v21, _x.v22, _x.v23, _x.v24, _x.v25, _x.v26, _x.v27, _x.v28, _x.v29, _x.v30, _x.v31, _x.v32, _x.v33, _x.v34, _x.v35, _x.v36, _x.v37, _x.v38, _x.v39, _x.v40, _x.v41, _x.v42, _x.v43, _x.v44, _x.v45, _x.v46, _x.v47, _x.v48, _x.v49, _x.v50, _x.v51, _x.v52, _x.v53, _x.v54, _x.v55, _x.v56, _x.v57, _x.v58, _x.v59, _x.v60, _x.v61, _x.v62, _x.v63, _x.v64, _x.v65, _x.v66, _x.v67, _x.v68, _x.v69, _x.v70, _x.v71, _x.v72, _x.v73, _x.v74, _x.v75, _x.v76, _x.v77, _x.v78, _x.v79, _x.v80, _x.v81, _x.v82, _x.v83, _x.v84, _x.v85, _x.v86, _x.v87, _x.v88, _x.v89, _x.v90, _x.v91, _x.v92, _x.v93, _x.v94, _x.v95, _x.v96, _x.v97, _x.v98, _x.v99, _x.v100, _x.v101, _x.v102, _x.v103, _x.v104, _x.v105, _x.v106, _x.v107, _x.v108, _x.v109, _x.v110, _x.v111, _x.v112, _x.v113, _x.v114, _x.v115, _x.v116, _x.v117, _x.v118, _x.v119, _x.v120, _x.v121, _x.v122, _x.v123, _x.v124, _x.v125, _x.v126, _x.v127, _x.v128, _x.v129, _x.v130, _x.v131, _x.v132, _x.v133, _x.v134, _x.v135, _x.v136, _x.v137, _x.v138, _x.v139, _x.v140, _x.v141, _x.v142, _x.v143, _x.v144, _x.v145, _x.v146, _x.v147, _x.v148, _x.v149, _x.v150, _x.v151, _x.v152, _x.v153, _x.v154, _x.v155, _x.v156, _x.v157, _x.v158, _x.v159, _x.v160, _x.v161, _x.v162, _x.v163, _x.v164, _x.v165, _x.v166, _x.v167, _x.v168, _x.v169, _x.v170, _x.v171, _x.v172, _x.v173, _x.v174, _x.v175, _x.v176, _x.v177, _x.v178, _x.v179, _x.v180, _x.v181, _x.v182, _x.v183, _x.v184, _x.v185, _x.v186, _x.v187, _x.v188, _x.v189, _x.v190, _x.v191, _x.v192, _x.v193, _x.v194, _x.v195, _x.v196, _x.v197, _x.v198, _x.v199, _x.v200, _x.v201, _x.v202, _x.v203, _x.v204, _x.v205, _x.v206, _x.v207, _x.v208, _x.v209, _x.v210, _x.v211, _x.v212, _x.v213, _x.v214, _x.v215, _x.v216, _x.v217, _x.v218, _x.v219, _x.v220, _x.v221, _x.v222, _x.v223, _x.v224, _x.v225, _x.v226, _x.v227, _x.v228, _x.v229, _x.v230, _x.v231, _x.v232, _x.v233, _x.v234, _x.v235, _x.v236, _x.v237, _x.v238, _x.v239, _x.v240, _x.v241, _x.v242, _x.v243, _x.v244, _x.v245, _x.v246, _x.v247, _x.v248, _x.v249, _x.v250, _x.v251, _x.v252, _x.v253, _x.v254, _x.v255,) = _struct_255i.unpack(str[start:end]) - start = end - end += 4 - (self.v256,) = _struct_i.unpack(str[start:end]) - return self - except struct.error as e: - raise genpy.DeserializationError(e) #most likely buffer underfill - -_struct_I = genpy.struct_I -_struct_i = struct.Struct(" 0x03000000 else False -import genpy -import struct - -import genpy.msg - -class TestMsgArray(genpy.Message): - _md5sum = "e75eac49334a57b5055be2d573580cc2" - _type = "genpy/TestMsgArray" - _has_header = False #flag to mark the presence of a Header object - _full_text = """TestString[] strings -TestString[1] fixed_strings - -================================================================================ -MSG: genpy/TestString -string data - -""" - __slots__ = ['strings','fixed_strings'] - _slot_types = ['genpy/TestString[]','genpy/TestString[1]'] - - def __init__(self, *args, **kwds): - """ - Constructor. Any message fields that are implicitly/explicitly - set to None will be assigned a default value. The recommend - use is keyword arguments as this is more robust to future message - changes. You cannot mix in-order arguments and keyword arguments. - - The available fields are: - strings,fixed_strings - - :param args: complete set of field values, in .msg order - :param kwds: use keyword arguments corresponding to message field names - to set specific fields. - """ - if args or kwds: - super(TestMsgArray, self).__init__(*args, **kwds) - #message fields cannot be None, assign default values for those that are - if self.strings is None: - self.strings = [] - if self.fixed_strings is None: - self.fixed_strings = [genpy.msg.TestString()] - else: - self.strings = [] - self.fixed_strings = [genpy.msg.TestString()] - - def _get_types(self): - """ - internal API method - """ - return self._slot_types - - def serialize(self, buff): - """ - serialize message into buffer - :param buff: buffer, ``StringIO`` - """ - try: - length = len(self.strings) - buff.write(_struct_I.pack(length)) - for val1 in self.strings: - _x = val1.data - length = len(_x) - if python3 or type(_x) == unicode: - _x = _x.encode('utf-8') - length = len(_x) - buff.write(struct.pack(' 0x03000000 else False -import genpy -import struct - - -class TestPrimitiveArray(genpy.Message): - _md5sum = "967cfe360901d64005cbd5a83593b144" - _type = "genpy/TestPrimitiveArray" - _has_header = False #flag to mark the presence of a Header object - _full_text = """int32[] ints -int32[4] fixed_ints -string[] strings -string[4] fixed_strings - -""" - __slots__ = ['ints','fixed_ints','strings','fixed_strings'] - _slot_types = ['int32[]','int32[4]','string[]','string[4]'] - - def __init__(self, *args, **kwds): - """ - Constructor. Any message fields that are implicitly/explicitly - set to None will be assigned a default value. The recommend - use is keyword arguments as this is more robust to future message - changes. You cannot mix in-order arguments and keyword arguments. - - The available fields are: - ints,fixed_ints,strings,fixed_strings - - :param args: complete set of field values, in .msg order - :param kwds: use keyword arguments corresponding to message field names - to set specific fields. - """ - if args or kwds: - super(TestPrimitiveArray, self).__init__(*args, **kwds) - #message fields cannot be None, assign default values for those that are - if self.ints is None: - self.ints = [] - if self.fixed_ints is None: - self.fixed_ints = [0,0,0,0] - if self.strings is None: - self.strings = [] - if self.fixed_strings is None: - self.fixed_strings = ['','','',''] - else: - self.ints = [] - self.fixed_ints = [0,0,0,0] - self.strings = [] - self.fixed_strings = ['','','',''] - - def _get_types(self): - """ - internal API method - """ - return self._slot_types - - def serialize(self, buff): - """ - serialize message into buffer - :param buff: buffer, ``StringIO`` - """ - try: - length = len(self.ints) - buff.write(_struct_I.pack(length)) - pattern = '<%si'%length - buff.write(struct.pack(pattern, *self.ints)) - buff.write(_struct_4i.pack(*self.fixed_ints)) - length = len(self.strings) - buff.write(_struct_I.pack(length)) - for val1 in self.strings: - length = len(val1) - if python3 or type(val1) == unicode: - val1 = val1.encode('utf-8') - length = len(val1) - buff.write(struct.pack(' 0x03000000 else False -import genpy -import struct - - -class TestString(genpy.Message): - _md5sum = "992ce8a1687cec8c8bd883ec73ca41d1" - _type = "genpy/TestString" - _has_header = False #flag to mark the presence of a Header object - _full_text = """string data - -""" - __slots__ = ['data'] - _slot_types = ['string'] - - def __init__(self, *args, **kwds): - """ - Constructor. Any message fields that are implicitly/explicitly - set to None will be assigned a default value. The recommend - use is keyword arguments as this is more robust to future message - changes. You cannot mix in-order arguments and keyword arguments. - - The available fields are: - data - - :param args: complete set of field values, in .msg order - :param kwds: use keyword arguments corresponding to message field names - to set specific fields. - """ - if args or kwds: - super(TestString, self).__init__(*args, **kwds) - #message fields cannot be None, assign default values for those that are - if self.data is None: - self.data = '' - else: - self.data = '' - - def _get_types(self): - """ - internal API method - """ - return self._slot_types - - def serialize(self, buff): - """ - serialize message into buffer - :param buff: buffer, ``StringIO`` - """ - try: - _x = self.data - length = len(_x) - if python3 or type(_x) == unicode: - _x = _x.encode('utf-8') - length = len(_x) - buff.write(struct.pack(' '3': - long = int - -def _canon(secs, nsecs): - #canonical form: nsecs is always positive, nsecs < 1 second - while nsecs >= 1000000000: - secs += 1 - nsecs -= 1000000000 - while nsecs < 0: - secs -= 1 - nsecs += 1000000000 - return secs,nsecs - -class TVal(object): - """ - Base class of :class:`Time` and :class:`Duration` representations. Representation - is secs+nanoseconds since epoch. - """ - - __slots__ = ['secs', 'nsecs'] - - # mimic same API as messages when being introspected - _slot_types = ['int32', 'int32'] - - def __init__(self, secs=0, nsecs=0): - """ - :param secs: seconds. If secs is a float, then nsecs must not be set or 0, - larger seconds will be of type long on 32-bit systems, ``int/long/float`` - :param nsecs: nanoseconds, ``int`` - """ - if type(secs) != int and type(secs) != long: - # float secs constructor - if nsecs != 0: - raise ValueError("if secs is a float, nsecs cannot be set") - float_secs = secs - secs = int(float_secs) - nsecs = int((float_secs - secs) * 1000000000) - - self.secs, self.nsecs = _canon(secs, nsecs) - - def is_zero(self): - """ - :returns: ``True`` if time is zero (secs and nsecs are zero), ``bool`` - """ - return self.secs == 0 and self.nsecs == 0 - - def set(self, secs, nsecs): - """ - Set time using separate secs and nsecs values - - :param secs: seconds since epoch, ``int`` - :param nsecs: nanoseconds since seconds, ``int`` - """ - self.secs = secs - self.nsecs = nsecs - - def canon(self): - """ - Canonicalize the field representation in this instance. should - only be used when manually setting secs/nsecs slot values, as - in deserialization. - """ - self.secs, self.nsecs = _canon(self.secs, self.nsecs) - - def to_sec(self): - """ - :returns: time as float seconds (same as time.time() representation), ``float`` - """ - return float(self.secs) + float(self.nsecs) / 1e9 - - def to_nsec(self): - """ - :returns: time as nanoseconds, ``long`` - """ - return self.secs * long(1e9) + self.nsecs - - def __hash__(self): - """ - Time values are hashable. Time values with identical fields have the same hash. - """ - return ("%s.%s"%(self.secs, self.nsecs)) .__hash__() - - def __str__(self): - return str(self.to_nsec()) - - def __repr__(self): - return "genpy.TVal[%d]"%self.to_nsec() - - def __bool__(self): - """ - Return if time value is not zero - """ - return self.secs != 0 or self.nsecs != 0 - - def __nonzero__(self): - """ - Check if time value is not zero - """ - return self.secs or self.nsecs - - def __lt__(self, other): - """ - < test for time values - """ - try: - return self.__cmp__(other) < 0 - except TypeError: - return NotImplemented - def __le__(self, other): - """ - <= test for time values - """ - try: - return self.__cmp__(other) <= 0 - except TypeError: - return NotImplemented - def __gt__(self, other): - """ - > test for time values - """ - try: - return self.__cmp__(other) > 0 - except TypeError: - return NotImplemented - def __ge__(self, other): - """ - >= test for time values - """ - try: - return self.__cmp__(other) >= 0 - except TypeError: - return NotImplemented - def __ne__(self, other): - return not self.__eq__(other) - def __cmp__(self, other): - if not isinstance(other, TVal): - raise TypeError("Cannot compare to non-TVal") - nanos = self.to_nsec() - other.to_nsec() - if nanos > 0: - return 1 - if nanos == 0: - return 0 - return -1 - def __eq__(self, other): - if not isinstance(other, TVal): - return False - return self.to_nsec() == other.to_nsec() - -class Time(TVal): - """ - Time contains the ROS-wide 'time' primitive representation, which - consists of two integers: seconds since epoch and nanoseconds since - seconds. Time instances are mutable. - """ - __slots__ = ['secs', 'nsecs'] - def __init__(self, secs=0, nsecs=0): - """ - Constructor: secs and nsecs are integers. You may prefer to use the static L{from_sec()} factory - method instead. - - :param secs: seconds since epoch, ``int`` - :param nsecs: nanoseconds since seconds (since epoch), ``int`` - """ - super(Time, self).__init__(secs, nsecs) - if self.secs < 0: - raise TypeError("time values must be positive") - - def __getstate__(self): - """ - support for Python pickling - """ - return [self.secs, self.nsecs] - - def __setstate__(self, state): - """ - support for Python pickling - """ - self.secs, self.nsecs = state - - def from_sec(float_secs): - """ - Create new Time instance using time.time() value (float - seconds) - - :param float_secs: time value in time.time() format, ``float`` - :returns: :class:`Time` instance for specified time - """ - secs = int(float_secs) - nsecs = int((float_secs - secs) * 1000000000) - return Time(secs, nsecs) - - from_sec = staticmethod(from_sec) - - def to_time(self): - """ - Get Time in time.time() format. alias of L{to_sec()} - - :returns: time in floating point secs (time.time() format), ``float`` - """ - return self.to_sec() - - def __repr__(self): - return "genpy.Time[%d]"%self.to_nsec() - - def __add__(self, other): - """ - Add duration to this time - - :param other: :class:`Duration` - """ - if not isinstance(other, Duration): - return NotImplemented - return Time(self.secs + other.secs, self.nsecs + other.nsecs) - - def __sub__(self, other): - """ - Subtract time or duration from this time - :param other: :class:`Duration`/:class:`Time` - :returns: :class:`Duration` if other is a :class:`Time`, :class:`Time` if other is a :class:`Duration` - """ - if isinstance(other, Time): - return Duration(self.secs - other.secs, self.nsecs - other.nsecs) - elif isinstance(other, Duration): - return Time(self.secs - other.secs, self.nsecs - other.nsecs) - else: - return NotImplemented - - def __cmp__(self, other): - """ - Compare to another time - :param other: :class:`Time` - """ - if not isinstance(other, Time): - raise TypeError("cannot compare to non-Time") - nanos = self.to_nsec() - other.to_nsec() - if nanos > 0: - return 1 - if nanos == 0: - return 0 - return -1 - - def __eq__(self, other): - """ - Equals test for Time. Comparison assumes that both time - instances are in canonical representation; only compares fields. - - :param other: :class:`Time` - """ - if not isinstance(other, Time): - return False - return self.secs == other.secs and self.nsecs == other.nsecs - - def __hash__(self): - return super(Time, self).__hash__() - -class Duration(TVal): - """ - Duration represents the ROS 'duration' primitive, which consists - of two integers: seconds and nanoseconds. The Duration class - allows you to add and subtract Duration instances, including - adding and subtracting from :class:`Time` instances. - """ - __slots__ = ['secs', 'nsecs'] - def __init__(self, secs=0, nsecs=0): - """ - Create new Duration instance. secs and nsecs are integers and correspond to the ROS 'duration' primitive. - - :param secs: seconds, ``int`` - :param nsecs: nanoseconds, ``int`` - """ - super(Duration, self).__init__(secs, nsecs) - - def __getstate__(self): - """ - support for Python pickling - """ - return [self.secs, self.nsecs] - - def __setstate__(self, state): - """ - support for Python pickling - """ - self.secs, self.nsecs = state - - def __repr__(self): - return "genpy.Duration[%d]"%self.to_nsec() - - def from_sec(float_seconds): - """ - Create new Duration instance from float seconds format. - - :param float_seconds: time value in specified as float seconds, ``float`` - :returns: :class:`Duration` instance for specified float_seconds - """ - secs = int(float_seconds) - nsecs = int((float_seconds - secs) * 1000000000) - return Duration(secs, nsecs) - - from_sec = staticmethod(from_sec) - - def __neg__(self): - """ - :returns: Negative value of this :class:`Duration` - """ - return Duration(-self.secs, -self.nsecs) - def __abs__(self): - """ - Absolute value of this duration - :returns: positive :class:`Duration` - """ - if self.secs > 0: - return self - return self.__neg__() - - def __add__(self, other): - """ - Add duration to this duration, or this duration to a time, creating a new time value as a result. - :param other: duration or time, ``Duration``/``Time`` - :returns: :class:`Duration` if other is a :class:`Duration` - instance, :class:`Time` if other is a :class:`Time` - """ - if isinstance(other, Time): - return other.__add__(self) - elif isinstance(other, Duration): - return Duration(self.secs+other.secs, self.nsecs+other.nsecs) - else: - return NotImplemented - def __sub__(self, other): - """ - Subtract duration from this duration, returning a new duration - :param other: duration - :returns: :class:`Duration` - """ - if not isinstance(other, Duration): - return NotImplemented - return Duration(self.secs-other.secs, self.nsecs-other.nsecs) - - def __mul__(self, val): - """ - Multiply this duration by an integer or float - :param val: multiplication factor, ``int/float`` - :returns: :class:`Duration` multiplied by val - """ - t = type(val) - if t in (int, long): - return Duration(self.secs * val, self.nsecs * val) - elif t == float: - return Duration.from_sec(self.to_sec() * val) - else: - return NotImplemented - - def __floordiv__(self, val): - """ - Floor divide this duration by an integer or float - :param val: division factor, ``int/float`` - :returns: :class:`Duration` divided by val - """ - t = type(val) - if t in (int, long): - return Duration(self.secs // val, self.nsecs // val) - elif t == float: - return Duration.from_sec(self.to_sec() // val) - else: - return NotImplemented - - def __div__(self, val): - """ - Divide this duration by an integer or float - :param val: division factor, ``int/float`` - :returns: :class:`Duration` divided by val - """ - # unlike __floordiv__, this uses true div for float arg. - # PEP 238 - t = type(val) - if t in (int, long): - return Duration(self.secs // val, self.nsecs // val) - elif t == float: - return Duration.from_sec(self.to_sec() / val) - else: - return NotImplemented - - def __truediv__(self, val): - """ - Divide this duration by an integer or float - :param val: division factor, ``int/float`` - :returns: :class:`Duration` multiplied by val - """ - if type(val) in (int, long, float): - return Duration.from_sec(self.to_sec() / val) - else: - return NotImplemented - - def __cmp__(self, other): - if not isinstance(other, Duration): - raise TypeError("Cannot compare to non-Duration") - nanos = self.to_nsec() - other.to_nsec() - if nanos > 0: - return 1 - if nanos == 0: - return 0 - return -1 - - def __eq__(self, other): - if not isinstance(other, Duration): - return False - return self.secs == other.secs and self.nsecs == other.nsecs - - def __hash__(self): - return super(Duration, self).__hash__() diff --git a/firos/include/libLoader.py b/firos/include/libLoader.py index f22a335..6497863 100644 --- a/firos/include/libLoader.py +++ b/firos/include/libLoader.py @@ -18,47 +18,119 @@ import re import imp import importlib +import sys + +# Add genpy to sys.path (This is not written as a module) +sys.path.append(os.path.dirname(os.path.realpath(__file__)) + "/genpy/src/") +from genpy.generator import MsgGenerator +from include.logger import Log regex = re.compile(u'^(.*)(\\b.msg\\b)(.*)$') -# TODO DL , loadFromFile and loadFromSystem is only used by Topic Handler -# load3rdParty might be replaced by obj2ros? + class LibLoader: + ''' LibLoader is a class which tries to retrieve the python class of + specific ROS-Messages. First tries to retrieve it via the standard + python import module. If this fails, it checks the folder FIORS/msgs for the + specific message. If the '.msg'-File is missing in the corresponding folder (or + the class could not be generated), this LibLoader tries to load the message via + roslib. If every method fails FIROS will shutdown, since FIROS need the messages + due to rospy beforehand. + ''' + + # Our custom search path for genpy + searchpath = dict() + + @staticmethod - def loadFromFile(filepath): - ## \brief Load file from path - # \param File path - mod_name, file_ext = os.path.splitext(os.path.split(filepath)[-1]) + def _init_search_path(path): + ''' Initializes the search path for genpy. + In this case we add all directory-names into the search path which + are available in path. - if file_ext.lower() == '.py': - py_mod = importlib.import_module(mod_name, package=filepath) + 'namepace' still needs to be set to the actual package of the Message (TODO DL correct?) + ''' + if len(LibLoader.searchpath) == 0: + # Initialize seachpath + subdirs = [x[0] for x in os.walk(path)] # get all directories inside path (including itself) + subdirs = subdirs[1:] # Remove reference to itself + for subdir in subdirs: + subdir_name = subdir.split("/")[-1] + LibLoader.searchpath[subdir_name] = [subdir] - elif file_ext.lower() == '.pyc': - py_mod = importlib.import_module(mod_name, package=filepath) + return LibLoader.searchpath - return py_mod @staticmethod - def load3rdParty(filepath, className): - ## \brief Load class from file - # \param File path - # \param Class name - module = LibLoader.loadFromFile(filepath) - return getattr(module, className) + def loadFromSystem(msgType, robotID, topic): + ''' This actually tries all three methods mentioned above. + + Remark: If the regex does not find a match, we are also not able + to parse the Configuration-File ('robots.json') and exit. + ''' + matches = re.search(regex, msgType) # get (PACKAGE).(msg).(MSGTYPE) - @staticmethod - def loadFromSystem(lib): - ## \brief Load library - # \param library name - module = None - matches = re.search(regex, lib) if matches is not None: - module_name = str(matches.group(1)) + str(matches.group(2)) - modules = str(matches.group(3)).split(".") + # We have a Match, we can start to get the Message now! + module_name = str(matches.group(1)) + str(matches.group(2))[:-4] # PACKAGE + '.msg' + modules = str(matches.group(3)).split(".") # MSGTYPE modules = modules[1: len(modules)] - module = importlib.import_module(module_name) + module_msg = modules[0] + + + ##### 1: Try to load it via Python-Import + try: + module = importlib.import_module(module_name + ".msg") + clazz = getattr(module, module_msg) + return clazz + except ImportError: + Log("WARNING", "Message {} was not found. Trying to load the Message-File in FIROS/msgs".format(module_msg)) + + + + ##### 2: Try to load the Message given the Message-files inside FIROS/msgs + current_path = os.path.dirname(os.path.abspath(__file__)) + msgsFold = current_path + "/../../msgs/" # FIROS/msgs - Folder + search_path = LibLoader._init_search_path(msgsFold) + search_path["namespace"] = module_name + try: + # Disable Output, since genpy prints exceptions + sys.stdout = open(os.devnull, "w") + sys.stderr = open(os.devnull, "w") + retcode = MsgGenerator().generate_messages(module_name, [msgsFold + module_name + "/" + module_msg + ".msg"], msgsFold + module_name, search_path) + except Exception: + # Case we got an Exception -> retcode = 1 -> Error + retcode = 1 + pass + finally: + # Enable Output again + sys.stdout = sys.__stdout__ + sys.stderr = sys.__stderr__ + + if retcode == 1: + Log("WARNING", "Could not load message {}/{}. Maybe it references other missing messages?".format(module_name, module_msg)) + elif retcode == 0: + module = imp.load_source(module_msg, msgsFold + module_name + "/_" + module_msg + ".py") + clazz = getattr(module, module_msg) + Log("INFO", "Message {}/{}.msg succesfully loaded.".format(module_name, module_msg)) + return clazz + + + + ##### 3: Our last resort, the roslib.message which might know this message! + try: + import roslib.message + import rostopic + type_name = rostopic.get_topic_type('/{}/{}'.format(robotID, topic), blocking=False)[0] + if type_name: + clazz = roslib.message.get_message_class(type_name) + Log("INFO", "Message {}/{}.msg loaded via roslib.message!".format(module_name, module_msg)) + return clazz + except Exception: + pass + + + ### Message could not be loaded or the regex does not match + Log("ERROR", "Unable to load the message: {} on this system.".format(msgType)) + exit() - - for name in modules: - module = getattr(module, name) - return module diff --git a/firos/include/ros/dependencies/__init__.py b/firos/include/ros/dependencies/__init__.py deleted file mode 100644 index 06c4e5c..0000000 --- a/firos/include/ros/dependencies/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env python - -# MIT License -# -# Copyright (c) <2015> -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files -# (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, -# publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -# FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/firos/include/ros/dependencies/third_party.py b/firos/include/ros/dependencies/third_party.py deleted file mode 100644 index ca95627..0000000 --- a/firos/include/ros/dependencies/third_party.py +++ /dev/null @@ -1,18 +0,0 @@ -import os -from include.libLoader import LibLoader -THIRDPARTY_BASE_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "thirdparty") - -# USE LibLoader.load3rdParty to assign a class to variable -# MyClass = LibLoader.load3rdParty("PATH/TO/myclass.py, 'MyClass') - - -# PLAY_MOTION_PATH = os.path.join(THIRDPARTY_BASE_PATH, 'play_motion_msgs/msg/') - -# MotionInfo = LibLoader.load3rdParty(os.path.join(PLAY_MOTION_PATH, 'MotionInfo.py'), 'MotionInfo') -# PlayMotionAction = LibLoader.load3rdParty(os.path.join(PLAY_MOTION_PATH, 'PlayMotionAction.py'), 'PlayMotionAction') -# PlayMotionActionFeedback = LibLoader.load3rdParty(os.path.join(PLAY_MOTION_PATH, 'PlayMotionActionFeedback.py'), 'PlayMotionActionFeedback') -# PlayMotionActionGoal = LibLoader.load3rdParty(os.path.join(PLAY_MOTION_PATH, 'PlayMotionActionGoal.py'), 'PlayMotionActionGoal') -# PlayMotionActionResult = LibLoader.load3rdParty(os.path.join(PLAY_MOTION_PATH, 'PlayMotionActionResult.py'), 'PlayMotionActionResult') -# PlayMotionFeedback = LibLoader.load3rdParty(os.path.join(PLAY_MOTION_PATH, 'PlayMotionFeedback.py'), 'PlayMotionFeedback') -# PlayMotionGoal = LibLoader.load3rdParty(os.path.join(PLAY_MOTION_PATH, 'PlayMotionGoal.py'), 'PlayMotionGoal') -# PlayMotionResult = LibLoader.load3rdParty(os.path.join(PLAY_MOTION_PATH, 'PlayMotionResult.py'), 'PlayMotionResult') diff --git a/firos/include/ros/rosConfigurator.py b/firos/include/ros/rosConfigurator.py index bddb256..930e5c7 100644 --- a/firos/include/ros/rosConfigurator.py +++ b/firos/include/ros/rosConfigurator.py @@ -21,6 +21,7 @@ import rostopic import rosgraph +from include.logger import Log from include.constants import Constants as C # TODO DL previously ur'' was used instead of r''? or ''? . Working? Refactor! @@ -178,6 +179,8 @@ def setWhiteList(additions, deletions, restore=False): try: json_path = C.PATH + "/whitelist.json" mem_whitelist = json.load(open(json_path)) + if len(mem_whitelist) == 0: + Log("WARNING", "The 'whitelist.json' was not set. You might want to use a whitelist to avoid subscribing to every existing topic!") except: mem_whitelist = {} if additions: @@ -220,6 +223,8 @@ def _getWhiteList(pubsub): if mem_whitelist is None: json_path = C.PATH + "/whitelist.json" data = json.load(open(json_path)) + if len(data) == 0: + Log("WARNING", "The 'whitelist.json' was not set. You might want to use a whitelist to avoid subscribing to every existing topic!") else: data = mem_whitelist diff --git a/firos/include/ros/topicHandler.py b/firos/include/ros/topicHandler.py index 419946e..e0ade39 100644 --- a/firos/include/ros/topicHandler.py +++ b/firos/include/ros/topicHandler.py @@ -28,7 +28,6 @@ from include.constants import Constants as C from include.libLoader import LibLoader from include.ros.rosConfigurator import RosConfigurator -from include.ros.dependencies.third_party import * # PubSub Handlers from include.contextbroker.cbPublisher import CbPublisher @@ -95,18 +94,7 @@ def loadMsgHandlers(robot_data): # Load specific message from robot_data # TODO DL maybe change this in config to ._type values? Refactor! msg = str(robot_data[robotID]['topics'][topic]['msg']) - if type(msg) is dict: - # TODO DL Dead Code? - _topic_name = robotID + ".msg." + robotID - module = LibLoader.loadFromFile(os.path.join(TOPIC_BASE_PATH, robotID+topic+".py")) - theclass = getattr(module, topic) - else: - _final_name = msg.split('.')[-1] - _topic_name = str(msg) - if _final_name in globals(): - theclass = globals()[_final_name] - else: - theclass = LibLoader.loadFromSystem(msg) + theclass = LibLoader.loadFromSystem(msg, robotID, topic) # Add specific message in struct to not load it again later. if theclass._type not in ROS_MESSAGE_CLASSES: diff --git a/firos/include/server/requestHandler.py b/firos/include/server/requestHandler.py index 5263965..befd175 100644 --- a/firos/include/server/requestHandler.py +++ b/firos/include/server/requestHandler.py @@ -177,7 +177,7 @@ def listRobots(request, action): TODO DL, currently a List of containing 'topics' with a list of topics is returned Better would be a list of robotIds with their corersponding topics and types ''' - robots = getRobots(False, True) + robots = getRobots(False) data = [] for robot_name in robots.keys(): robot_data = {"name": robot_name, "topics": []} diff --git a/firos/setup.py b/firos/setup.py deleted file mode 100755 index cf18f9e..0000000 --- a/firos/setup.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python - -# MIT License -# -# Copyright (c) <2015> -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files -# (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, -# publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -# FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -# ROSPY LOGS -# logdebug -# logerr -# logfatal -# loginfo -# logout -# logwarn - -# Import required Python code. -import os -import sys -import rospy -import traceback -import genmsg.msg_loader -from include.genpy import generator -from include.genpy import genpy_firos -from include import confManager -from include.logger import Log - - -def launchSetup(main=False): - retcode = 0 - - Log("INFO", "\nStarting Firos setup...") - Log("INFO", "---------------------------------\n") - Log("INFO", "\nGenerating Message Description Files\n") - - try: - robots = confManager.getRobots(True, True) - current_path = os.path.dirname(os.path.abspath(__file__)) - outdir = os.path.join(current_path, "include/ros/") - retcode = genpy_firos.genmain(robots, generator.MsgGenerator(genmsg.msg_loader.load_msg_from_string), outdir) - Log("INFO", "\nSuccesfully generated\n") - if main: - sys.exit(retcode or 0) - except Exception as e: - rospy.logerr("\nSomething wrong happened\n") - traceback.print_exc() - Log("ERROR", e) - sys.exit(retcode or 0) - -# Main function. -if __name__ == '__main__': - # Initialize the node and name it. - rospy.init_node('firos_setup') - launchSetup(True) diff --git a/msgs/geometry_msgs/Twist.msg b/msgs/geometry_msgs/Twist.msg new file mode 100644 index 0000000..7012c2d --- /dev/null +++ b/msgs/geometry_msgs/Twist.msg @@ -0,0 +1,3 @@ +# This expresses velocity in free space broken into its linear and angular parts. +Vector3 linear +Vector3 angular diff --git a/msgs/geometry_msgs/Vector3.msg b/msgs/geometry_msgs/Vector3.msg new file mode 100644 index 0000000..2877783 --- /dev/null +++ b/msgs/geometry_msgs/Vector3.msg @@ -0,0 +1,10 @@ +# This represents a vector in free space. +# It is only meant to represent a direction. Therefore, it does not +# make sense to apply a translation to it (e.g., when applying a +# generic rigid transformation to a Vector3, tf2 will only apply the +# rotation). If you want your data to be translatable too, use the +# geometry_msgs/Point message instead. + +float64 x +float64 y +float64 z \ No newline at end of file diff --git a/msgs/turtlesim/Pose.msg b/msgs/turtlesim/Pose.msg new file mode 100644 index 0000000..c1d03a3 --- /dev/null +++ b/msgs/turtlesim/Pose.msg @@ -0,0 +1,6 @@ +float32 x +float32 y +float32 theta + +float32 linear_velocity +float32 angular_velocity \ No newline at end of file