├── README.md ├── visensor_calibration_flasher ├── CMakeLists.txt ├── README.md ├── camchain-imucam-example.yaml ├── launch │ └── flash_sensor.launch ├── package.xml └── src │ └── visensor_calibration_flasher.cpp └── visensor_update ├── CMakeLists.txt ├── README.md └── src ├── SensorUpdater.cpp ├── SensorUpdater.hpp ├── communication_layers ├── SshConnection.cpp ├── SshConnection.hpp ├── WebClient.cpp └── WebClient.hpp ├── main.cpp └── update_config.hpp /README.md: -------------------------------------------------------------------------------- 1 | # README # 2 | 3 | This repo contains some tools to interface the VI-Sensor: 4 | 5 | * **visensor_calibration_flasher**: Uploads VI-Sensor calibration on sensor firmware. The device itself is factory calibrated. However, if you changed the camera/IMU configuration, you can calibrate it using the [Kalibr](https://github.com/ethz-asl/kalibr/) framework. The resulting camchain file can be uploaded to sensor using this script. 6 | 7 | * **visensor_update**: Updates your VI-Sensor to newest firmware version. Checks online if your sensor is up to date and updates it if necessary. 8 | -------------------------------------------------------------------------------- /visensor_calibration_flasher/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(visensor_calibration_flasher) 3 | 4 | find_package(catkin REQUIRED COMPONENTS 5 | roscpp 6 | libvisensor 7 | ) 8 | 9 | include_directories(include ${catkin_INCLUDE_DIRS}) 10 | 11 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -std=c++0x -D__STRICT_ANSI__") 12 | 13 | catkin_package( 14 | INCLUDE_DIRS ${catkin_INCLUDE_DIRS} 15 | CATKIN_DEPENDS 16 | roscpp 17 | libvisensor 18 | ) 19 | 20 | add_executable(visensor_calibration_flasher src/visensor_calibration_flasher.cpp ) 21 | 22 | target_link_libraries(visensor_calibration_flasher ${catkin_LIBRARIES}) 23 | -------------------------------------------------------------------------------- /visensor_calibration_flasher/README.md: -------------------------------------------------------------------------------- 1 | # README # 2 | 3 | ### Howto: Build visensor_calibration_flasher ### 4 | 5 | Clone repository into your ROS catkin workspace 6 | ``` 7 | cd /src 8 | git clone https://github.com/skybotix/visensor_tools.git 9 | ``` 10 | Build your catkin workspace 11 | ``` 12 | cd 13 | catkin_make 14 | ``` 15 | 16 | ### Howto: Flash a calibration file### 17 | 18 | To test the program, we attached an example camchain file to this repo. You can generate your own camera-imu calibration using the framework [Kalibr](https://github.com/ethz-asl/kalibr). 19 | 20 | Once the calibration using Kalibr is done, you can update the camchain-imucam-example.yaml file using the new values. 21 | 22 | You can now upload the new calibration to the VI-Sensor 23 | 24 | **Please note that you will overwrite the factory calibration**: 25 | ``` 26 | roslaunch visensor_calibration_flasher flash_sensor.launch 27 | ``` 28 | If you get a *Calibration upload succeeded!*, everything went smoothly. You can test the new calibration by starting the block-matcher launch file of the visensor_node. If you managed to flash your sensor incidentally, but still want the factory calibration, contact support@skybotix.com . 29 | ``` 30 | roslaunch visensor_node dense.launch 31 | ``` 32 | If everything went smoothly, the rectified and disparity image should look fine (Rectified image: straight lines should be straight, also towards the image corners. Disparity image: If scene is sufficiently textured, disparity map should be dense and fairly outlier-free). 33 | 34 | -------------------------------------------------------------------------------- /visensor_calibration_flasher/camchain-imucam-example.yaml: -------------------------------------------------------------------------------- 1 | cam0: 2 | T_cam_imu: 3 | - [1.0, 0.0, 0.0, 0.0] 4 | - [0.0, 1.0, 0.0, 0.0] 5 | - [0.0, 0.0, 1.0, 0.0] 6 | - [0.0, 0.0, 0.0, 1.0] 7 | cam_overlaps: [1] 8 | camera_model: pinhole 9 | distortion_coeffs: [0.0, 0.0, 0.0, 0.0] # [k1, k2, p1, p2] 10 | distortion_model: radtan 11 | intrinsics: [0.0, 0.0, 0.0, 0.0] # [f_x, f_y, c_x, c_y] 12 | resolution: [752, 480] 13 | rostopic: /cam0/image_raw 14 | flip_camera: true 15 | cam1: 16 | T_cam_imu: 17 | - [1.0, 0.0, 0.0, 1.0] 18 | - [0.0, 1.0, 0.0, 1.0] 19 | - [0.0, 0.0, 1.0, 1.0] 20 | - [0.0, 0.0, 0.0, 1.0] 21 | cam_overlaps: [0] 22 | camera_model: pinhole 23 | distortion_coeffs: [0.0, 0.0, 0.0, 0.0] # [k1, k2, p1, p2] 24 | distortion_model: radtan 25 | intrinsics: [0.0, 0.0, 0.0, 0.0] # [f_x, f_y, c_x, c_y] 26 | resolution: [752, 480] 27 | rostopic: /cam1/image_raw 28 | flip_camera: true 29 | -------------------------------------------------------------------------------- /visensor_calibration_flasher/launch/flash_sensor.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /visensor_calibration_flasher/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | visensor_calibration_flasher 4 | 0.0.0 5 | Flashes the VI Sensor given a Kalibr calibration file 6 | Sammy Omari 7 | BSD 8 | catkin 9 | roscpp 10 | libvisensor 11 | roscpp 12 | libvisensor 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /visensor_calibration_flasher/src/visensor_calibration_flasher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Skybotix AG, Switzerland (info@skybotix.com) 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and non-commercial use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * Neither the name of the {organization} nor the names of its 17 | * contributors may be used to endorse or promote products derived from 18 | * this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 24 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | * 31 | */ 32 | #include 33 | #include 34 | 35 | #include 36 | 37 | void printSensorConfig(const visensor::ViCameraCalibration& config){ 38 | 39 | std::cout << "Focal Length: \n"; 40 | std::cout << config.focal_point[0] << "\t" << config.focal_point[1] << std::endl; 41 | std::cout << "Principcal Point: \n"; 42 | std::cout << config.principal_point[0] << "\t" << config.principal_point[1] << std::endl; 43 | std::cout << "Principcal Coefficient: \n"; 44 | for (int i = 0; i< 5; ++i){ 45 | std::cout << config.dist_coeff[i] << " "; 46 | } 47 | std::cout << "\nR: \n"; 48 | for (int i = 0; i< 3; ++i){ 49 | std::cout << config.R[i] << "\t" << config.R[i + 3] << "\t" << config.R[i + 6] << "\n"; 50 | } 51 | std::cout << "T: \n"; 52 | for (int i = 0; i< 3; ++i){ 53 | std::cout << config.t[i] << "\t"; 54 | } 55 | std::cout << std::endl; 56 | } 57 | 58 | static const std::map ROS_CAMERA_NAMES { 59 | { visensor::SensorId::SensorId::CAM0, "/cam0" }, 60 | { visensor::SensorId::SensorId::CAM1, "/cam1" }, 61 | { visensor::SensorId::SensorId::CAM2, "/cam2" }, 62 | { visensor::SensorId::SensorId::CAM3, "/cam3" }, 63 | { visensor::SensorId::SensorId::FLIR0, "/tau0" }, 64 | { visensor::SensorId::SensorId::FLIR1, "/tau1" }, 65 | { visensor::SensorId::SensorId::FLIR2, "/tau2" }, 66 | { visensor::SensorId::SensorId::FLIR3, "/tau3" } }; 67 | 68 | int main(int argc, char **argv) 69 | { 70 | ros::init(argc, argv, "vi_calibration_flasher"); 71 | ros::NodeHandle nh("~"); 72 | 73 | visensor::ViSensorDriver drv; 74 | 75 | try { 76 | drv.init(); 77 | } catch (visensor::exceptions const &ex) { 78 | std::cout << ex.what() << "\n"; 79 | exit(1); 80 | } 81 | 82 | std::vector list_of_camera_ids = drv.getListOfCameraIDs(); 83 | 84 | std::vector camCalibration; 85 | camCalibration.resize(list_of_camera_ids.size()); 86 | 87 | char answer; 88 | std::cout << "Overwrite factory calibration? [y/N]" << std::endl; 89 | std::cin >> answer; 90 | std::cout << "\n"; 91 | 92 | if(answer=='y' || answer=='Y') { 93 | std::cout << "Going to overwrite factory calibration." << std::endl; 94 | } else { 95 | std::cout << "Calibration upload canceled." << std::endl; 96 | return 0; 97 | } 98 | 99 | for (auto camera_id : list_of_camera_ids) 100 | { 101 | visensor::ViCameraCalibration camera_calibration; 102 | 103 | std::cout << "Reading out " << ROS_CAMERA_NAMES.at(static_cast(camera_id)) << std::endl; 104 | XmlRpc::XmlRpcValue cam_params; 105 | nh.getParam(ROS_CAMERA_NAMES.at(static_cast(camera_id)), cam_params); 106 | 107 | assert(cam_params.hasMember("distortion_coeffs")); 108 | assert(cam_params.hasMember("intrinsics")); 109 | assert(cam_params.hasMember("resolution")); 110 | assert(cam_params.hasMember("camera_model")); 111 | assert(cam_params.hasMember("distortion_model")); 112 | assert(cam_params.hasMember("T_cam_imu")); 113 | XmlRpc::XmlRpcValue T_C_I; 114 | 115 | bool flip_camera; 116 | if (cam_params.hasMember("flip_camera")){ 117 | flip_camera = cam_params["flip_camera"]; 118 | } 119 | else{ 120 | flip_camera = true; 121 | } 122 | std::cout << "flip_camera: " << flip_camera << std::endl; 123 | T_C_I = cam_params["T_cam_imu"]; 124 | //EIGEN USES COLUMN MAJOR ORDER! 125 | camera_calibration.R[0] = (double) T_C_I[0][0]; 126 | camera_calibration.R[3] = (double) T_C_I[0][1]; 127 | camera_calibration.R[6] = (double) T_C_I[0][2]; 128 | camera_calibration.R[1] = (double) T_C_I[1][0]; 129 | camera_calibration.R[4] = (double) T_C_I[1][1]; 130 | camera_calibration.R[7] = (double) T_C_I[1][2]; 131 | camera_calibration.R[2] = (double) T_C_I[2][0]; 132 | camera_calibration.R[5] = (double) T_C_I[2][1]; 133 | camera_calibration.R[8] = (double) T_C_I[2][2]; 134 | 135 | camera_calibration.t[0] = (double) T_C_I[0][3]; 136 | camera_calibration.t[1] = (double) T_C_I[1][3]; 137 | camera_calibration.t[2] = (double) T_C_I[2][3]; 138 | 139 | 140 | 141 | XmlRpc::XmlRpcValue distortion_coeffs = cam_params["distortion_coeffs"]; 142 | camera_calibration.dist_coeff[0] = (double) distortion_coeffs[0]; 143 | camera_calibration.dist_coeff[1] = (double) distortion_coeffs[1]; 144 | camera_calibration.dist_coeff[2] = (double) distortion_coeffs[2]; 145 | camera_calibration.dist_coeff[3] = (double) distortion_coeffs[3]; 146 | camera_calibration.dist_coeff[4] = (double) 0.0; 147 | XmlRpc::XmlRpcValue intrinsics = cam_params["intrinsics"]; 148 | 149 | camera_calibration.focal_point[0] = (double) intrinsics[0]; 150 | camera_calibration.focal_point[1] = (double) intrinsics[1]; 151 | camera_calibration.principal_point[0] = (double) intrinsics[2]; 152 | camera_calibration.principal_point[1] = (double) intrinsics[3]; 153 | 154 | XmlRpc::XmlRpcValue resolution = cam_params["resolution"]; 155 | 156 | std::string camera_model; 157 | std::string distortion_model; 158 | 159 | camera_model.assign(cam_params["camera_model"]); 160 | distortion_model.assign(cam_params["distortion_model"]); 161 | 162 | if (camera_model != std::string("pinhole")) { 163 | std::cout << "Camera Model is not pinhole model. Abort, abort!\n"; 164 | return 1; 165 | } 166 | if (distortion_model != std::string("radtan")) { 167 | std::cout << "Distortion Model is not radtan model. Abort, abort!\n"; 168 | return 1; 169 | } 170 | 171 | if(drv.setCameraFactoryCalibration(camera_id, camera_calibration, flip_camera) == false) { 172 | std::cout << "Calibration upload failed!\n"; 173 | return 1; 174 | } 175 | } 176 | std::cout << "Calibration upload succeeded!\n"; 177 | return 0; 178 | } 179 | 180 | -------------------------------------------------------------------------------- /visensor_update/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #Skybotix AG, 2/12/2013 2 | cmake_minimum_required(VERSION 2.8.0) 3 | 4 | ############ 5 | # SETTINGS 6 | ############ 7 | set(PKGNAME visensor_update) 8 | 9 | SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin) 10 | SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib) 11 | 12 | ########### 13 | # BUILD 14 | ########### 15 | FILE(GLOB SRCS src/*.cpp src/communication_layers/*.cpp) 16 | 17 | #Release / debug build 18 | set(CMAKE_BUILD_TYPE Release) 19 | ADD_DEFINITIONS (-march=native -O2 -fmessage-length=0 -MMD -MP -Wall -pedantic -std=c++0x ) #Release 20 | #ADD_DEFINITIONS (-march=native -std=c++0x -O0 -g3 -fmessage-length=0 -MMD -MP -Wall -pedantic -std=c++0x ) #Debug 21 | 22 | #executable 23 | ADD_EXECUTABLE(${PKGNAME} ${SRCS}) 24 | TARGET_LINK_LIBRARIES(${PKGNAME} boost_regex curl ssh2) 25 | 26 | ########### 27 | # INSTALL 28 | ########### 29 | #visensor_update 30 | INSTALL( 31 | FILES bin/visensor_update 32 | DESTINATION bin 33 | COMPONENT tools 34 | ) 35 | 36 | -------------------------------------------------------------------------------- /visensor_update/README.md: -------------------------------------------------------------------------------- 1 | # README # 2 | 3 | ### Howto: Build visensor_update ### 4 | 5 | Clone repository onto your harddrive 6 | ``` 7 | git clone https://github.com/skybotix/visensor_tools.git 8 | ``` 9 | Make sure that you have all necessary packages installed in order to compile update package 10 | ``` 11 | sudo apt-get install libssh2-1-dev libboost-regex-dev 12 | ``` 13 | Go to visensor_update directory, create build directory and compile it 14 | ``` 15 | cd visensor_tools/visensor_update 16 | mkdir build 17 | cd build 18 | cmake .. 19 | make 20 | ``` 21 | 22 | ### Howto: Update the VI-Sensor### 23 | Make sure that you are connected to the internet. Make sure that the sensor is connected and you know its IP. If the sensor is directly connected to the PC, its IP is 10.0.0.1 : 24 | 25 | Run visensor_update tool (assuming that the sensor IP is 10.0.0.1 and the sensor has a ADIS16448 IMU) 26 | ``` 27 | cd visensor_tools/visensor_update/bin 28 | ./visensor_update 10.0.0.1 update 29 | ``` 30 | 31 | If the sensor has a ADIS16488 IMU (tactical grade), adjust the update command as follows: 32 | ``` 33 | cd visensor_tools/visensor_update/bin 34 | ./visensor_update 10.0.0.1 update-16488 35 | ``` 36 | 37 | If everything went smoothly, the sensor will reboot after the update and the terminal output is something like 38 | 39 | ``` 40 | After update: 41 | Name Version 42 | ----------------------------------------- 43 | visensor-fpga-bitstream 0.0.8 44 | visensor-kernel-modules 0.0.3 45 | visensor-linux-embedded 0.1.1 46 | 47 | Rebooting sensor... 48 | ``` 49 | -------------------------------------------------------------------------------- /visensor_update/src/SensorUpdater.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Skybotix AG, Switzerland (info@skybotix.com) 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and non-commercial use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * Neither the name of the {organization} nor the names of its 17 | * contributors may be used to endorse or promote products derived from 18 | * this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 24 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | * 31 | */ 32 | 33 | 34 | #include 35 | 36 | #include "SensorUpdater.hpp" 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | 44 | 45 | SensorUpdater::SensorUpdater(const std::string &hostname) : 46 | pSsh_( new SshConnection(hostname, 47 | UpdateConfig::ssh_username, 48 | UpdateConfig::ssh_password) ) 49 | { 50 | } 51 | 52 | 53 | SensorUpdater::~SensorUpdater() 54 | { 55 | } 56 | 57 | //function returns a vector of pairs with (package_name, version) 58 | //for all packages that start with the given packagename prefix 59 | bool SensorUpdater::getVersionInstalled(SensorUpdater::VersionList &outPackageList, const std::string &prefix, bool dontParseVersion) 60 | { 61 | int exitcode=127; 62 | 63 | /* run command */ 64 | std::string output; 65 | pSsh_->runCommand( std::string("dpkg -l | grep ") + prefix, 66 | output, 67 | exitcode ); 68 | 69 | //clear the output VersionList 70 | outPackageList.clear(); 71 | 72 | //typical line to parse: 73 | // ii vim 2:7.3.547-4ubuntu1.1 amd64 Vi IMproved - enhanced vi editor 74 | typedef boost::tokenizer > tokenizer; 75 | boost::char_separator sep("\n"); 76 | tokenizer tokens(output, sep); 77 | 78 | 79 | //divide by new lines 80 | for (tokenizer::iterator tok_iter = tokens.begin(); tok_iter != tokens.end(); ++tok_iter) 81 | { 82 | 83 | //get the filename 84 | std::string line = *tok_iter; 85 | 86 | //parse package file names 87 | //typical line: visensor-linux-1.0.1-Linux.deb 88 | //design and check on: http://regexpal.com/ 89 | 90 | boost::regex *expression; 91 | 92 | if(!dontParseVersion) 93 | { 94 | //exract version number 95 | expression = new boost::regex("[\\s\\t]*[A-Za-z0-9]*[\\s\\t]+([A-Za-z0-9\\-]+)[\\s\\t]+([0-9]+)\\.([0-9]+)\\.([0-9]+)[\\s\\t]+([A-Za-z0-9-]+)[A-Za-z0-9\\-\\.\\s.()]*"); 96 | } else { 97 | //do not extract version number 98 | expression = new boost::regex("[\\s\\t]*[A-Za-z0-9]{2}[\\s\\t]+([A-Za-z0-9\\-]+)[\\s\\t]+([A-Za-z0-9\\-\\.\\s.()]+)"); 99 | } 100 | 101 | 102 | boost::cmatch what; 103 | 104 | /* find matches */ 105 | if( regex_match(line.c_str(), what, *expression) ) 106 | { 107 | // what[0] contains whole filename 108 | // what[1] contains the package name 109 | // what[2] contains the major version number 110 | // what[3] contains the minor version number 111 | // what[4] contains the patch version number 112 | // what[5] contains the arch 113 | 114 | SensorUpdater::VersionEntry package; 115 | package.package_name = what[1]; 116 | if(!dontParseVersion) 117 | { 118 | package.version_major = boost::lexical_cast( what[2] ); 119 | package.version_minor = boost::lexical_cast( what[3] ); 120 | package.version_patch = boost::lexical_cast( what[4] ); 121 | } 122 | 123 | /* add package to the list of packages */ 124 | outPackageList.push_back( package ); 125 | 126 | } else { 127 | //regex match failed (file is not a valid package name...) 128 | std::cout << "regex failed: " << line.c_str() << "\n"; 129 | } 130 | } 131 | 132 | /* return true if exit-code = 0 */ 133 | return true; 134 | } 135 | 136 | 137 | 138 | bool SensorUpdater::getVersionsOnServer(SensorUpdater::VersionList &outPackageList, UpdateConfig::REPOS repo) 139 | { 140 | /* clear the output list*/ 141 | outPackageList.clear(); 142 | 143 | /* query the ftp server */ 144 | std::string filelist; 145 | std::string repo_ftppath = UpdateConfig::REPOS_PATH[ static_cast( repo ) ]; 146 | 147 | /* open ftp connection */ 148 | WebClient web_client(UpdateConfig::hostname); 149 | 150 | bool success = web_client.dirList(repo_ftppath, filelist); 151 | 152 | if(!success) 153 | return false; 154 | 155 | //extract filenames from filelist 156 | typedef boost::tokenizer > tokenizer; 157 | boost::char_separator sep(";"); 158 | tokenizer tokensL(filelist, sep); 159 | 160 | //loop through all filenames 161 | for (tokenizer::iterator tokL_iter = tokensL.begin(); tokL_iter != tokensL.end(); ++tokL_iter) 162 | { 163 | 164 | //get the filename 165 | std::string filename = *tokL_iter; 166 | 167 | //parse package file names 168 | //typical line: visensor-linux-1.0.1-Linux.deb 169 | //design and check on: http://regexpal.com/ 170 | boost::regex expression("([A-Za-z0-9-]+)-([0-9]+)\\.([0-9]+)\\.([0-9]+)-([A-Za-z0-9-]+)\\.deb"); 171 | boost::cmatch what; 172 | 173 | /* find matches */ 174 | if( regex_match(filename.c_str(), what, expression) ) 175 | { 176 | // what[0] contains whole filename 177 | // what[1] contains the package name 178 | // what[2] contains the major version number 179 | // what[3] contains the minor version number 180 | // what[4] contains the patch version number 181 | // what[5] contains the arch 182 | 183 | SensorUpdater::VersionEntry package; 184 | package.package_name = what[1]; 185 | package.version_major = boost::lexical_cast( what[2] ); 186 | package.version_minor = boost::lexical_cast( what[3] ); 187 | package.version_patch = boost::lexical_cast( what[4] ); 188 | 189 | /* store the relative ftp path (if we want to downlaod it later...) */ 190 | package.path = UpdateConfig::REPOS_PATH[ static_cast( repo ) ] + "/" + filename; 191 | 192 | 193 | /* store the packages */ 194 | outPackageList.push_back( package ); 195 | 196 | } else { 197 | //regex match failed (file is not a valid package name...) 198 | //std::cout << "regex failed: " << filename.c_str() << "\n"; 199 | } 200 | } 201 | 202 | //now remove old version (only the newest version of each package should remain in the list 203 | return true; 204 | } 205 | 206 | bool SensorUpdater::printVersionsInstalled(void) 207 | { 208 | SensorUpdater::VersionList listSensor; 209 | bool success = getVersionInstalled(listSensor, UpdateConfig::prefix); 210 | 211 | if(!success) 212 | { 213 | std::cout << "Error: could not get installed versions from sensor!\n"; 214 | return false; 215 | } 216 | 217 | std:: cout << "Name\t\t\t\tVersion\n"; 218 | std:: cout << "-----------------------------------------\n"; 219 | 220 | if( !listSensor.size() ) 221 | { 222 | std::cout << "No packages installed!\n"; 223 | return true; 224 | } 225 | 226 | for(size_t i=0; irunCommand( std::string("reboot"), 280 | output, 281 | exitcode ); 282 | 283 | std::cout << "Rebooting sensor...\n"; 284 | 285 | /* return true if exit-code = 0 */ 286 | return (exitcode == 0); 287 | } 288 | 289 | 290 | /* install a debian package which is on the sensor */ 291 | bool sensorInstallDebMemory(const std::string &debian_package); 292 | 293 | 294 | /* install a debian package which is on the sensor */ 295 | bool SensorUpdater::sensorInstallDebFile(const std::string &remotefile) 296 | { 297 | std::string output; 298 | int exitcode=127; 299 | 300 | /* mount read-write for changes */ 301 | bool success = sensorSetMountRW(true); 302 | 303 | if(!success) 304 | return false; 305 | 306 | /* run command */ 307 | pSsh_->runCommand( std::string("dpkg -i ") + remotefile, 308 | output, 309 | exitcode ); 310 | 311 | 312 | /* mount read-only after changes */ 313 | success = sensorSetMountRW(false); 314 | 315 | /* return true if exit-code = 0 */ 316 | return (exitcode == 0); 317 | } 318 | 319 | 320 | /* remove the deb package with the name package_name */ 321 | bool SensorUpdater::sensorRemoveDeb(const std::string &package_name) 322 | { 323 | std::string output; 324 | int exitcode=127; 325 | 326 | /* mount read-write for changes */ 327 | bool success = sensorSetMountRW(true); 328 | 329 | if(!success) 330 | return false; 331 | 332 | /* run command */ 333 | pSsh_->runCommand( std::string("dpkg -P ") + package_name, 334 | output, 335 | exitcode ); 336 | 337 | 338 | /* mount read-only after changes */ 339 | success = sensorSetMountRW(false); 340 | 341 | /* return true if exit-code = 0 */ 342 | return (exitcode == 0); 343 | } 344 | 345 | //RW: true ==> read-write, RW: false ==> read-only 346 | bool SensorUpdater::sensorSetMountRW(bool RW) 347 | { 348 | 349 | std::string output; 350 | int exitcode=127; 351 | 352 | /*command */ 353 | std::string cmd; 354 | if(RW) 355 | cmd = "mount -o remount,rw /"; 356 | else 357 | cmd = "mount -o remount,ro /"; 358 | 359 | /* run command */ 360 | pSsh_->runCommand( cmd, 361 | output, 362 | exitcode ); 363 | 364 | //0 and 255 are success exit codes 365 | if( exitcode != 0 && exitcode != 255) 366 | { 367 | std::cout << "Error: could not change RW mode on sensor!\n"; 368 | return false; 369 | } 370 | 371 | /* return true */ 372 | return true; 373 | } 374 | 375 | 376 | /* clean all installed packages on the sensor with the given prefix */ 377 | bool SensorUpdater::sensorClean(void) 378 | { 379 | SensorUpdater::VersionList listSensor; 380 | 381 | /* get all the installed packages with the given prefix */ 382 | bool success = getVersionInstalled(listSensor, UpdateConfig::prefix, true); 383 | 384 | if(!success) 385 | { 386 | std::cout << "Error: could not get installed versions from sensor!\n"; 387 | return false; 388 | } 389 | 390 | /* remove package after package */ 391 | for(size_t i=0; isendFile(pkg_filename, pkg_filename); 482 | if(!ret) 483 | { 484 | std::cout << "failed.\n"; 485 | std::cout << "[ERROR]: Could not upload file to sensor!\n"; 486 | exit(1); 487 | } 488 | 489 | /* install */ 490 | ret = sensorInstallDebFile(pkg_filename); 491 | 492 | if(!ret) 493 | { 494 | std::cout << "failed.\n"; 495 | std::cout << "[ERROR]: Could not install debfile on sensor " << pkg_filename << "\n"; 496 | exit(1); 497 | } 498 | 499 | std::cout << "done.\n"; 500 | } 501 | std::cout << std::endl; 502 | return true; 503 | } 504 | 505 | /* remove all old packages and install the newest version of all packages in the repo which are mandatory */ 506 | bool SensorUpdater::sensorUpdate(const UpdateConfig::REPOS &repo) 507 | { 508 | SensorUpdater::VersionList list; 509 | std::string localPath = std::string("/tmp/"); 510 | bool success = false; 511 | 512 | if(getUpdateList(list, repo)) 513 | { 514 | if(downloadPackagesToPath(list, localPath)) 515 | { 516 | if(sensorClean()) 517 | { 518 | if(installPackagesFromPath(list, localPath)) 519 | success = true; 520 | } 521 | } 522 | } 523 | 524 | return success; 525 | } 526 | 527 | 528 | -------------------------------------------------------------------------------- /visensor_update/src/SensorUpdater.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Skybotix AG, Switzerland (info@skybotix.com) 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and non-commercial use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * Neither the name of the {organization} nor the names of its 17 | * contributors may be used to endorse or promote products derived from 18 | * this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 24 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | * 31 | */ 32 | 33 | #ifndef SENSORUPDATER_HPP_ 34 | #define SENSORUPDATER_HPP_ 35 | 36 | #include "update_config.hpp" 37 | 38 | #include "communication_layers/SshConnection.hpp" 39 | #include "communication_layers/WebClient.hpp" 40 | 41 | #include 42 | #include 43 | 44 | 45 | class SensorUpdater { 46 | public: 47 | 48 | /* some typedefs */ 49 | struct VersionEntry { 50 | std::string package_name; 51 | unsigned int version_major; 52 | unsigned int version_minor; 53 | unsigned int version_patch; 54 | std::string path; 55 | 56 | /* lexicographical version comparison */ 57 | bool operator<(const VersionEntry& rhs) const 58 | { 59 | // compares n to rhs.n, 60 | // then s to rhs.s, 61 | // then d to rhs.d 62 | 63 | return std::tie(version_major, version_minor, version_patch) < std::tie(rhs.version_major, rhs.version_minor, rhs.version_patch); 64 | } 65 | 66 | bool operator==(const VersionEntry& rhs) const 67 | { 68 | return (version_major == rhs.version_major) && (version_minor == rhs.version_minor) && (version_patch == rhs.version_patch); 69 | } 70 | 71 | bool operator>(const VersionEntry& rhs) const 72 | { 73 | return !(*this VersionList; 79 | 80 | 81 | SensorUpdater(const std::string &hostname); 82 | virtual ~SensorUpdater(); 83 | 84 | /* repo functions */ 85 | bool getVersionInstalled(VersionList &outPackageList, const std::string &prefix, bool dontParseVersion=false); 86 | bool getVersionsOnServer(SensorUpdater::VersionList &outPackageList, UpdateConfig::REPOS repo); 87 | bool printVersionsInstalled(void); 88 | bool printVersionsRepo(UpdateConfig::REPOS repo); 89 | 90 | bool getUpdateList(SensorUpdater::VersionList &outList, const UpdateConfig::REPOS &repo); 91 | 92 | 93 | /* package functions */ 94 | bool downloadPackagesToPath(SensorUpdater::VersionList &packageList, const std::string &localPath); 95 | bool installPackagesFromPath(SensorUpdater::VersionList &packageList, const std::string &localPath); 96 | 97 | 98 | /* sensor functions */ 99 | bool sensorInstallDebMemory(const std::string &debian_package); 100 | bool sensorInstallDebFile(const std::string &file); 101 | bool sensorRemoveDeb(const std::string &package_name); 102 | 103 | bool sensorClean(void); 104 | bool sensorReboot(void) const; 105 | 106 | bool sensorSetMountRW(bool RW); 107 | 108 | 109 | /* high level update functions */ 110 | bool sensorUpdate(const UpdateConfig::REPOS &repo); 111 | 112 | 113 | private: 114 | SshConnection *pSsh_; //ssh connection to sensor 115 | 116 | }; 117 | 118 | #endif /* SENSORUPDATER_HPP_ */ 119 | -------------------------------------------------------------------------------- /visensor_update/src/communication_layers/SshConnection.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "SshConnection.hpp" 22 | 23 | 24 | static int waitsocket(int socket_fd, LIBSSH2_SESSION *session_ssh_) { 25 | struct timeval timeout; 26 | int rc; 27 | fd_set fd; 28 | fd_set *writefd = NULL; 29 | fd_set *readfd = NULL; 30 | int dir; 31 | 32 | /*timeout definition */ 33 | timeout.tv_sec = 0; 34 | timeout.tv_usec = 100; 35 | 36 | FD_ZERO(&fd); 37 | FD_SET(socket_fd, &fd); 38 | 39 | /* now make sure we wait in the correct direction */ 40 | dir = libssh2_session_block_directions(session_ssh_); 41 | 42 | if (dir & LIBSSH2_SESSION_BLOCK_INBOUND) 43 | readfd = &fd; 44 | 45 | if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) 46 | writefd = &fd; 47 | 48 | rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout); 49 | 50 | return rc; 51 | } 52 | 53 | SshConnection::SshConnection(const std::string &hostname, const std::string &username, const std::string &password, const unsigned int port): 54 | hostname_(hostname), 55 | username_(username), 56 | password_(password), 57 | port_(port) 58 | { 59 | 60 | /* init ssh session instance */ 61 | session_ssh_ = NULL; 62 | 63 | //establish connection to ssh server 64 | bool success = sshConnect(); 65 | 66 | if(!success) 67 | { 68 | std::cout << "Error: could not connect to sensor at " << hostname_ << "\n"; 69 | exit(1); 70 | } 71 | 72 | 73 | } 74 | 75 | SshConnection::~SshConnection() 76 | { 77 | //disconnect from ssh 78 | sshDisconnect(); 79 | } 80 | 81 | 82 | bool SshConnection::runCommand(const std::string &command, std::string &output, int &exitcode) const 83 | { 84 | 85 | LIBSSH2_CHANNEL *channel; 86 | int rc; 87 | char *exitsignal=(char *)"none"; 88 | int bytecount = 0; 89 | 90 | /*clear the output*/ 91 | output.clear(); 92 | 93 | /* Exec non-blocking on the remove host */ 94 | while( (channel = libssh2_channel_open_session(session_ssh_)) == NULL && libssh2_session_last_error(session_ssh_,NULL,NULL,0) == LIBSSH2_ERROR_EAGAIN ) 95 | { 96 | waitsocket(socket_, session_ssh_); 97 | } 98 | 99 | if( channel == NULL ) 100 | { 101 | std::cout << "Error runCommand\n"; 102 | return false; 103 | } 104 | while( (rc = libssh2_channel_exec(channel, command.c_str())) == LIBSSH2_ERROR_EAGAIN ) 105 | { 106 | waitsocket(socket_, session_ssh_); 107 | } 108 | 109 | if( rc != 0 ) 110 | { 111 | std::cout << "Error runCommand\n"; 112 | return false; 113 | } 114 | for( ;; ) 115 | { 116 | /* loop until we block */ 117 | int rc; 118 | do 119 | { 120 | char buffer[0x4000]; 121 | rc = libssh2_channel_read( channel, buffer, sizeof(buffer) ); 122 | 123 | if( rc > 0 ) 124 | { 125 | bytecount += rc; 126 | 127 | //write received data into output buffer 128 | for(int i=0; i 0 ); 134 | 135 | /* this is due to blocking that would occur otherwise so we loop on 136 | this condition */ 137 | if( rc == LIBSSH2_ERROR_EAGAIN ) 138 | { 139 | waitsocket(socket_, session_ssh_); 140 | } 141 | else 142 | break; 143 | } 144 | exitcode = 127; 145 | while( (rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN ) 146 | waitsocket(socket_, session_ssh_); 147 | 148 | if( rc == 0 ) 149 | { 150 | exitcode = libssh2_channel_get_exit_status( channel ); 151 | 152 | libssh2_channel_get_exit_signal(channel, &exitsignal, NULL, NULL, NULL, NULL, NULL); 153 | } 154 | 155 | libssh2_channel_free(channel); 156 | return true; 157 | } 158 | 159 | 160 | bool SshConnection::sendFile(const std::string &srcpath, std::string &scppath) const 161 | { 162 | 163 | LIBSSH2_CHANNEL *channel; 164 | 165 | FILE *local; 166 | struct stat fileinfo; 167 | int rc; 168 | char mem[1024*100]; 169 | size_t nread; 170 | char *ptr; 171 | long total = 0; 172 | size_t prev; 173 | 174 | /* open the local file */ 175 | local = fopen(srcpath.c_str(), "rb"); 176 | if (!local) { 177 | std::cout << "sendfile: can't find local file" << srcpath.c_str() << "\n"; 178 | return -1; 179 | } 180 | 181 | stat(srcpath.c_str(), &fileinfo); 182 | 183 | 184 | /* Send a file via scp. The mode parameter must only have permissions! */ 185 | do { 186 | channel = libssh2_scp_send(session_ssh_, scppath.c_str(), fileinfo.st_mode & 0777, (unsigned long)fileinfo.st_size); 187 | 188 | if ((!channel) && (libssh2_session_last_errno(session_ssh_) != LIBSSH2_ERROR_EAGAIN)) 189 | { 190 | char *err_msg; 191 | 192 | libssh2_session_last_error(session_ssh_, &err_msg, NULL, 0); 193 | 194 | std::cout << "sendFile error:" << err_msg << "\n"; 195 | return false; 196 | } 197 | } while (!channel); 198 | 199 | /* send file*/ 200 | do { 201 | nread = fread(mem, 1, sizeof(mem), local); 202 | if (nread <= 0) { 203 | /* end of file */ 204 | break; 205 | } 206 | ptr = mem; 207 | 208 | total += nread; 209 | 210 | prev = 0; 211 | do { 212 | while ((rc = libssh2_channel_write(channel, ptr, nread)) == LIBSSH2_ERROR_EAGAIN) 213 | { 214 | waitsocket(socket_, session_ssh_); 215 | prev = 0; 216 | } 217 | if (rc < 0) { 218 | std::cout << "sendFile: ERROR " << rc << "total "< 0) { 289 | 290 | //write received data into output buffer 291 | for(int i=0; i 0); 298 | 299 | if ((rc == LIBSSH2_ERROR_EAGAIN) && (got < fileinfo.st_size)) { 300 | /* this is due to blocking that would occur otherwise 301 | so we loop on this condition */ 302 | 303 | spin++; 304 | waitsocket(socket_, session_ssh_); /* now we wait */ 305 | continue; 306 | } 307 | break; 308 | } 309 | 310 | 311 | /* clean up channel */ 312 | libssh2_channel_free(channel); 313 | channel = NULL; 314 | 315 | /* close file */ 316 | dstFile.close(); 317 | 318 | return true; 319 | } 320 | 321 | void SshConnection::sshDisconnect() { 322 | 323 | libssh2_session_disconnect(session_ssh_, "Normal Shutdown, Thank you for playing"); 324 | libssh2_session_free(session_ssh_); 325 | close(socket_); 326 | libssh2_exit(); 327 | } 328 | 329 | 330 | bool SshConnection::sshConnect() { 331 | unsigned long hostaddr; 332 | struct sockaddr_in sin; 333 | int rc; 334 | 335 | /* set the ip address */ 336 | hostaddr = inet_addr(hostname_.c_str()); 337 | 338 | /* init the libssh2 library */ 339 | rc = libssh2_init(0); 340 | if (rc != 0) { 341 | std::cout << "libssh2 initialization failed (" << rc << ")\n"; 342 | return false; 343 | } 344 | 345 | /* create socket to connect to ip */ 346 | socket_ = socket(AF_INET, SOCK_STREAM, 0); 347 | 348 | sin.sin_family = AF_INET; 349 | sin.sin_port = htons(port_); 350 | sin.sin_addr.s_addr = hostaddr; 351 | if (connect(socket_, (struct sockaddr*) (&sin), sizeof(struct sockaddr_in)) != 0) 352 | { 353 | //could not connect to hostname... 354 | return false; 355 | } 356 | 357 | /* Create a session_ssh_ instance */ 358 | session_ssh_ = libssh2_session_init(); 359 | if (!session_ssh_) 360 | return false; 361 | 362 | /* Since we have set non-blocking, tell libssh2 we are non-blocking */ 363 | libssh2_session_set_blocking(session_ssh_, 0); 364 | 365 | 366 | /* ... start it up. This will trade welcome banners, exchange keys, 367 | * and setup crypto, compression, and MAC layers 368 | */ 369 | while ((rc = libssh2_session_handshake(session_ssh_, socket_)) == LIBSSH2_ERROR_EAGAIN); 370 | if (rc) { 371 | std::cout << "Failure establishing SSH session_ssh_: " << rc << "\n"; 372 | return false; 373 | } 374 | 375 | /* We could authenticate via password */ 376 | while ((rc = libssh2_userauth_password(session_ssh_, username_.c_str(), password_.c_str())) == LIBSSH2_ERROR_EAGAIN); 377 | if (rc) { 378 | std::cout << "SSH authentication by password failed.\n"; 379 | return false; 380 | } 381 | 382 | return true; 383 | } 384 | 385 | -------------------------------------------------------------------------------- /visensor_update/src/communication_layers/SshConnection.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SensorUpdater.hpp 3 | * 4 | * Created on: Dec 1, 2013 5 | * Author: skybotix 6 | */ 7 | 8 | #ifndef SSHCONNECTION_HPP_ 9 | #define SSHCONNECTION_HPP_ 10 | 11 | #include 12 | #include 13 | 14 | class SshConnection { 15 | 16 | 17 | public: 18 | SshConnection(const std::string &hostname, const std::string &username, const std::string &password, const unsigned int port=22); 19 | virtual ~SshConnection(); 20 | 21 | 22 | /* protocol-lvl functionality */ 23 | bool runCommand(const std::string &command, std::string &output, int &exitcode) const; 24 | bool sendFile(const std::string &srcpath, std::string &scppath) const; 25 | bool getFile(const std::string &scppath, std::string &dstpath) const; 26 | 27 | 28 | 29 | 30 | private: 31 | /* ssh session stuff mgmt */ 32 | bool sshConnect(); 33 | void sshDisconnect(); 34 | 35 | 36 | LIBSSH2_SESSION *session_ssh_; //ssh session 37 | int socket_; //network socket 38 | 39 | const std::string hostname_; //ssh server details 40 | const std::string username_; 41 | const std::string password_; 42 | const unsigned int port_; 43 | 44 | 45 | 46 | }; 47 | 48 | #endif /* SSHCONNECTION_HPP_ */ 49 | 50 | -------------------------------------------------------------------------------- /visensor_update/src/communication_layers/WebClient.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "WebClient.hpp" 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *outputBuffer) 13 | { 14 | size_t realsize = size * nmemb; 15 | 16 | for(size_t i=0; i 12 | #include 13 | 14 | 15 | class WebClient { 16 | 17 | 18 | public: 19 | WebClient(const std::string &hostname, bool verbose=false); 20 | virtual ~WebClient(); 21 | 22 | /* protocol-lvl functionality */ 23 | bool dirList(const std::string &ftppath, std::string &outputBuffer); 24 | bool getFileToMemory(const std::string &ftppath, std::string &outputBuffer); 25 | bool getFileToFile(const std::string &ftppath, const std::string &localpath); 26 | 27 | 28 | 29 | private: 30 | CURL *curl_; //curl instance 31 | 32 | const std::string hostname_; //server data 33 | const bool verbose_; 34 | 35 | 36 | }; 37 | 38 | #endif /* FTPCLIENT_HPP_ */ 39 | 40 | -------------------------------------------------------------------------------- /visensor_update/src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Skybotix AG, Switzerland (info@skybotix.com) 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and non-commercial use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * Neither the name of the {organization} nor the names of its 17 | * contributors may be used to endorse or promote products derived from 18 | * this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 24 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | * 31 | */ 32 | #include "SensorUpdater.hpp" 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | void printArgs(void) 39 | { 40 | std::cout << "visensor_update " << std::endl; 41 | std::cout << std::endl; 42 | 43 | std::cout << " Available commands are:" << std::endl; 44 | std::cout << " update updates the sensor to the newest software on the online repo" << std::endl; 45 | std::cout << " update-16488 updates the sensor with ADIS 16488 to the newest software on the online repo" << std::endl; 46 | std::cout << " clean removes all software on the sensor" << std::endl; 47 | std::cout << " version shows installed packages " << std::endl; 48 | std::cout << " reboot reboot sensor " << std::endl; 49 | //std::cout << " install install custom package " << std::endl; 50 | //std::cout << " remove removes custom package " << std::endl; 51 | std::cout << std::endl; 52 | 53 | std::cout << " Perform sensor update:" << std::endl; 54 | std::cout << " visensor_update 10.0.0.1 update" << std::endl; 55 | std::cout << std::endl; 56 | } 57 | 58 | bool update(SensorUpdater &updater, const UpdateConfig::REPOS &repo) 59 | { 60 | /* print version before update */ 61 | std::cout << "Before update:\n"; 62 | updater.printVersionsInstalled(); 63 | 64 | /* install the newest version of all mandatory packages */ 65 | bool success = updater.sensorUpdate(repo); 66 | 67 | /* print version before update */ 68 | std::cout << "After update:\n"; 69 | updater.printVersionsInstalled(); 70 | 71 | /* reboot the sensor */ 72 | updater.sensorReboot(); 73 | 74 | return success; 75 | } 76 | 77 | bool cmdUpdate(SensorUpdater &updater) 78 | { 79 | return update(updater, UpdateConfig::REPOS::REPO_RELEASE); 80 | } 81 | 82 | bool cmdUpdate16488(SensorUpdater &updater) 83 | { 84 | return update(updater, UpdateConfig::REPOS::REPO_16488_RELEASE); 85 | } 86 | 87 | bool cmdUpdateDevelop(SensorUpdater &updater) 88 | { 89 | return update(updater, UpdateConfig::REPOS::REPO_DEV); 90 | } 91 | 92 | bool cmdUpdate16488Develop(SensorUpdater &updater) 93 | { 94 | return update(updater, UpdateConfig::REPOS::REPO_16488_DEV); 95 | } 96 | 97 | bool cmdClean(SensorUpdater &updater) 98 | { 99 | return updater.sensorClean(); 100 | } 101 | 102 | bool cmdVersion(SensorUpdater &updater) 103 | { 104 | return updater.printVersionsInstalled(); 105 | } 106 | 107 | bool cmdReboot(SensorUpdater &updater) 108 | { 109 | return updater.sensorReboot(); 110 | } 111 | 112 | 113 | int main(int argc, char** argv) 114 | { 115 | // command arguments 116 | typedef bool (*commandFunction)(SensorUpdater&); // function pointer type 117 | std::map argCmds = 118 | { 119 | {"update", cmdUpdate}, 120 | {"update-16488", cmdUpdate16488}, 121 | {"update-devel", cmdUpdateDevelop}, 122 | {"update-16488-devel", cmdUpdate16488Develop}, 123 | {"clean", cmdClean}, 124 | {"reboot", cmdReboot}, 125 | {"version", cmdVersion}, 126 | }; 127 | 128 | //parse args 129 | std::vector args; 130 | for(int i=1; i 142 | hostname = args[0]; 143 | command = args[1]; 144 | } 145 | else if (args.size() == 1) 146 | { 147 | //args , use default hostname 148 | std::cout << "Sensor IP address not specified; using default (10.0.0.1)\n\n"; 149 | hostname = std::string("10.0.0.1"); 150 | command = args[0]; 151 | } 152 | else 153 | { 154 | printArgs(); 155 | exit(1); 156 | } 157 | 158 | //check command and run it 159 | bool success=false; 160 | 161 | if( !argCmds.count( command ) ) 162 | { 163 | //invalid command 164 | printArgs(); 165 | exit(-1); 166 | } 167 | 168 | // try to connect to the specified hostname/IP 169 | SensorUpdater updater(hostname); 170 | 171 | // run the command 172 | success = argCmds[command](updater); 173 | 174 | return success; 175 | } 176 | 177 | -------------------------------------------------------------------------------- /visensor_update/src/update_config.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Skybotix AG, Switzerland (info@skybotix.com) 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and non-commercial use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * Redistributions of source code must retain the above copyright notice, this 10 | * list of conditions and the following disclaimer. 11 | * 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | * list of conditions and the following disclaimer in the documentation and/or 14 | * other materials provided with the distribution. 15 | * 16 | * Neither the name of the {organization} nor the names of its 17 | * contributors may be used to endorse or promote products derived from 18 | * this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 24 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | * 31 | */ 32 | 33 | 34 | #ifndef UPDATE_CONFIG_HPP_ 35 | #define UPDATE_CONFIG_HPP_ 36 | 37 | #include 38 | #include 39 | 40 | namespace UpdateConfig 41 | { 42 | /* sensor ssh login configuration */ 43 | const std::string ssh_username = "root"; 44 | const std::string ssh_password = ""; 45 | 46 | /* update repo configuration */ 47 | const std::string hostname = "http://skybotix.com/downloads/vi-firmware"; 48 | 49 | /*standard prefix for debian package filenames */ 50 | const std::string prefix("visensor"); 51 | 52 | /* where are the repos on the ftp server (ftp relative path) */ 53 | enum class REPOS : std::size_t 54 | { 55 | REPO_RELEASE, 56 | REPO_DEV, 57 | REPO_16488_RELEASE, 58 | REPO_16488_DEV 59 | }; 60 | 61 | const std::string REPOS_PATH[] = 62 | { 63 | "release", 64 | "develop", 65 | "release/adis16488", 66 | "develop/adis16488" 67 | }; 68 | 69 | 70 | /* which packages do we want to install, if we do a sensor update */ 71 | const std::vector repo_mandatory_pkgs = 72 | { 73 | std::string("visensor-fpga-bitstream"), 74 | std::string("visensor-kernel-modules"), 75 | std::string("visensor-linux-embedded") 76 | }; 77 | 78 | 79 | } 80 | 81 | #endif /* UPDATE_CONFIG_HPP_ */ 82 | 83 | 84 | --------------------------------------------------------------------------------