spi_base_controller.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2013, Shadow Robot Company, All rights reserved.
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 3.0 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library.
00016  */
00017 
00024 #include "sr_ronex_controllers/spi_base_controller.hpp"
00025 #include "pluginlib/class_list_macros.h"
00026 #include <utility>
00027 #include <string>
00028 #include <queue>
00029 
00030 namespace ronex
00031 {
00032 SPIBaseController::SPIBaseController()
00033   : loop_count_(0), command_queue_(NUM_SPI_OUTPUTS), status_queue_(NUM_SPI_OUTPUTS), delete_status_(NUM_SPI_OUTPUTS)
00034 {}
00035 
00036 bool SPIBaseController::init(ros_ethercat_model::RobotStateInterface* robot, ros::NodeHandle &n)
00037 {
00038   return pre_init_(robot, n);
00039 }
00040 
00041 bool SPIBaseController::pre_init_(ros_ethercat_model::RobotStateInterface* robot, ros::NodeHandle &n)
00042 {
00043   assert(robot);
00044   node_ = n;
00045 
00046   std::string ronex_id;
00047   if (!node_.getParam("ronex_id", ronex_id))
00048   {
00049     ROS_ERROR("No RoNeX ID given (namespace: %s)", node_.getNamespace().c_str());
00050     return false;
00051   }
00052 
00053   // get the path from the parameters
00054   std::string path;
00055   int parameter_id = get_ronex_param_id(ronex_id);
00056   {
00057     if ( parameter_id == -1 )
00058     {
00059       ROS_ERROR_STREAM("Could not find the RoNeX id in the parameter server: " << ronex_id <<
00060                                " not loading the controller.");
00061       return false;
00062     }
00063     else
00064     {
00065       std::stringstream ss;
00066       ss << "/ronex/devices/" << parameter_id << "/path";
00067       if ( !ros::param::get(ss.str(), path) )
00068       {
00069         ROS_ERROR_STREAM("Couldn't read the parameter " << ss.str() <<
00070                                  " from the parameter server. Not loading the controller.");
00071         return false;
00072       }
00073     }
00074   }
00075   topic_prefix_ = path;
00076 
00077   std::string robot_state_name;
00078   node_.param<std::string>("robot_state_name", robot_state_name, "unique_robot_hw");
00079 
00080   try
00081   {
00082     spi_ = static_cast<ronex::SPI*>(robot->getHandle(robot_state_name).getState()->getCustomHW(path));
00083   }
00084   catch(const hardware_interface::HardwareInterfaceException& e)
00085   {
00086     ROS_ERROR_STREAM("Could not find robot state: " << robot_state_name << " Not loading the controller. " << e.what());
00087     return false;
00088   }
00089 
00090   if (spi_ == NULL)
00091   {
00092     ROS_ERROR_STREAM("Could not find RoNeX module: " << ronex_id << " not loading the controller");
00093     return false;
00094   }
00095 
00096   // preallocating memory for the command and statues queues
00097   for (uint16_t spi_index = 0; spi_index < NUM_SPI_OUTPUTS; ++spi_index)
00098   {
00099     std::queue<SplittedSPICommand, boost::circular_buffer<SplittedSPICommand> > cq(
00100         boost::circular_buffer<SplittedSPICommand>(NUM_BUFFER_ELEMENTS));
00101     command_queue_[spi_index] = cq;
00102     std::queue<std::pair<SplittedSPICommand, SPIResponse >,
00103         boost::circular_buffer<std::pair<SplittedSPICommand, SPIResponse > > > sq(boost::circular_buffer<
00104         std::pair<SplittedSPICommand, SPIResponse > >(NUM_BUFFER_ELEMENTS));
00105     status_queue_[spi_index] = sq;
00106   }
00107   return true;
00108 }
00109 
00110 void SPIBaseController::starting(const ros::Time&)
00111 {
00112   // @TODO: implement starting
00113 }
00114 
00118 void SPIBaseController::update(const ros::Time&, const ros::Duration&)
00119 {
00120   for (uint16_t spi_index = 0; spi_index < NUM_SPI_OUTPUTS; ++spi_index)
00121   {
00122     // Check if the status has been processed
00123     if (delete_status_[spi_index] && status_queue_[spi_index].size() > 0)
00124     {
00125       status_queue_[spi_index].pop();
00126       delete_status_[spi_index] = false;
00127     }
00128     // Check if we need to update a status
00129     if ( status_queue_[spi_index].size() > 0)
00130     {
00131       // check if two cycles has passed since the cmd was received so it contains its answer
00132       if (loop_count_ == status_queue_[spi_index].front().second.loop_number + 2 )
00133       {
00134         // the response has not been received. If the command type is NORMAL
00135         // then the response can be updated (it's INVALID until the SPI responds)
00136         if ( spi_->state_->command_type == RONEX_COMMAND_02000002_COMMAND_TYPE_NORMAL )
00137         {
00138           status_queue_[spi_index].back().second.received = true;
00139           status_queue_[spi_index].back().second.packet =
00140               spi_->state_->info_type.status_data.spi_in[spi_index];
00141         }
00142       }
00143     }
00144     // if no available command then send the NULL command
00145     if ( command_queue_[spi_index].empty() )
00146     {
00147       spi_->nullify_command(spi_index);
00148     }
00149     else
00150     {
00151       // sending the available command
00152 
00153       // first we add the pointer to the command onto the status queue - the status received flag is still false
00154       // as we haven't received the response yet.
00155       status_queue_[spi_index].push(std::pair<SplittedSPICommand, SPIResponse>());
00156       status_queue_[spi_index].back().first = command_queue_[spi_index].front();
00157       status_queue_[spi_index].back().second.received = false;
00158       status_queue_[spi_index].back().second.loop_number = loop_count_;
00159 
00160       // now we copy the command to the hardware interface
00161       copy_splitted_to_cmd_(spi_index);
00162 
00163       // the command will be sent at the end of the iteration,
00164       // removing the command from the queue but not freeing the
00165       // memory yet
00166       command_queue_[spi_index].pop();
00167     }
00168   }
00169 
00170   loop_count_++;
00171 }
00172 
00173 void SPIBaseController::copy_splitted_to_cmd_(uint16_t spi_index)
00174 {
00175   // Mask to avoid setting the CS for the other SPI ports
00176   uint16_t bit_mask_CS = PIN_OUTPUT_STATE_CS_0 | PIN_OUTPUT_STATE_CS_1 | PIN_OUTPUT_STATE_CS_2 | PIN_OUTPUT_STATE_CS_3;
00177   uint16_t bit_mask_no_CS = ~bit_mask_CS;
00178   uint16_t bit_mask_one_CS_bit = PIN_OUTPUT_STATE_CS_0 << spi_index;
00179 
00180   // setting the pre / post pin states (for all the spi outputs)
00181   // First we leave the existing values for the CS bits
00182   spi_->command_->pin_output_states_pre &= bit_mask_CS;
00183   // then we set the values for all the non-CS bits
00184   spi_->command_->pin_output_states_pre |= (cmd_pin_output_states_pre_ & bit_mask_no_CS);
00185   // then we set the value for the CS bit corresponding to the current spi_index
00186   spi_->command_->pin_output_states_pre &= (~bit_mask_one_CS_bit);
00187   spi_->command_->pin_output_states_pre |= (cmd_pin_output_states_pre_ & bit_mask_one_CS_bit);
00188 
00189   // We do the same for the post-state
00190   // First we leave the existing values for the CS bits
00191   spi_->command_->pin_output_states_post &= bit_mask_CS;
00192   // then we set the values for all the non-CS bits
00193   spi_->command_->pin_output_states_post |= (cmd_pin_output_states_post_ & bit_mask_no_CS);
00194   // then we set the value for the CS bit corresponding to the current spi_index
00195   spi_->command_->pin_output_states_post &= (~bit_mask_one_CS_bit);
00196   spi_->command_->pin_output_states_post |= (cmd_pin_output_states_post_ & bit_mask_one_CS_bit);
00197 
00198   // copying the packet data
00199   spi_->command_->spi_out[spi_index].clock_divider = command_queue_[spi_index].front().packet.clock_divider;
00200   spi_->command_->spi_out[spi_index].SPI_config = command_queue_[spi_index].front().packet.SPI_config;
00201   spi_->command_->spi_out[spi_index].inter_byte_gap = command_queue_[spi_index].front().packet.inter_byte_gap;
00202   spi_->command_->spi_out[spi_index].num_bytes = command_queue_[spi_index].front().packet.num_bytes;
00203 
00204   for (size_t i = 0; i < SPI_TRANSACTION_MAX_SIZE; ++i)
00205     spi_->command_->spi_out[spi_index].data_bytes[i] = command_queue_[spi_index].front().packet.data_bytes[i];
00206 }
00207 }  // namespace ronex
00208 
00209 /* For the emacs weenies in the crowd.
00210 Local Variables:
00211    c-basic-offset: 2
00212 End:
00213 */


sr_ronex_controllers
Author(s): Ugo Cupcic, Toni Oliver, Mark Pitchless
autogenerated on Thu Jun 6 2019 21:22:06