drivers/can_copcican_linux/can_copcican_linux.c
changeset 629 b9274b595650
equal deleted inserted replaced
628:9e496a2aadca 629:b9274b595650
       
     1 /*
       
     2 This file is part of CanFestival, a library implementing CanOpen Stack.
       
     3 
       
     4 Copyright (C): Cosateq GmbH & Co.KG
       
     5                http://www.cosateq.com/
       
     6                http://www.scale-rt.com/
       
     7 
       
     8 See COPYING file for copyrights details.
       
     9 
       
    10 This library is free software; you can redistribute it and/or
       
    11 modify it under the terms of the GNU Lesser General Public
       
    12 License as published by the Free Software Foundation; either
       
    13 version 2.1 of the License, or (at your option) any later version.
       
    14 
       
    15 This library is distributed in the hope that it will be useful,
       
    16 but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    18 Lesser General Public License for more details.
       
    19 
       
    20 You should have received a copy of the GNU Lesser General Public
       
    21 License along with this library; if not, write to the Free Software
       
    22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    23 */
       
    24 
       
    25 /*
       
    26 	CAN driver interface for CO-PCICAN card.
       
    27 */
       
    28 
       
    29 #include <stdio.h>
       
    30 #include <unistd.h>
       
    31 #include <fcntl.h>
       
    32 
       
    33 #define NEED_PRINT_MESSAGE
       
    34 #include "can_driver.h"
       
    35 #include "def.h"
       
    36 #include "co_pcicanops.h"
       
    37 
       
    38 /* at the moment not threadsafe :-( */
       
    39 static unsigned char selectedChannelRx = 0, selectedChannelTx = 0;
       
    40 
       
    41 static int TranslateBaudRate( char* optarg )
       
    42 {
       
    43   /* values see documentation of CO-PCICAN */
       
    44   if( !strcmp( optarg, "1M"    ) ) return 0;
       
    45   if( !strcmp( optarg, "800K"  ) ) return 1;
       
    46   if( !strcmp( optarg, "500K"  ) ) return 2;
       
    47   if( !strcmp( optarg, "250K"  ) ) return 3;
       
    48   if( !strcmp( optarg, "125K"  ) ) return 4;
       
    49   if( !strcmp( optarg, "100K"  ) ) return 5;
       
    50   if( !strcmp( optarg, "83.3K" ) ) return 6;
       
    51   if( !strcmp( optarg, "10K"   ) ) return 7;
       
    52 
       
    53   return -1;
       
    54 }
       
    55 
       
    56 /*********CO-PCICAN specific functions to communicate with the board**********/
       
    57 typedef struct
       
    58 {
       
    59   char used;
       
    60   CAN_HANDLE fd;
       
    61   void* receiveTask;
       
    62   void* d;
       
    63 } CANPort; /* taken from drivers/unix.c */
       
    64 
       
    65 int get_fd_of_port( CAN_PORT port )
       
    66 {
       
    67   CANPort *thisPort = (CANPort*)port;
       
    68   CAN_HANDLE thisHandle;
       
    69   int *pfd;
       
    70 
       
    71   if( thisPort == NULL )
       
    72   {
       
    73     MSG("can_copcican_linux: get_fd_of_port(): thisPort is NULL\n");
       
    74     return -1;
       
    75   }
       
    76 
       
    77   thisHandle = thisPort->fd;
       
    78 
       
    79   if( thisHandle == NULL )
       
    80   {
       
    81     MSG("can_copcican_linux: get_fd_of_port(): thisHandle is NULL\n");
       
    82     return -1;
       
    83   }
       
    84 
       
    85   pfd = (int*)thisHandle;
       
    86 
       
    87   /*MSG("can_copcican_linux: get_fd_of_port(): handle is %d\n", *pfd);*/
       
    88 
       
    89   return *pfd;
       
    90 }
       
    91 
       
    92 int co_pcican_enter_run_mode( const int fd )
       
    93 {
       
    94   co_pcican_config_t board_config;
       
    95 
       
    96   if( fd < 0 )
       
    97   {
       
    98     MSG("can_copcican_linux: co_pcican_enter_run_mode(): invalid file descriptor\n");
       
    99     return -1;
       
   100   }
       
   101 
       
   102   memset( &board_config, 0x00, sizeof(co_pcican_config_t) );
       
   103   board_config.opcode = CMDQ_OPC_ENTER_RUN_MODE;
       
   104 
       
   105   return ioctl( fd, CAN_CONFIG, &board_config );
       
   106 }
       
   107 
       
   108 int co_pcican_enter_config_mode( const int fd )
       
   109 {
       
   110   co_pcican_config_t board_config;
       
   111 
       
   112   if( fd < 0 )
       
   113   {
       
   114     MSG("can_copcican_linux: co_pcican_enter_config_mode(): invalid file descriptor\n");
       
   115     return -1;
       
   116   }
       
   117 
       
   118   memset( &board_config, 0x00, sizeof(co_pcican_config_t) );
       
   119   board_config.opcode = CMDQ_OPC_ENTER_CONFIG_MODE;
       
   120 
       
   121   return ioctl( fd, CAN_CONFIG, &board_config );
       
   122 }
       
   123 
       
   124 int co_pcican_select_channel( const unsigned char channel, const unsigned int direction )
       
   125 {
       
   126   if( channel >= NUM_CAN_CHANNELS )
       
   127   {
       
   128     MSG("can_copcican_linux: co_pcican_select_channel(): invalid channel\n");
       
   129     return -1;
       
   130   }
       
   131 
       
   132   /* at the moment not threadsafe :-( */
       
   133   switch( direction )
       
   134   {
       
   135     case RX: selectedChannelRx = channel;
       
   136              break;
       
   137     case TX: selectedChannelTx = channel;
       
   138              break;
       
   139     default: return -1;
       
   140   }
       
   141 
       
   142   return 0;
       
   143 }
       
   144 
       
   145 int co_pcican_configure_selected_channel( const int fd, s_BOARD *board, const unsigned int direction )
       
   146 {
       
   147   co_pcican_config_t board_config;
       
   148   unsigned int selectedChannel;
       
   149 
       
   150   if( fd < 0 )
       
   151   {
       
   152     MSG("can_copcican_linux: co_pcican_configure_selected_channel(): invalid file descriptor\n");
       
   153     return -1;
       
   154   }
       
   155 
       
   156   if( board == NULL )
       
   157   {
       
   158     MSG("can_copcican_linux: co_pcican_configure_selected_channel(): board is NULL\n");
       
   159     return -1;
       
   160   }
       
   161 
       
   162   if( board->baudrate == NULL )
       
   163   {
       
   164     MSG("can_copcican_linux: co_pcican_configure_selected_channel(): baudrate is NULL\n");
       
   165     return -1;
       
   166   }
       
   167 
       
   168   switch( direction )
       
   169   {
       
   170     case RX: selectedChannel = selectedChannelRx;
       
   171              break;
       
   172     case TX: selectedChannel = selectedChannelTx;
       
   173              break;
       
   174     default: selectedChannel = 0xff;
       
   175   }
       
   176 
       
   177   if( selectedChannel >= NUM_CAN_CHANNELS )
       
   178   {
       
   179     MSG("can_copcican_linux: co_pcican_configure_selected_channel(): invalid channel selected\n");
       
   180     return -1;
       
   181   }
       
   182 
       
   183   memset( &board_config, 0x00, sizeof(co_pcican_config_t) );
       
   184   board_config.opcode   = CMDQ_OPC_SET_CONFIG_CHANNEL;
       
   185   board_config.param[0] = selectedChannel;
       
   186   board_config.param[1] = TranslateBaudRate( board->baudrate );
       
   187 
       
   188   return ioctl( fd, CAN_CONFIG, &board_config );
       
   189 }
       
   190 
       
   191 /*********functions which permit to communicate with the board****************/
       
   192 UNS8 canReceive_driver( CAN_HANDLE fd0, Message *m )
       
   193 {
       
   194   co_pcican_message_t canmsg;
       
   195   UNS8 ret = 0;
       
   196   int *pfd = (int*)fd0;
       
   197 
       
   198   if( pfd == NULL )
       
   199   {
       
   200     MSG("can_copcican_linux: canReceive_driver(): file descriptor is NULL\n");
       
   201     return 1;
       
   202   }
       
   203 
       
   204   if( *pfd < 0 )
       
   205   {
       
   206     MSG("can_copcican_linux: canReceive_driver(): invalid file descriptor\n");
       
   207     return 1;
       
   208   }
       
   209 
       
   210   if( selectedChannelRx >= NUM_CAN_CHANNELS )
       
   211   {
       
   212     MSG("can_copcican_linux: canReceive_driver(): invalid channel selected\n");
       
   213     return 1;
       
   214   }
       
   215 
       
   216   if( m == NULL )
       
   217   {
       
   218     MSG("can_copcican_linux: canReceive_driver(): message is NULL\n");
       
   219     return 1;
       
   220   }
       
   221 
       
   222   memset( &canmsg, 0x00, sizeof(co_pcican_message_t) );
       
   223   canmsg.channelnum = selectedChannelRx;
       
   224 
       
   225   ioctl( *pfd, CAN_READ, &canmsg );
       
   226 
       
   227   if( canmsg.timestamp_lo == 0 )
       
   228   {
       
   229     memset( m, 0x00, sizeof(Message) );
       
   230 
       
   231     m->cob_id = 0xffff; /* set to invalid so nothing happens */
       
   232   }
       
   233   else
       
   234   {
       
   235     m->len = canmsg.size;
       
   236     m->cob_id = canmsg.id;
       
   237     m->rtr = canmsg.type & MSG_RTR;
       
   238 
       
   239     if( !m->rtr )
       
   240     {
       
   241       /* this is for safety */
       
   242       if( m->len > 8 )
       
   243         m->len = 8;
       
   244 
       
   245       memcpy( m->data, canmsg.data, m->len);
       
   246     }
       
   247   }
       
   248 
       
   249   return ret;
       
   250 }
       
   251 
       
   252 /***************************************************************************/
       
   253 UNS8 canSend_driver( CAN_HANDLE fd0, Message *m )
       
   254 {
       
   255   co_pcican_message_t canmsg;
       
   256   UNS8 ret = 0;
       
   257   int *pfd = (int*)fd0;
       
   258 
       
   259   if( pfd == NULL )
       
   260   {
       
   261     MSG("can_copcican_linux: canSend_driver(): file descriptor is NULL\n");
       
   262     return 1;
       
   263   }
       
   264 
       
   265   if( *pfd < 0 )
       
   266   {
       
   267     MSG("can_copcican_linux: canSend_driver(): invalid file descriptor\n");
       
   268     return 1;
       
   269   }
       
   270 
       
   271   if( selectedChannelTx >= NUM_CAN_CHANNELS )
       
   272   {
       
   273     MSG("can_copcican_linux: canSend_driver(): invalid channel selected\n");
       
   274     return 1;
       
   275   }
       
   276 
       
   277   if( m == NULL )
       
   278   {
       
   279     MSG("can_copcican_linux: canSend_driver(): message is NULL\n");
       
   280     return 1;
       
   281   }
       
   282 
       
   283   memset( &canmsg, 0x00, sizeof(co_pcican_message_t) );
       
   284   canmsg.channelnum = selectedChannelTx;
       
   285   canmsg.size = m->len;
       
   286   canmsg.id = m->cob_id;
       
   287 
       
   288   if( canmsg.id >= 0x800 )
       
   289     canmsg.type |= MSG_EXT;
       
   290 
       
   291   if( m->rtr )
       
   292   {
       
   293     canmsg.type |= MSG_RTR;
       
   294   }
       
   295   else
       
   296   {
       
   297     /* this is for safety */
       
   298     if( canmsg.size > 8 )
       
   299       canmsg.size = 8;
       
   300 
       
   301     memcpy( canmsg.data, m->data, canmsg.size);
       
   302   }
       
   303 
       
   304   if( ioctl( *pfd, CAN_WRITE, &canmsg ) < 0 )
       
   305     ret = 1;
       
   306 
       
   307   return ret;
       
   308 }
       
   309 
       
   310 /***************************************************************************/
       
   311 CAN_HANDLE canOpen_driver( s_BOARD *board )
       
   312 {
       
   313   int *pfd;
       
   314 
       
   315   if( board == NULL )
       
   316   {
       
   317     MSG("can_copcican_linux: canOpen_driver(): board is NULL\n");
       
   318     return NULL;
       
   319   }
       
   320 
       
   321   if( board->busname == NULL )
       
   322   {
       
   323     MSG("can_copcican_linux: canOpen_driver(): busname is NULL\n");
       
   324     return NULL;
       
   325   }
       
   326 
       
   327   /* create dynamically to avoid global variable */
       
   328   pfd = (int*)malloc( sizeof(int) );
       
   329 
       
   330   if( pfd == NULL )
       
   331   {
       
   332     MSG("can_copcican_linux: canOpen_driver(): file descriptor is NULL\n");
       
   333     return NULL;
       
   334   }
       
   335 
       
   336   *pfd = open( board->busname, O_RDWR, 0 );
       
   337 
       
   338   if( *pfd < 0 )
       
   339   {
       
   340     MSG("can_copcican_linux: canOpen_driver(): invalid file descriptor\n");
       
   341 
       
   342     /* clear resources if open failed */
       
   343     free( pfd );
       
   344     pfd = NULL;
       
   345   }
       
   346 
       
   347   /*MSG("can_copcican_linux: canOpen_driver(): handle is %d\n", *pfd);*/
       
   348 
       
   349   return (CAN_HANDLE)pfd;
       
   350 }
       
   351 
       
   352 /***************************************************************************/
       
   353 int canClose_driver( CAN_HANDLE fd0 )
       
   354 {
       
   355   int *pfd = (int*)fd0;
       
   356 
       
   357   if( pfd == NULL )
       
   358   {
       
   359     MSG("can_copcican_linux: canClose_driver(): file descriptor is NULL\n");
       
   360     return -1;
       
   361   }
       
   362 
       
   363   if( *pfd < 0 )
       
   364   {
       
   365     MSG("can_copcican_linux: canClose_driver(): invalid file descriptor\n");
       
   366     return -1;
       
   367   }
       
   368 
       
   369   close( *pfd );
       
   370   free( pfd );
       
   371   pfd = NULL;
       
   372 
       
   373   selectedChannelRx = 0;
       
   374   selectedChannelTx = 0;
       
   375 
       
   376   return 0;
       
   377 }
       
   378 
       
   379 /***************************************************************************/
       
   380 UNS8 canChangeBaudRate_driver( CAN_HANDLE fd0, char* baud )
       
   381 {
       
   382   s_BOARD board;
       
   383   UNS8 ret = 0;
       
   384   int *pfd = (int*)fd0;
       
   385 
       
   386   if( pfd == NULL )
       
   387   {
       
   388     MSG("can_copcican_linux: canChangeBaudRate_driver(): file descriptor is NULL\n");
       
   389     return 1;
       
   390   }
       
   391 
       
   392   if( *pfd < 0 )
       
   393   {
       
   394     MSG("can_copcican_linux: canChangeBaudRate_driver(): invalid file descriptor\n");
       
   395     return 1;
       
   396   }
       
   397 
       
   398   if( baud == NULL )
       
   399   {
       
   400     MSG("can_copcican_linux: canChangeBaudRate_driver(): baud is NULL\n");
       
   401     return 1;
       
   402   }
       
   403 
       
   404   memset( &board, 0x00, sizeof(s_BOARD) );
       
   405   board.baudrate = baud;
       
   406 
       
   407   if( co_pcican_configure_selected_channel( *pfd, &board, RX ) < 0 )
       
   408     ret = 1;
       
   409 
       
   410   if( co_pcican_configure_selected_channel( *pfd, &board, TX ) < 0 )
       
   411     ret = 1;
       
   412 
       
   413   return ret;
       
   414 }
       
   415