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 
00027 namespace ronex
00028 {
00029   SPIBaseController::SPIBaseController()
00030     : loop_count_(0), command_queue_(NUM_SPI_OUTPUTS), status_queue_(NUM_SPI_OUTPUTS)
00031   {}
00032 
00033   bool SPIBaseController::init(ros_ethercat_model::RobotState* robot, ros::NodeHandle &n)
00034   {
00035     return pre_init_(robot, n);
00036   }
00037 
00038   bool SPIBaseController::pre_init_(ros_ethercat_model::RobotState* robot, ros::NodeHandle &n)
00039   {
00040     assert(robot);
00041     node_ = n;
00042 
00043     std::string ronex_id;
00044     if (!node_.getParam("ronex_id", ronex_id)) {
00045       ROS_ERROR("No RoNeX ID given (namespace: %s)", node_.getNamespace().c_str());
00046       return false;
00047     }
00048 
00049     //get the path from the parameters
00050     std::string path;
00051     int parameter_id = get_ronex_param_id(ronex_id);
00052     {
00053       if( parameter_id == -1 )
00054       {
00055         ROS_ERROR_STREAM("Could not find the RoNeX id in the parameter server: " << ronex_id << " not loading the controller.");
00056         return false;
00057       }
00058       else
00059       {
00060         std::stringstream ss;
00061         ss << "/ronex/devices/" << parameter_id << "/path";
00062         if( !ros::param::get(ss.str(), path) )
00063         {
00064           ROS_ERROR_STREAM("Couldn't read the parameter " << ss.str() << " from the parameter server. Not loading the controller.");
00065           return false;
00066         }
00067       }
00068     }
00069     topic_prefix_ = path;
00070 
00071     spi_ = static_cast<ronex::SPI*>( robot->getCustomHW(path) );
00072     if( spi_ == NULL)
00073     {
00074       ROS_ERROR_STREAM("Could not find RoNeX module: " << ronex_id << " not loading the controller");
00075       return false;
00076     }
00077 
00078     return true;
00079   }
00080 
00081   void SPIBaseController::starting(const ros::Time&)
00082   {
00083     //@TODO: implement starting
00084   }
00085 
00089   void SPIBaseController::update(const ros::Time&, const ros::Duration&)
00090   {
00091     for (uint16_t spi_index = 0; spi_index < NUM_SPI_OUTPUTS; ++spi_index)
00092     {
00093       //Check if we need to update a status
00094       if( status_queue_[spi_index].size() > 0)
00095       {
00096         if( status_queue_[spi_index].front().second == NULL )
00097         {
00098           if(new_command)
00099           {
00100             new_command = false;
00101             spi_->nullify_command(spi_index);
00102             continue;
00103           }
00104 
00105           //the response has not been received. If the command type is NORMAL
00106           // then the response can be updated (it's INVALID until the SPI responds)
00107           if( spi_->state_->command_type == RONEX_COMMAND_02000002_COMMAND_TYPE_NORMAL );
00108           {
00109             status_queue_[spi_index].front().second = new SPI_PACKET_IN(spi_->state_->info_type.status_data.spi_in[spi_index]);
00110           }
00111         }
00112       }
00113       //if no available command then send the NULL command
00114       if( command_queue_[spi_index].empty() )
00115         spi_->nullify_command(spi_index);
00116       else
00117       {
00118         //sending the available command
00119 
00120         //first we add the pointer to the command onto the status queue - the status is still NULL
00121         // as we haven't received the response yet.
00122         status_queue_[spi_index].push(std::pair<SplittedSPICommand*, SPI_PACKET_IN*>());
00123         status_queue_[spi_index].front().first = command_queue_[spi_index].front();
00124 
00125         //now we copy the command to the hardware interface
00126         copy_splitted_to_cmd_(spi_index);
00127 
00128         new_command = true;
00129 
00130         //the command will be sent at the end of the iteration,
00131         // removing the command from the queue but not freeing the
00132         // memory yet
00133         command_queue_[spi_index].pop();
00134       }
00135     }
00136   }
00137 
00138   void SPIBaseController::copy_splitted_to_cmd_(uint16_t spi_index)
00139   {
00140     //Mask to avoid setting the CS for the other SPI ports
00141     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;
00142     uint16_t bit_mask_no_CS = ~bit_mask_CS;
00143     uint16_t bit_mask_one_CS_bit = PIN_OUTPUT_STATE_CS_0 << spi_index;
00144 
00145     //setting the pre / post pin states (for all the spi outputs)
00146     //First we leave the existing values for the CS bits
00147     spi_->command_->pin_output_states_pre &= bit_mask_CS;
00148     //then we set the values for all the non-CS bits
00149     spi_->command_->pin_output_states_pre |= (cmd_pin_output_states_pre_ & bit_mask_no_CS);
00150     //then we set the value for the CS bit corresponding to the current spi_index
00151     spi_->command_->pin_output_states_pre &= (~bit_mask_one_CS_bit);
00152     spi_->command_->pin_output_states_pre |= (cmd_pin_output_states_pre_ & bit_mask_one_CS_bit);
00153 
00154     //We do the same for the post-state
00155     //First we leave the existing values for the CS bits
00156     spi_->command_->pin_output_states_post &= bit_mask_CS;
00157     //then we set the values for all the non-CS bits
00158     spi_->command_->pin_output_states_post |= (cmd_pin_output_states_post_ & bit_mask_no_CS);
00159     //then we set the value for the CS bit corresponding to the current spi_index
00160     spi_->command_->pin_output_states_post &= (~bit_mask_one_CS_bit);
00161     spi_->command_->pin_output_states_post |= (cmd_pin_output_states_post_ & bit_mask_one_CS_bit);
00162 
00163     //copying the packet data
00164     spi_->command_->spi_out[spi_index].clock_divider = command_queue_[spi_index].front()->packet.clock_divider;
00165     spi_->command_->spi_out[spi_index].SPI_config = command_queue_[spi_index].front()->packet.SPI_config;
00166     spi_->command_->spi_out[spi_index].inter_byte_gap = command_queue_[spi_index].front()->packet.inter_byte_gap;
00167     spi_->command_->spi_out[spi_index].num_bytes = command_queue_[spi_index].front()->packet.num_bytes;
00168 
00169     for(size_t i = 0; i < SPI_TRANSACTION_MAX_SIZE; ++i)
00170       spi_->command_->spi_out[spi_index].data_bytes[i] = command_queue_[spi_index].front()->packet.data_bytes[i];
00171   }
00172 }
00173 
00174 /* For the emacs weenies in the crowd.
00175 Local Variables:
00176    c-basic-offset: 2
00177 End:
00178 */


sr_ronex_controllers
Author(s): Ugo Cupcic, Toni Oliver, Mark Pitchless
autogenerated on Fri Aug 28 2015 13:12:37