Menu

XenomaiRTCANDriver.h

Go to the documentation of this file.
00001 /*******************************************************************************
00002  *
00003  * Copyright (c) 2008-2010 Michael Schulze <mschulze@ivs.cs.uni-magdeburg.de>
00004  * All rights reserved.
00005  *
00006  *    Redistribution and use in source and binary forms, with or without
00007  *    modification, are permitted provided that the following conditions
00008  *    are met:
00009  *
00010  *    * Redistributions of source code must retain the above copyright
00011  *      notice, this list of conditions and the following disclaimer.
00012  *
00013  *    * Redistributions in binary form must reproduce the above copyright
00014  *      notice, this list of conditions and the following disclaimer in
00015  *      the documentation and/or other materials provided with the
00016  *      distribution.
00017  *
00018  *    * Neither the name of the copyright holders nor the names of
00019  *      contributors may be used to endorse or promote products derived
00020  *      from this software without specific prior written permission.
00021  *
00022  *
00023  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00024  *    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00025  *    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00026  *    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00027  *    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00028  *    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00029  *    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00030  *    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00031  *    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032  *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00033  *    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034  *
00035  *
00036  * $Id$
00037  *
00038  ******************************************************************************/
00039 
00040 #ifndef __XenomaiRTCANDriver_h__
00041 #define __XenomaiRTCANDriver_h__
00042 
00043 #include <stdio.h>
00044 #include <rtdm/rtcan.h>
00045 #include <string.h>
00046 #include <sys/mman.h>
00047 
00048 #include "util/CommandLineParameterGenerator.h"
00049 
00050 #include "debug.h"
00051 
00052 #include "mw/nl/can/canID_LE_PC.h"
00053 
00054 namespace device {
00055     namespace nic {
00056         namespace CAN {
00057 
00058             CLP1(XenomaiRTCANOptions,
00059                  "XenomaiRT CAN Driver",
00060                  "scan,s",
00061                  "The device that is used\n"
00062                  "(e.g. rtcan0 (default))",
00063                  std::string, device, "rtcan0");
00064 
00068             template < typename IDDesc = famouso::mw::nl::CAN::detail::famouso_CAN_ID_LE_PC >
00069             class XenomaiRTCANDriver {
00070                 public:
00071 
00072                     class MOB : private can_frame {
00073                         public:
00074                             typedef famouso::mw::nl::CAN::detail::ID <
00075                             IDDesc
00076                             > IDType;
00077 
00078                             void extended() {
00079                                 can_id |= CAN_EFF_FLAG;
00080                             }
00081                             IDType& id() {
00082                                 return *reinterpret_cast<IDType*>(&can_id);
00083                             }
00084                             uint8_t& len() {
00085                                 return can_dlc;
00086                             }
00087                             void len(uint8_t l) {
00088                                 can_dlc = l;
00089                             }
00090                             uint8_t *data() {
00091                                 return can_frame::data;
00092                             }
00093                             void data(uint8_t *) {}
00094                             uint8_t &data(uint8_t i) {
00095                                 return can_frame::data[i];
00096                             }
00097                             explicit MOB() {
00098                                 can_id = 0;
00099                             }
00100                     };
00101 
00102                     explicit XenomaiRTCANDriver() : _can_socket(0) {
00103                     }
00104 
00105                     ~XenomaiRTCANDriver() {
00106                         rt_dev_close(_can_socket);
00107                     }
00108 
00109                     void report_error_and_exit(int error_value, const char* reporter) {
00110                         const char *error = 0;
00111                         switch (error_value) {
00112                             case -ETIMEDOUT:
00113                                 error = "timed out";
00114                                 break;
00115                             case -EBADF:
00116                                 error = "aborted because socket was closed";
00117                                 break;
00118                             default:
00119                                 error = strerror (-error_value);
00120                                 break;
00121                         }
00122 
00123                         ::logging::log::emit< ::logging::Error>() << reporter
00124                             << error << ::logging::log::endl;
00125                         exit(errno);
00126                     }
00127 
00135                     bool read(MOB& mob) {
00136                         int ret = 0;
00137                         if ((ret = rt_dev_recv(_can_socket, &mob, sizeof(MOB), 0))  != sizeof(MOB) ) {
00138                             report_error_and_exit(ret,"__FILE__:__LINE__ : rt_dev_recv ");
00139                         }
00140                         return true;
00141                     }
00142 
00147                     void write(MOB &mob) {
00148                         /* send frame */
00149                         int ret = 0;
00150                         if ( (ret = rt_dev_send(_can_socket, &mob, sizeof(mob), 0)) != sizeof(MOB)) {
00151                             report_error_and_exit(ret,"__FILE__:__LINE__ : rt_dev_send ");
00152                         }
00153                     }
00154 
00156                     void init() {
00157                         CLP::config::XenomaiRTCANOptions::Parameter param;
00158                         CLP::config::XenomaiRTCANOptions::instance().getParameter(param);
00159                         /* open CAN port */
00160                         struct sockaddr_can addr;
00161                         struct ifreq ifr;
00162                         if ((_can_socket = rt_dev_socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
00163                             ::logging::log::emit< ::logging::Error>()
00164                             << "can't create XenomaiRTCAN socket"
00165                             << ::logging::log::endl;
00166                             exit(errno);
00167                         }
00168                         strcpy(ifr.ifr_name, param.device.c_str());
00169                         if (rt_dev_ioctl(_can_socket, SIOCGIFINDEX, &ifr) < 0) {
00170                             ::logging::log::emit< ::logging::Error>()
00171                             << "SIOCGIFINDEX " << param.device.c_str()
00172                             << "no such CAN device found."
00173                             << ::logging::log::endl;
00174                             exit(errno);
00175                         }
00176                         addr.can_family = AF_CAN;
00177                         addr.can_ifindex = ifr.ifr_ifindex;
00178 
00179                         if (rt_dev_bind(_can_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
00180                             ::logging::log::emit< ::logging::Error>()
00181                             << "can't bind CAN device " << param.device.c_str()
00182                             << ::logging::log::endl;
00183                             exit(errno);
00184                         }
00185                     }
00186 
00187                 private:
00191                     int _can_socket;
00192 
00193             };
00194 
00195             void fnc() __attribute__((constructor));
00196             void fnc() {
00197                 mlockall (MCL_CURRENT | MCL_FUTURE);
00198             }
00199         } /* namespace CAN */
00200     } /* namespace nic */
00201 } /* namespace device */
00202 
00203 #endif
00204