Mercurial > nand-ecoscentric
comparison packages/io/can/current/src/can.c @ 2059:f929becf4af2
CAN driver, from Uwe Kindler
| author | gthomas |
|---|---|
| date | Thu, 25 Aug 2005 13:40:35 +0000 |
| parents | |
| children | c051df3f1083 |
comparison
equal
deleted
inserted
replaced
| 2058:8d6df59beb34 | 2059:f929becf4af2 |
|---|---|
| 1 //========================================================================== | |
| 2 // | |
| 3 // io/can/common/can.c | |
| 4 // | |
| 5 // High level CAN driver | |
| 6 // | |
| 7 //========================================================================== | |
| 8 //####ECOSGPLCOPYRIGHTBEGIN#### | |
| 9 // ------------------------------------------- | |
| 10 // This file is part of eCos, the Embedded Configurable Operating System. | |
| 11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. | |
| 12 // Copyright (C) 2003 Gary Thomas | |
| 13 // | |
| 14 // eCos is free software; you can redistribute it and/or modify it under | |
| 15 // the terms of the GNU General Public License as published by the Free | |
| 16 // Software Foundation; either version 2 or (at your option) any later version. | |
| 17 // | |
| 18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY | |
| 19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 21 // for more details. | |
| 22 // | |
| 23 // You should have received a copy of the GNU General Public License along | |
| 24 // with eCos; if not, write to the Free Software Foundation, Inc., | |
| 25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | |
| 26 // | |
| 27 // As a special exception, if other files instantiate templates or use macros | |
| 28 // or inline functions from this file, or you compile this file and link it | |
| 29 // with other works to produce a work based on this file, this file does not | |
| 30 // by itself cause the resulting work to be covered by the GNU General Public | |
| 31 // License. However the source code for this file must still be made available | |
| 32 // in accordance with section (3) of the GNU General Public License. | |
| 33 // | |
| 34 // This exception does not invalidate any other reasons why a work based on | |
| 35 // this file might be covered by the GNU General Public License. | |
| 36 // | |
| 37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. | |
| 38 // at http://sources.redhat.com/ecos/ecos-license/ | |
| 39 // ------------------------------------------- | |
| 40 //####ECOSGPLCOPYRIGHTEND#### | |
| 41 //========================================================================== | |
| 42 //#####DESCRIPTIONBEGIN#### | |
| 43 // | |
| 44 // Author(s): Uwe Kindler | |
| 45 // Contributors: Uwe Kindler | |
| 46 // Date: 2005-05-12 | |
| 47 // Purpose: Top level CAN driver | |
| 48 // Description: | |
| 49 // | |
| 50 //####DESCRIPTIONEND#### | |
| 51 // | |
| 52 //========================================================================== | |
| 53 | |
| 54 | |
| 55 //========================================================================== | |
| 56 // INCLUDES | |
| 57 //========================================================================== | |
| 58 #include <pkgconf/io.h> | |
| 59 #include <pkgconf/io_can.h> | |
| 60 | |
| 61 #include <cyg/io/io.h> | |
| 62 #include <cyg/io/devtab.h> | |
| 63 #include <cyg/io/can.h> | |
| 64 #include <cyg/infra/cyg_ass.h> // assertion support | |
| 65 #include <cyg/infra/diag.h> // diagnostic output | |
| 66 | |
| 67 | |
| 68 //========================================================================== | |
| 69 // MACROS | |
| 70 //========================================================================== | |
| 71 #ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS | |
| 72 #define CYG_DRV_COND_WAIT(_cond, _time) cyg_cond_timed_wait(_cond, cyg_current_time() + (_time)) | |
| 73 #else | |
| 74 #define CYG_DRV_COND_WAIT(_cond, _time) cyg_drv_cond_wait(_cond) | |
| 75 #endif | |
| 76 | |
| 77 | |
| 78 //========================================================================== | |
| 79 // LOCAL FUNCTIONS | |
| 80 //========================================================================== | |
| 81 // | |
| 82 // Device I/O functions | |
| 83 // | |
| 84 static Cyg_ErrNo can_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32 *len); | |
| 85 static Cyg_ErrNo can_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len); | |
| 86 static cyg_bool can_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info); | |
| 87 static Cyg_ErrNo can_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *xbuf, cyg_uint32 *len); | |
| 88 static Cyg_ErrNo can_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *xbuf, cyg_uint32 *len); | |
| 89 | |
| 90 // | |
| 91 // Callback functions into upper layer driver | |
| 92 // | |
| 93 static void can_init(can_channel *chan); | |
| 94 static void can_rcv_event(can_channel *chan, void *pdata); | |
| 95 static void can_xmt_msg(can_channel *chan, void *pdata); | |
| 96 | |
| 97 // | |
| 98 // Device I/O table | |
| 99 // | |
| 100 DEVIO_TABLE(cyg_io_can_devio, | |
| 101 can_write, | |
| 102 can_read, | |
| 103 can_select, | |
| 104 can_get_config, | |
| 105 can_set_config | |
| 106 ); | |
| 107 | |
| 108 | |
| 109 // | |
| 110 // Callbacks into upper layer driver | |
| 111 // | |
| 112 CAN_CALLBACKS(cyg_io_can_callbacks, | |
| 113 can_init, | |
| 114 can_xmt_msg, | |
| 115 can_rcv_event); | |
| 116 | |
| 117 | |
| 118 //=========================================================================== | |
| 119 // Initialize CAN driver | |
| 120 //=========================================================================== | |
| 121 static void can_init(can_channel *chan) | |
| 122 { | |
| 123 can_cbuf_t *cbuf; | |
| 124 | |
| 125 if (chan->init) | |
| 126 { | |
| 127 return; | |
| 128 } | |
| 129 | |
| 130 cbuf = &chan->in_cbuf; | |
| 131 cbuf->waiting = false; | |
| 132 cbuf->abort = false; | |
| 133 #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING | |
| 134 cbuf->blocking = true; | |
| 135 #endif | |
| 136 cyg_drv_mutex_init(&cbuf->lock); | |
| 137 cyg_drv_cond_init(&cbuf->wait, &cbuf->lock); | |
| 138 | |
| 139 cbuf = &chan->out_cbuf; | |
| 140 cbuf->waiting = false; | |
| 141 cbuf->abort = false; | |
| 142 #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING | |
| 143 cbuf->blocking = true; | |
| 144 #endif | |
| 145 cyg_drv_mutex_init(&cbuf->lock); | |
| 146 cyg_drv_cond_init(&cbuf->wait, &cbuf->lock); | |
| 147 | |
| 148 chan->init = true; | |
| 149 } | |
| 150 | |
| 151 | |
| 152 //=========================================================================== | |
| 153 // Write exactly one CAN message to CAN bus | |
| 154 //=========================================================================== | |
| 155 static Cyg_ErrNo can_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32 *len) | |
| 156 { | |
| 157 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle; | |
| 158 can_channel *chan = (can_channel *)t->priv; | |
| 159 can_lowlevel_funs *funs = chan->funs; | |
| 160 Cyg_ErrNo res = ENOERR; | |
| 161 can_cbuf_t *cbuf = &chan->out_cbuf; | |
| 162 cyg_uint32 size = *len; | |
| 163 | |
| 164 // | |
| 165 // the user need to provide a can message buffer | |
| 166 // | |
| 167 if (*len != sizeof(cyg_can_message)) | |
| 168 { | |
| 169 return -EINVAL; | |
| 170 } | |
| 171 | |
| 172 cyg_drv_mutex_lock(&cbuf->lock); | |
| 173 cbuf->abort = false; | |
| 174 cyg_drv_dsr_lock(); // avoid race condition while testing pointers | |
| 175 | |
| 176 while (size > 0) | |
| 177 { | |
| 178 if (cbuf->data_cnt == cbuf->len) | |
| 179 { | |
| 180 cbuf->waiting = true; // Buffer full - wait for space | |
| 181 funs->start_xmit(chan); // Make sure xmit is running | |
| 182 // | |
| 183 // Check flag: 'start_xmit' may have obviated the need | |
| 184 // to wait | |
| 185 // | |
| 186 if (cbuf->waiting) | |
| 187 { | |
| 188 cbuf->pending += size; // Have this much more to send [eventually] | |
| 189 #if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING) | |
| 190 #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS) | |
| 191 // | |
| 192 // If timeouts are enabled and we use nonblocking calls then we | |
| 193 // can use the timeout values | |
| 194 // | |
| 195 if (!cbuf->blocking) | |
| 196 { | |
| 197 if(!CYG_DRV_COND_WAIT(&cbuf->wait, cbuf->timeout)) | |
| 198 { | |
| 199 cbuf->abort = true; | |
| 200 } | |
| 201 } // if (!cbuf->blocking)# | |
| 202 else | |
| 203 #else // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS) | |
| 204 // | |
| 205 // if this is a nonblocking call then we return immediatelly | |
| 206 // | |
| 207 if (!cbuf->blocking) | |
| 208 { | |
| 209 *len = 0; | |
| 210 res = -EAGAIN; | |
| 211 break; | |
| 212 } | |
| 213 else | |
| 214 #endif // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS) | |
| 215 #endif //defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING) | |
| 216 { | |
| 217 if(!cyg_drv_cond_wait(&cbuf->wait)) | |
| 218 { | |
| 219 cbuf->abort = true; | |
| 220 } | |
| 221 } | |
| 222 cbuf->pending -= size; | |
| 223 if (cbuf->abort) | |
| 224 { | |
| 225 // Give up! | |
| 226 *len -= size; // number of characters actually sent | |
| 227 cbuf->abort = false; | |
| 228 cbuf->waiting = false; | |
| 229 res = -EINTR; | |
| 230 break; | |
| 231 } // if (cbuf->abort) | |
| 232 } // if (cbuf->waiting) | |
| 233 } // if (cbuf->data_cnt == cbuf->len) | |
| 234 else | |
| 235 { | |
| 236 // | |
| 237 // there is enougth space left so we can store additional data | |
| 238 // | |
| 239 cyg_can_message *ptxbuf = (cyg_can_message *)cbuf->pdata; | |
| 240 cyg_can_message *pbuf_message = &ptxbuf[cbuf->put]; | |
| 241 cyg_can_message *pmessage = (cyg_can_message *)_buf; | |
| 242 | |
| 243 *pbuf_message = *pmessage; // copy message | |
| 244 | |
| 245 cbuf->put = (cbuf->put + 1) % cbuf->len; | |
| 246 cbuf->data_cnt++; | |
| 247 size -= sizeof(cyg_can_message); | |
| 248 } | |
| 249 } // while (size > 0) | |
| 250 | |
| 251 (funs->start_xmit)(chan); // Start output as necessary | |
| 252 cyg_drv_dsr_unlock(); | |
| 253 cyg_drv_mutex_unlock(&cbuf->lock); | |
| 254 return res; | |
| 255 } | |
| 256 | |
| 257 | |
| 258 //=========================================================================== | |
| 259 // Read one single CAN event from hw | |
| 260 //=========================================================================== | |
| 261 static Cyg_ErrNo can_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len) | |
| 262 { | |
| 263 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle; | |
| 264 can_channel *chan = (can_channel *)t->priv; | |
| 265 can_cbuf_t *cbuf = &chan->in_cbuf; | |
| 266 cyg_uint32 size = 0; | |
| 267 Cyg_ErrNo res = ENOERR; | |
| 268 | |
| 269 // | |
| 270 // the user need to provide a can event buffer | |
| 271 // | |
| 272 if (*len != sizeof(cyg_can_event)) | |
| 273 { | |
| 274 return -EINVAL; | |
| 275 } | |
| 276 | |
| 277 cyg_drv_mutex_lock(&cbuf->lock); | |
| 278 cbuf->abort = false; | |
| 279 | |
| 280 cyg_drv_dsr_lock(); // avoid race conditions | |
| 281 while (size < *len) | |
| 282 { | |
| 283 // | |
| 284 // if message buffer contains at least one message then read the | |
| 285 // oldest message from buffer and return | |
| 286 // | |
| 287 if (cbuf->data_cnt > 0) | |
| 288 { | |
| 289 cyg_can_event *prxbuf = (cyg_can_event *)cbuf->pdata; | |
| 290 cyg_can_event *pbuf_event = &prxbuf[cbuf->get]; | |
| 291 cyg_can_event *pevent = (cyg_can_event *)_buf; | |
| 292 | |
| 293 *pevent = *pbuf_event; // copy event | |
| 294 | |
| 295 cbuf->get = (cbuf->get + 1) % cbuf->len; | |
| 296 cbuf->data_cnt--; | |
| 297 size += sizeof(cyg_can_event); | |
| 298 } | |
| 299 else | |
| 300 { | |
| 301 // | |
| 302 // if messaeg buffer does not contain any message, then wait until | |
| 303 // a message arrives or return immediatelly if nonblocking calls are | |
| 304 // supported | |
| 305 // | |
| 306 cbuf->waiting = true; | |
| 307 #if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING) | |
| 308 #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS) | |
| 309 // | |
| 310 // If timeouts are enabled and we use nonblocking calls then we | |
| 311 // can use the timeout values | |
| 312 // | |
| 313 if (!cbuf->blocking) | |
| 314 { | |
| 315 if(!CYG_DRV_COND_WAIT(&cbuf->wait, cbuf->timeout)) | |
| 316 { | |
| 317 cbuf->abort = true; | |
| 318 } | |
| 319 } // if (!cbuf->blocking)# | |
| 320 else | |
| 321 #else // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS) | |
| 322 // | |
| 323 // if this is a nonblocking call then we return immediatelly | |
| 324 // | |
| 325 if (!cbuf->blocking) | |
| 326 { | |
| 327 *len = 0; | |
| 328 res = -EAGAIN; | |
| 329 break; | |
| 330 } | |
| 331 else | |
| 332 #endif // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS) | |
| 333 #endif // #if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING) | |
| 334 { | |
| 335 if(!cyg_drv_cond_wait(&cbuf->wait)) | |
| 336 { | |
| 337 cbuf->abort = true; | |
| 338 } | |
| 339 } | |
| 340 | |
| 341 if (cbuf->abort) | |
| 342 { | |
| 343 *len = size; | |
| 344 cbuf->abort = false; | |
| 345 cbuf->waiting = false; | |
| 346 res = -EINTR; | |
| 347 break; | |
| 348 } | |
| 349 } | |
| 350 } // while (size < *len) | |
| 351 cyg_drv_dsr_unlock(); | |
| 352 | |
| 353 cyg_drv_mutex_unlock(&cbuf->lock); | |
| 354 | |
| 355 return res; | |
| 356 } | |
| 357 | |
| 358 | |
| 359 //=========================================================================== | |
| 360 // Query CAN channel configuration data | |
| 361 //=========================================================================== | |
| 362 static Cyg_ErrNo can_get_config(cyg_io_handle_t handle, | |
| 363 cyg_uint32 key, | |
| 364 void *xbuf, | |
| 365 cyg_uint32 *len) | |
| 366 { | |
| 367 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle; | |
| 368 can_channel *chan = (can_channel *)t->priv; | |
| 369 Cyg_ErrNo res = ENOERR; | |
| 370 cyg_can_info_t *pcan_info = (cyg_can_info_t *)xbuf; | |
| 371 can_cbuf_t *out_cbuf = &chan->out_cbuf; | |
| 372 can_cbuf_t *in_cbuf = &chan->in_cbuf; | |
| 373 | |
| 374 switch (key) | |
| 375 { | |
| 376 case CYG_IO_GET_CONFIG_CAN_INFO : | |
| 377 if (*len < sizeof(cyg_can_info_t)) | |
| 378 { | |
| 379 return -EINVAL; | |
| 380 } | |
| 381 *pcan_info = chan->config; | |
| 382 *len = sizeof(chan->config); | |
| 383 break; | |
| 384 // | |
| 385 // return rx/tx buffer sizes and counts | |
| 386 // | |
| 387 case CYG_IO_GET_CONFIG_CAN_BUFFER_INFO : | |
| 388 { | |
| 389 cyg_can_buf_info_t *pbuf_info; | |
| 390 if (*len < sizeof(cyg_can_buf_info_t)) | |
| 391 { | |
| 392 return -EINVAL; | |
| 393 } | |
| 394 | |
| 395 *len = sizeof(cyg_can_buf_info_t); | |
| 396 pbuf_info = (cyg_can_buf_info_t *)xbuf; | |
| 397 pbuf_info->rx_bufsize = in_cbuf->len; | |
| 398 if (pbuf_info->rx_bufsize) | |
| 399 { | |
| 400 pbuf_info->rx_count = in_cbuf->data_cnt ; | |
| 401 } | |
| 402 else | |
| 403 { | |
| 404 pbuf_info->rx_count = 0; | |
| 405 } | |
| 406 pbuf_info->tx_bufsize = out_cbuf->len; | |
| 407 if (pbuf_info->tx_bufsize) | |
| 408 { | |
| 409 pbuf_info->tx_count = out_cbuf->data_cnt; | |
| 410 } | |
| 411 else | |
| 412 { | |
| 413 pbuf_info->tx_count = 0; | |
| 414 } | |
| 415 } | |
| 416 break; // case CYG_IO_GET_CONFIG_CAN_BUFFER_INFO | |
| 417 | |
| 418 #ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS | |
| 419 // | |
| 420 // return current timeouts | |
| 421 // | |
| 422 case CYG_IO_GET_CONFIG_CAN_TIMEOUT : | |
| 423 { | |
| 424 cyg_can_timeout_info_t *ptimeout_info; | |
| 425 if (*len < sizeof(cyg_can_timeout_info_t)) | |
| 426 { | |
| 427 return -EINVAL; | |
| 428 } | |
| 429 | |
| 430 *len = sizeof(cyg_can_timeout_info_t); | |
| 431 ptimeout_info = (cyg_can_timeout_info_t *)xbuf; | |
| 432 | |
| 433 ptimeout_info->rx_timeout = in_cbuf->timeout; | |
| 434 ptimeout_info->tx_timeout = out_cbuf->timeout; | |
| 435 } | |
| 436 break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO | |
| 437 #endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS | |
| 438 | |
| 439 #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING | |
| 440 case CYG_IO_GET_CONFIG_READ_BLOCKING: | |
| 441 { | |
| 442 if (*len < sizeof(cyg_uint32)) | |
| 443 { | |
| 444 return -EINVAL; | |
| 445 } | |
| 446 *(cyg_uint32*)xbuf = (in_cbuf->blocking) ? 1 : 0; | |
| 447 } | |
| 448 break; | |
| 449 | |
| 450 case CYG_IO_GET_CONFIG_WRITE_BLOCKING: | |
| 451 { | |
| 452 if (*len < sizeof(cyg_uint32)) | |
| 453 { | |
| 454 return -EINVAL; | |
| 455 } | |
| 456 *(cyg_uint32*)xbuf = (out_cbuf->blocking) ? 1 : 0; | |
| 457 } | |
| 458 break; | |
| 459 #endif // CYGOPT_IO_CAN_SUPPORT_NONBLOCKING | |
| 460 | |
| 461 default: | |
| 462 res = -EINVAL; | |
| 463 } // switch (key) | |
| 464 | |
| 465 return res; | |
| 466 } | |
| 467 | |
| 468 | |
| 469 //=========================================================================== | |
| 470 // Set CAN channel configuration | |
| 471 //=========================================================================== | |
| 472 static Cyg_ErrNo can_set_config(cyg_io_handle_t handle, | |
| 473 cyg_uint32 key, | |
| 474 const void *xbuf, | |
| 475 cyg_uint32 *len) | |
| 476 { | |
| 477 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle; | |
| 478 can_channel *chan = (can_channel *)t->priv; | |
| 479 Cyg_ErrNo res = ENOERR; | |
| 480 can_lowlevel_funs *funs = chan->funs; | |
| 481 can_cbuf_t *out_cbuf = &chan->out_cbuf; | |
| 482 can_cbuf_t *in_cbuf = &chan->in_cbuf; | |
| 483 | |
| 484 switch (key) | |
| 485 { | |
| 486 #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING | |
| 487 case CYG_IO_SET_CONFIG_READ_BLOCKING: | |
| 488 { | |
| 489 if (*len < sizeof(cyg_uint32) || 0 == in_cbuf->len) | |
| 490 { | |
| 491 return -EINVAL; | |
| 492 } | |
| 493 in_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false; | |
| 494 } | |
| 495 break; | |
| 496 | |
| 497 case CYG_IO_SET_CONFIG_WRITE_BLOCKING: | |
| 498 { | |
| 499 if (*len < sizeof(cyg_uint32) || 0 == out_cbuf->len) | |
| 500 { | |
| 501 return -EINVAL; | |
| 502 } | |
| 503 out_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false; | |
| 504 } | |
| 505 break; | |
| 506 #endif // CYGOPT_IO_CAN_SUPPORT_NONBLOCKING | |
| 507 | |
| 508 #ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS | |
| 509 // | |
| 510 // return current timeouts | |
| 511 // | |
| 512 case CYG_IO_SET_CONFIG_CAN_TIMEOUT : | |
| 513 { | |
| 514 cyg_can_timeout_info_t *ptimeout_info; | |
| 515 if (*len < sizeof(cyg_can_timeout_info_t)) | |
| 516 { | |
| 517 return -EINVAL; | |
| 518 } | |
| 519 | |
| 520 *len = sizeof(cyg_can_timeout_info_t); | |
| 521 ptimeout_info = (cyg_can_timeout_info_t *)xbuf; | |
| 522 | |
| 523 in_cbuf->timeout = ptimeout_info->rx_timeout; | |
| 524 out_cbuf->timeout = ptimeout_info->tx_timeout; | |
| 525 } | |
| 526 break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO | |
| 527 #endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS | |
| 528 | |
| 529 default: | |
| 530 // | |
| 531 // pass down to lower layers | |
| 532 // | |
| 533 res = (funs->set_config)(chan, key, xbuf, len); | |
| 534 } // switch (key) | |
| 535 | |
| 536 return res; | |
| 537 } | |
| 538 | |
| 539 | |
| 540 //=========================================================================== | |
| 541 // Select support for CAN channel | |
| 542 //=========================================================================== | |
| 543 static cyg_bool can_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info) | |
| 544 { | |
| 545 // | |
| 546 // do nothing here because we currently do not support select | |
| 547 // | |
| 548 return true; | |
| 549 } | |
| 550 | |
| 551 | |
| 552 //=========================================================================== | |
| 553 // Callback for received events | |
| 554 //=========================================================================== | |
| 555 static void can_rcv_event(can_channel *chan, void *pdata) | |
| 556 { | |
| 557 can_cbuf_t *cbuf = &chan->in_cbuf; | |
| 558 cyg_can_event *prxbuf = (cyg_can_event *)cbuf->pdata; | |
| 559 | |
| 560 // | |
| 561 // cbuf is a ring buffer - if the buffer is full, then we overwrite the | |
| 562 // oldest message in buffer so the user will always get the actual and | |
| 563 // last state of the external hardware that is connected to the | |
| 564 // CAN bus. | |
| 565 // | |
| 566 if (chan->funs->getevent(chan, &prxbuf[cbuf->put], pdata)) | |
| 567 { | |
| 568 if (cbuf->data_cnt < cbuf->len) | |
| 569 { | |
| 570 cbuf->data_cnt++; | |
| 571 } | |
| 572 else | |
| 573 { | |
| 574 // | |
| 575 // the buffer is full but a new message arrived. We store this new | |
| 576 // message and overwrite the oldest one, but at least we tell the user | |
| 577 // that there is an overrun in RX queue | |
| 578 // | |
| 579 prxbuf[cbuf->put].flags |= CYGNUM_CAN_EVENT_OVERRUN_RX; | |
| 580 cbuf->get = (cbuf->get + 1) % cbuf->len; | |
| 581 } | |
| 582 | |
| 583 cbuf->put = (cbuf->put + 1) % cbuf->len; | |
| 584 | |
| 585 if (cbuf->waiting) | |
| 586 { | |
| 587 cbuf->waiting = false; | |
| 588 cyg_drv_cond_broadcast(&cbuf->wait); | |
| 589 } | |
| 590 } | |
| 591 } | |
| 592 | |
| 593 | |
| 594 //=========================================================================== | |
| 595 // Callback function for transmit events | |
| 596 //=========================================================================== | |
| 597 static void can_xmt_msg(can_channel *chan, void *pdata) | |
| 598 { | |
| 599 can_cbuf_t *cbuf = &chan->out_cbuf; | |
| 600 can_lowlevel_funs *funs = chan->funs; | |
| 601 cyg_can_message *ptxbuf = (cyg_can_message *)cbuf->pdata; | |
| 602 cyg_can_message *pbuf_txmsg; | |
| 603 | |
| 604 // | |
| 605 // transmit messages as long as there are messages in the buffer | |
| 606 // | |
| 607 while (cbuf->data_cnt > 0) | |
| 608 { | |
| 609 pbuf_txmsg = &ptxbuf[cbuf->get]; | |
| 610 | |
| 611 if (funs->putmsg(chan, pbuf_txmsg, pdata)) | |
| 612 { | |
| 613 cbuf->get = (cbuf->get + 1) % cbuf->len; | |
| 614 cbuf->data_cnt--; | |
| 615 } | |
| 616 else | |
| 617 { | |
| 618 // | |
| 619 // we are here because the hardware is busy at the moment and | |
| 620 // we can't send another message - now we check if there is already | |
| 621 // some space in buffer so we can wakeup the writer | |
| 622 // | |
| 623 if ((cbuf->len - cbuf->data_cnt) > 0) | |
| 624 { | |
| 625 if (cbuf->waiting) | |
| 626 { | |
| 627 cbuf->waiting = false; | |
| 628 cyg_drv_cond_broadcast(&cbuf->wait); | |
| 629 } | |
| 630 } | |
| 631 return; | |
| 632 } | |
| 633 } // while (cbuf->data_cnt > 0) | |
| 634 funs->stop_xmit(chan); // Done with transmit | |
| 635 | |
| 636 if (cbuf->waiting) | |
| 637 { | |
| 638 cbuf->waiting = false; | |
| 639 cyg_drv_cond_broadcast(&cbuf->wait); | |
| 640 } | |
| 641 } | |
| 642 | |
| 643 | |
| 644 //--------------------------------------------------------------------------- | |
| 645 // end of can.c |
