Details | Last modification | View Log | SVN | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 59 | jimmy | 1 | /** |
| 142 | jimmy | 2 | * CAN communication interface. This is a general, high-level interface for CAN |
| 3 | * communication. Underlying CAN controllers are abstracted by this interface, |
||
| 4 | * so the application needs not work directly with the CAN controllers. |
||
| 59 | jimmy | 5 | * |
| 142 | jimmy | 6 | * The interface is fully queued in both directions. Both queues can configured |
| 7 | * in terms of size, and can also be disabled completely to save both RAM and |
||
| 8 | * FLASH space (the queue routines are removed by preprocessor when queues |
||
| 9 | * are disabled). When queues are enabled, the application has to call |
||
| 10 | * Can_Service as often as possible, so messages can be moved between the CAN |
||
| 11 | * controller and the message queues. This might be handled by interrupts in |
||
| 12 | * future. When queues are disabled, on the other hand, the application has |
||
| 13 | * to call Can_Receive as often as possible in order not to loose any messages. |
||
| 59 | jimmy | 14 | * |
| 142 | jimmy | 15 | * @date 2006-11-21 |
| 16 | * |
||
| 59 | jimmy | 17 | * @author Jimmy Myhrman |
| 18 | * |
||
| 19 | */ |
||
| 20 | |||
| 21 | /*----------------------------------------------------------------------------- |
||
| 22 | * Includes |
||
| 23 | *---------------------------------------------------------------------------*/ |
||
| 24 | #include <string.h> |
||
| 25 | #include <can.h> |
||
| 142 | jimmy | 26 | #include <mcu.h> |
| 27 | #include <stdio.h> |
||
| 28 | #include <timebase.h> |
||
| 29 | #include <assert.h> |
||
| 30 | #if CAN_CONTROLLER == CAN_CONTROLLER_MCP2515 |
||
| 31 | #include "mcp2515.h" |
||
| 32 | #endif |
||
| 59 | jimmy | 33 | |
| 34 | |||
| 142 | jimmy | 35 | /*----------------------------------------------------------------------------- |
| 36 | * Prerequisites |
||
| 37 | *---------------------------------------------------------------------------*/ |
||
| 38 | #ifndef CAN_CONTROLLER |
||
| 39 | #error CAN_CONTROLLER not specified! Edit can_cfg.h ! |
||
| 59 | jimmy | 40 | #endif |
| 41 | |||
| 142 | jimmy | 42 | #ifndef CAN_BITRATE |
| 43 | #error CAN_BITRATE not defined! Edit can_cfg.h ! |
||
| 44 | #endif |
||
| 59 | jimmy | 45 | |
| 142 | jimmy | 46 | #ifndef CAN_QUEUE_SIZE_RX |
| 47 | #error CAN_QUEUE_SIZE_RX not defined! Edit can_cfg.h ! |
||
| 48 | #endif |
||
| 49 | |||
| 50 | #ifndef CAN_QUEUE_SIZE_TX |
||
| 51 | #error CAN_QUEUE_SIZE_TX not defined! Edit can_cfg.h ! |
||
| 52 | #endif |
||
| 53 | |||
| 54 | #ifndef CAN_CONTROLLER_NR_TX_BUFFERS |
||
| 55 | #error CAN_CONTROLLER_NR_TX_BUFFERS not defined! Edit can_cfg.h ! |
||
| 56 | #endif |
||
| 57 | |||
| 58 | #ifndef CAN_CONTROLLER_NR_RX_BUFFERS |
||
| 59 | #error CAN_CONTROLLER_NR_RX_BUFFERS not defined! Edit can_cfg.h ! |
||
| 60 | #endif |
||
| 61 | |||
| 62 | |||
| 59 | jimmy | 63 | /*----------------------------------------------------------------------------- |
| 142 | jimmy | 64 | * Type Definitions |
| 59 | jimmy | 65 | *---------------------------------------------------------------------------*/ |
| 66 | |||
| 142 | jimmy | 67 | #if (CAN_QUEUE_SIZE_TX > 0) || (CAN_QUEUE_SIZE_RX > 0) |
| 59 | jimmy | 68 | /** |
| 142 | jimmy | 69 | * CAN Message Queue Type. Stores and manages several CAN messages |
| 70 | * in a FIFO structure. |
||
| 71 | */ |
||
| 72 | typedef struct { |
||
| 73 | Can_Message_t *dataPtr; /* pointer to the data storage */ |
||
| 74 | uint8_t head; /* current OUTPUT position */ |
||
| 75 | uint8_t tail; /* current INPUT position */ |
||
| 76 | uint8_t nrElements; /* nr of elements currently queued */ |
||
| 77 | uint8_t size; /* total size of the queue */ |
||
| 78 | } Can_MessageQueue_t; |
||
| 79 | #endif |
||
| 80 | |||
| 81 | |||
| 82 | /*----------------------------------------------------------------------------- |
||
| 83 | * Private (static) variables |
||
| 84 | *---------------------------------------------------------------------------*/ |
||
| 85 | |||
| 86 | #if CAN_QUEUE_SIZE_TX > 0 |
||
| 87 | /* TX queue object and static memory storage buffer for this queue */ |
||
| 88 | static Can_MessageQueue_t canTxQueue; |
||
| 89 | static Can_Message_t canTxQueueDataStorage[CAN_QUEUE_SIZE_TX]; |
||
| 90 | #endif |
||
| 91 | #if CAN_QUEUE_SIZE_RX > 0 |
||
| 92 | /* RX queue object and static memory storage buffer for this queue */ |
||
| 93 | static Can_MessageQueue_t canRxQueue; |
||
| 94 | static Can_Message_t canRxQueueDataStorage[CAN_QUEUE_SIZE_RX]; |
||
| 95 | #endif |
||
| 96 | |||
| 97 | |||
| 98 | /*----------------------------------------------------------------------------- |
||
| 99 | * Private Function Prototypes |
||
| 100 | *---------------------------------------------------------------------------*/ |
||
| 101 | |||
| 102 | /* functions that deal with the controller hardware */ |
||
| 103 | static Can_Return_t Can_SendImmediately(Can_Message_t *msg); |
||
| 104 | static Can_Return_t Can_ReceiveFromController(Can_Message_t *msg, uint8_t rxBuffer); |
||
| 105 | static uint8_t Can_MessagesAvailableInController(void); |
||
| 106 | static Can_Return_t Can_ControllerCheckError(void); |
||
| 107 | |||
| 108 | #if (CAN_QUEUE_SIZE_TX > 0) || (CAN_QUEUE_SIZE_RX > 0) |
||
| 109 | /* functions that deal with the message queues */ |
||
| 110 | static void Can_QueueInit(Can_MessageQueue_t *q, uint8_t size, Can_Message_t *dataPtr); |
||
| 111 | static Can_Message_t* Can_QueueInsert(Can_MessageQueue_t *q); |
||
| 112 | static Can_Message_t* Can_QueueReadTailPtr(Can_MessageQueue_t *q); |
||
| 113 | static void Can_QueueRemoveTail(Can_MessageQueue_t *q); |
||
| 114 | #endif |
||
| 115 | |||
| 116 | |||
| 117 | /*----------------------------------------------------------------------------- |
||
| 118 | * Public Functions |
||
| 119 | *---------------------------------------------------------------------------*/ |
||
| 120 | |||
| 121 | /** |
||
| 127 | jimmy | 122 | * Initializes the CAN interface. Edit can_cfg.h to choose bitrate. |
| 59 | jimmy | 123 | * |
| 124 | * @return |
||
| 125 | * CAN_OK if initialization was successful. |
||
| 142 | jimmy | 126 | * CAN_INIT_FAIL_SET_BITRATE if bitrate could not be set correctly. |
| 127 | * CAN_INIT_FAIL_SET_MODE if the controller could not be set to normal operation mode. |
||
| 128 | * CAN_INIT_FAIL in case of general error. |
||
| 59 | jimmy | 129 | */ |
| 127 | jimmy | 130 | Can_Return_t Can_Init() { |
| 142 | jimmy | 131 | #if CAN_QUEUE_SIZE_TX > 0 |
| 132 | /* initialize TX queue */ |
||
| 133 | Can_QueueInit(&canTxQueue, CAN_QUEUE_SIZE_TX, canTxQueueDataStorage); |
||
| 134 | #endif |
||
| 135 | #if CAN_QUEUE_SIZE_RX > 0 |
||
| 136 | /* initialize RX queue */ |
||
| 137 | Can_QueueInit(&canRxQueue, CAN_QUEUE_SIZE_RX, canRxQueueDataStorage); |
||
| 138 | #endif |
||
| 139 | |||
| 140 | #if CAN_CONTROLLER == CAN_CONTROLLER_NULL |
||
| 141 | /* |
||
| 142 | * Initialize null device. |
||
| 143 | */ |
||
| 144 | return CAN_OK; |
||
| 145 | #endif |
||
| 146 | |||
| 147 | #if CAN_CONTROLLER == CAN_CONTROLLER_MCP2515 |
||
| 148 | /* |
||
| 149 | * Initialize MCP2515 device. |
||
| 150 | */ |
||
| 151 | if (MCP2515_Init(CAN_BITRATE) != MCP2515_OK) { |
||
| 152 | return CAN_FAIL; |
||
| 153 | } |
||
| 154 | if (MCP2515_SetCanCtrlMode(MODE_NORMAL) != MCP2515_OK) { |
||
| 155 | return CAN_FAIL; |
||
| 156 | } |
||
| 157 | return CAN_OK; |
||
| 158 | #endif |
||
| 159 | |||
| 160 | return CAN_FAIL; |
||
| 161 | } |
||
| 59 | jimmy | 162 | |
| 142 | jimmy | 163 | |
| 164 | /** |
||
| 165 | * Sends a CAN message. The message will be put into the transmission queue, |
||
| 166 | * and hence, it might not be sent immediately. If the queue is full, the |
||
| 167 | * message will not be taken care of, and CAN_FAIL is returned. |
||
| 168 | * |
||
| 169 | * @param msg |
||
| 170 | * Pointer to the CAN message. |
||
| 171 | * |
||
| 172 | * @return |
||
| 173 | * CAN_OK if the message was successfully enqueued. |
||
| 174 | * CAN_FAIL if the transmission queue is full. |
||
| 175 | */ |
||
| 176 | Can_Return_t Can_Send(Can_Message_t *msg) { |
||
| 177 | #if CAN_QUEUE_SIZE_TX == 0 |
||
| 178 | /* TX queue is disabled, so send immediately */ |
||
| 179 | return Can_SendImmediately(msg); |
||
| 180 | #else |
||
| 181 | #if 0 |
||
| 182 | printf("Can_Send()\n\r"); |
||
| 183 | printf(" queue size before = %u\n\r", canTxQueue.nrElements); |
||
| 184 | #endif |
||
| 185 | /* check if there is room available in the tx queue */ |
||
| 186 | if (canTxQueue.nrElements >= canTxQueue.size) { |
||
| 187 | #if 0 |
||
| 188 | printf(" TX queue full!\n\r"); |
||
| 189 | #endif |
||
| 190 | return CAN_FAIL; |
||
| 191 | } |
||
| 192 | /* put message in queue */ |
||
| 193 | Can_Message_t *ptr = Can_QueueInsert(&canTxQueue); |
||
| 194 | memcpy(ptr, msg, sizeof(Can_Message_t)); |
||
| 195 | #if 0 |
||
| 196 | printf(" queue size after = %u\n\r", canTxQueue.nrElements); |
||
| 197 | #endif |
||
| 198 | return CAN_OK; |
||
| 199 | #endif |
||
| 200 | } |
||
| 201 | |||
| 202 | |||
| 203 | /** |
||
| 204 | * Services the CAN subsystem. Messages waiting in the transmission queue |
||
| 205 | * will be transmitted if the controller is not busy, and any messages |
||
| 206 | * received by the controller will be moved from the controller buffers |
||
| 207 | * into the internal reception queue. |
||
| 208 | */ |
||
| 209 | void Can_Service() { |
||
| 210 | #if CAN_QUEUE_SIZE_TX > 0 |
||
| 211 | /* try to transmit messages waiting in the transmission queue */ |
||
| 212 | for (uint8_t i=0; i<CAN_CONTROLLER_NR_TX_BUFFERS; i++) { |
||
| 213 | if (canTxQueue.nrElements > 0) { |
||
| 214 | #if 0 |
||
| 215 | printf("msg in TX queue. trying to send...\n"); |
||
| 216 | #endif |
||
| 217 | /* ensure the queue operations are atomic */ |
||
| 218 | Mcu_DisableIRQ(); |
||
| 219 | Can_Message_t *txMsg = Can_QueueReadTailPtr(&canTxQueue); |
||
| 220 | if (Can_SendImmediately(txMsg) == CAN_OK) { |
||
| 221 | /* transmission OK, remove from queue */ |
||
| 222 | Can_QueueRemoveTail(&canTxQueue); |
||
| 223 | } |
||
| 224 | Mcu_EnableIRQ(); |
||
| 225 | } |
||
| 226 | else { |
||
| 227 | /* quit the loop if the queue is empty */ |
||
| 228 | break; |
||
| 229 | } |
||
| 230 | } |
||
| 231 | #endif |
||
| 59 | jimmy | 232 | |
| 142 | jimmy | 233 | #if CAN_QUEUE_SIZE_RX > 0 |
| 234 | /* move all received messages from CAN controller to reception queue */ |
||
| 235 | Can_Message_t rxMsg; |
||
| 236 | /* all RX buffers have to be checked (and in correct order) */ |
||
| 237 | for (uint8_t buf=0; buf<CAN_CONTROLLER_NR_RX_BUFFERS; buf++) { |
||
| 238 | /* if buffer contains a message, handle it */ |
||
| 239 | if (Can_ReceiveFromController(&rxMsg, buf) == CAN_OK) { |
||
| 240 | /* ensure the queue operations are atomic */ |
||
| 241 | Mcu_DisableIRQ(); |
||
| 242 | /* try to get access to the queue */ |
||
| 243 | Can_Message_t *destPtr = Can_QueueInsert(&canRxQueue); |
||
| 244 | /* if we can insert into queue, copy the message */ |
||
| 245 | if (destPtr != 0) { |
||
| 246 | memcpy(destPtr, &rxMsg, sizeof(Can_Message_t)); |
||
| 247 | } |
||
| 248 | else { |
||
| 249 | /* otherwise, the received message will be discarded... */ |
||
| 250 | } |
||
| 251 | Mcu_EnableIRQ(); |
||
| 252 | } |
||
| 253 | } |
||
| 254 | #endif |
||
| 255 | |||
| 256 | /* TODO: check error status in controller */ |
||
| 59 | jimmy | 257 | } |
| 258 | |||
| 259 | |||
| 260 | /** |
||
| 142 | jimmy | 261 | * Receives a CAN message that is waiting in the reception queue. If no |
| 262 | * messages have been received, CAN_NO_MSG_AVAILABLE is returned. |
||
| 263 | * Otherwise, a CAN message is copied into the specified message buffer |
||
| 264 | * and deleted from the internal message reception queue. In this case, |
||
| 265 | * CAN_OK is returned. |
||
| 266 | * |
||
| 267 | * @param msg |
||
| 268 | * Pointer to the message storage buffer into which the message |
||
| 269 | * should be copied. |
||
| 270 | * |
||
| 271 | * @return |
||
| 272 | * CAN_OK if a received message was successfully copied into the buffer. |
||
| 273 | * CAN_NO_MSG_AVAILABLE if no messages are available. |
||
| 274 | */ |
||
| 275 | Can_Return_t Can_Receive(Can_Message_t *msg) { |
||
| 276 | |||
| 277 | #if CAN_QUEUE_SIZE_RX > 0 |
||
| 278 | /* |
||
| 279 | * RX queue is enabled, so try to get message from queue. |
||
| 280 | */ |
||
| 281 | Can_Message_t *pSrc; /* Source pointer */ |
||
| 282 | /* Check if there is anything available in the RxQueue */ |
||
| 283 | if (canRxQueue.nrElements == 0) { |
||
| 284 | return CAN_NO_MSG_AVAILABLE; |
||
| 285 | } |
||
| 286 | /* ensure the queue operations are atomic */ |
||
| 287 | Mcu_DisableIRQ(); |
||
| 288 | pSrc = Can_QueueReadTailPtr(&canRxQueue); |
||
| 289 | /* copy frame from queue, and then remove from queue */ |
||
| 290 | memcpy(msg, pSrc, sizeof(Can_Message_t)); |
||
| 291 | Can_QueueRemoveTail(&canRxQueue); |
||
| 292 | Mcu_EnableIRQ(); |
||
| 293 | /* a message has successfully been copied and removed from queue */ |
||
| 294 | return CAN_OK; |
||
| 295 | #else |
||
| 296 | /* |
||
| 297 | * RX queue is disabled, so try to get message from controller. |
||
| 298 | * We don't know which buffer to get the message from, so best |
||
| 299 | * we can do is to get from buf0 first time, and then increase |
||
| 300 | * buffer number at each call, finally wrapping around at |
||
| 301 | * CAN_CONTROLLER_NR_RX_BUFFERS. |
||
| 302 | */ |
||
| 303 | static uint8_t rxBuffer = 0; |
||
| 304 | /* worst case is that we need to check all available rx buffers in order to find a message */ |
||
| 305 | for (uint8_t i=0; i<CAN_CONTROLLER_NR_RX_BUFFERS; i++) { |
||
| 306 | /* is there a message available in this buffer? */ |
||
| 307 | if (Can_ReceiveFromController(msg, rxBuffer) == CAN_OK) { |
||
| 308 | /* increase buffer number and return the message */ |
||
| 309 | rxBuffer = (rxBuffer + 1) % CAN_CONTROLLER_NR_RX_BUFFERS; |
||
| 310 | return CAN_OK; |
||
| 311 | } |
||
| 312 | /* increase buffer number so we can check next buffer */ |
||
| 313 | rxBuffer = (rxBuffer + 1) % CAN_CONTROLLER_NR_RX_BUFFERS; |
||
| 314 | } |
||
| 315 | /* all buffers were checked, but no message found */ |
||
| 316 | return CAN_NO_MSG_AVAILABLE; |
||
| 317 | #endif |
||
| 318 | } |
||
| 319 | |||
| 320 | |||
| 321 | |||
| 322 | /*----------------------------------------------------------------------------- |
||
| 323 | * Private Functions |
||
| 324 | *---------------------------------------------------------------------------*/ |
||
| 325 | |||
| 326 | /** |
||
| 327 | * Sends a CAN message immediately with the controller hardware. If the CAN |
||
| 328 | * controller is busy, the function will return CAN_SEND_FAIL_TX_BUSY. |
||
| 59 | jimmy | 329 | * |
| 330 | * @param msg |
||
| 331 | * Pointer to the CAN message storage buffer. |
||
| 142 | jimmy | 332 | * |
| 59 | jimmy | 333 | * @return |
| 142 | jimmy | 334 | * CAN_OK if the message was successfully sent to the controller. |
| 335 | * CAN_FAIL if the controller is busy. |
||
| 59 | jimmy | 336 | */ |
| 142 | jimmy | 337 | static Can_Return_t Can_SendImmediately(Can_Message_t* msg) { |
| 338 | #if CAN_CONTROLLER == CAN_CONTROLLER_NULL |
||
| 339 | /* |
||
| 340 | * Send with null device. |
||
| 341 | */ |
||
| 342 | return CAN_OK; |
||
| 343 | #endif |
||
| 59 | jimmy | 344 | |
| 142 | jimmy | 345 | #if CAN_CONTROLLER == CAN_CONTROLLER_MCP2515 |
| 346 | /* |
||
| 347 | * Send with MCP2515 device. |
||
| 348 | */ |
||
| 349 | uint8_t res, txbuf_n; |
||
| 350 | res = MCP2515_GetNextFreeTXBuf(&txbuf_n); // info = addr. |
||
| 351 | if (res == MCP_ALLTXBUSY) { |
||
| 352 | return CAN_FAIL; |
||
| 353 | } |
||
| 354 | MCP2515_WriteCanMsg(txbuf_n, msg); |
||
| 355 | MCP2515_StartTransmit(txbuf_n); |
||
| 356 | return CAN_OK; |
||
| 357 | #endif |
||
| 59 | jimmy | 358 | } |
| 359 | |||
| 360 | |||
| 361 | /** |
||
| 142 | jimmy | 362 | * Receives a CAN message from the CAN controller hardware. |
| 59 | jimmy | 363 | * |
| 364 | * @param msg |
||
| 142 | jimmy | 365 | * Pointer to the message storage buffer into which the message should be copied. |
| 366 | * |
||
| 367 | * @param rxBuffer |
||
| 368 | * Identifies the RX buffer in the controller. Range is [0,CAN_CONTROLLER_NR_RX_BUFFERS-1]. |
||
| 369 | * |
||
| 59 | jimmy | 370 | * @return |
| 371 | * CAN_OK if a received message was successfully copied into the buffer. |
||
| 142 | jimmy | 372 | * CAN_NO_MSG_AVAILABLE if there are is no message available in the specified buffer. |
| 373 | * CAN_FAIL if the rxBuffer parameter i out of range for the specified controller. |
||
| 59 | jimmy | 374 | */ |
| 142 | jimmy | 375 | static Can_Return_t Can_ReceiveFromController(Can_Message_t *msg, uint8_t rxBuffer) { |
| 376 | #if CAN_CONTROLLER == CAN_CONTROLLER_NULL |
||
| 377 | /* |
||
| 378 | * Receive from null device. |
||
| 379 | */ |
||
| 380 | return CAN_NO_MSG_AVAILABLE; |
||
| 381 | #endif |
||
| 59 | jimmy | 382 | |
| 142 | jimmy | 383 | #if CAN_CONTROLLER == CAN_CONTROLLER_MCP2515 |
| 384 | /* |
||
| 385 | * Receive from MCP2515 device. |
||
| 386 | */ |
||
| 387 | uint8_t stat; |
||
| 388 | stat = MCP2515_ReadStatus(); |
||
| 389 | if (rxBuffer == 0) { |
||
| 390 | /* check BUF0 */ |
||
| 391 | if (stat & MCP_STAT_RX0IF) { |
||
| 392 | /* Msg in Buffer 0 */ |
||
| 393 | MCP2515_ReadCanMsg(MCP_RXBUF_0, msg); |
||
| 394 | MCP2515_ModifyRegister(MCP_CANINTF, MCP_RX0IF, 0); |
||
| 395 | return CAN_OK; |
||
| 396 | } |
||
| 397 | } |
||
| 398 | else if (rxBuffer == 1) { |
||
| 399 | /* check BUF1 */ |
||
| 400 | if (stat & MCP_STAT_RX1IF) { |
||
| 401 | /* Msg in Buffer 1 */ |
||
| 402 | MCP2515_ReadCanMsg(MCP_RXBUF_1, msg); |
||
| 403 | MCP2515_ModifyRegister(MCP_CANINTF, MCP_RX1IF, 0); |
||
| 404 | return CAN_OK; |
||
| 405 | } |
||
| 406 | } |
||
| 407 | else { |
||
| 408 | /* invalid parameters */ |
||
| 409 | return CAN_FAIL; |
||
| 410 | } |
||
| 411 | return CAN_NO_MSG_AVAILABLE; |
||
| 412 | #endif |
||
| 59 | jimmy | 413 | } |
| 414 | |||
| 415 | |||
| 416 | /** |
||
| 142 | jimmy | 417 | * Checks how many messages are available in the CAN controller hardware. |
| 59 | jimmy | 418 | * |
| 419 | * @return |
||
| 142 | jimmy | 420 | * The number of messages available (0 if none). |
| 59 | jimmy | 421 | */ |
| 142 | jimmy | 422 | static uint8_t Can_MessagesAvailableInController() { |
| 423 | #if CAN_CONTROLLER == CAN_CONTROLLER_NULL |
||
| 424 | /* |
||
| 425 | * Check for messages in null device. |
||
| 426 | */ |
||
| 427 | return 0; |
||
| 428 | #endif |
||
| 59 | jimmy | 429 | |
| 142 | jimmy | 430 | #if CAN_CONTROLLER == CAN_CONTROLLER_MCP2515 |
| 431 | /* |
||
| 432 | * Check for message in MCP2515 device. |
||
| 433 | */ |
||
| 434 | uint8_t res; |
||
| 435 | res = MCP2515_ReadStatus(); /* RXnIF in Bit 1 and 0 */ |
||
| 436 | if (res & MCP_STAT_RXIF_MASK) { |
||
| 437 | //TODO: check how many messages are available |
||
| 438 | return 1; /* at least one message available */ |
||
| 439 | } |
||
| 440 | else { |
||
| 441 | return 0; /* no messages available */ |
||
| 442 | } |
||
| 443 | #endif |
||
| 444 | |||
| 445 | return 0; |
||
| 59 | jimmy | 446 | } |
| 447 | |||
| 448 | |||
| 449 | /* |
||
| 450 | * Checks Controller-Error-State. |
||
| 451 | * |
||
| 452 | * @return |
||
| 453 | * CAN_OK if the controller is OK. |
||
| 142 | jimmy | 454 | * CAN_FAIL if errors have occured. |
| 455 | * |
||
| 59 | jimmy | 456 | * @todo |
| 457 | * Styr upp denna funktion lite bättre. |
||
| 458 | */ |
||
| 142 | jimmy | 459 | static Can_Return_t Can_ControllerCheckError() { |
| 460 | #if CAN_CONTROLLER == CAN_CONTROLLER_NULL |
||
| 461 | /* |
||
| 462 | * Check for errors in null device. |
||
| 463 | */ |
||
| 464 | return CAN_OK; |
||
| 465 | #endif |
||
| 59 | jimmy | 466 | |
| 142 | jimmy | 467 | #if CAN_CONTROLLER == CAN_CONTROLLER_MCP2515 |
| 468 | /* |
||
| 469 | * Check for errors in MCP2515 device. |
||
| 470 | */ |
||
| 471 | uint8_t eflg = MCP2515_ReadRegister(MCP_EFLG); |
||
| 472 | if (eflg & MCP_EFLG_ERRORMASK) { |
||
| 473 | return CAN_FAIL; /* errors found */ |
||
| 474 | } |
||
| 475 | else { |
||
| 476 | return CAN_OK; /* no errors found */ |
||
| 477 | } |
||
| 478 | #endif |
||
| 479 | } |
||
| 480 | |||
| 481 | |||
| 482 | #if (CAN_QUEUE_SIZE_TX > 0) || (CAN_QUEUE_SIZE_RX > 0) |
||
| 483 | /** |
||
| 484 | * Initializes a CAN queue. |
||
| 485 | * |
||
| 486 | * @param q |
||
| 487 | * Pointer to the queue object. |
||
| 488 | * |
||
| 489 | * @param size |
||
| 490 | * Size of the queue (number of messages that can be queued). |
||
| 491 | * |
||
| 492 | * @param dataPtr |
||
| 493 | * Pointer to the message storage buffer that should be used by the queue. |
||
| 494 | */ |
||
| 495 | static void Can_QueueInit(Can_MessageQueue_t *q, uint8_t size, Can_Message_t *dataPtr) { |
||
| 496 | q->dataPtr = dataPtr; |
||
| 497 | q->head = 0; |
||
| 498 | q->tail = 0; |
||
| 499 | q->nrElements = 0; |
||
| 500 | q->size = size; |
||
| 501 | } |
||
| 502 | |||
| 503 | |||
| 504 | /** |
||
| 505 | * Inserts a new element in a queue and returns a pointer to the new element. |
||
| 506 | * If the queue is full, the last element (the tail) will be overwritten by |
||
| 507 | * the new element. |
||
| 508 | * |
||
| 509 | * @param q |
||
| 510 | * Pointer to the queue object. |
||
| 511 | * |
||
| 512 | * @return |
||
| 513 | * Pointer to the new message element. Use this pointer to copy data into the queue. |
||
| 514 | */ |
||
| 515 | static Can_Message_t* Can_QueueInsert(Can_MessageQueue_t *q) { |
||
| 516 | Can_Message_t *ptr; |
||
| 517 | #if 0 |
||
| 518 | printf("INSERT: bef=%u, ", q->nrElements); |
||
| 519 | #endif |
||
| 520 | if ((q->nrElements+1) > q->size) { |
||
| 521 | q->tail = (q->tail + 1) % q->size; |
||
| 522 | q->nrElements--; |
||
| 523 | #if 0 |
||
| 524 | printf("Can_QueueInsertViaPtr: QUEUE OVERRUN!\n\r"); |
||
| 525 | #endif |
||
| 526 | } |
||
| 527 | ptr = &(q->dataPtr[q->head]); |
||
| 528 | #if 0 |
||
| 529 | if (q->handled[q->head] == 0) { |
||
| 530 | printf("Can_QueueInsertViaPtr: discarding non-handled msg!\n\r"); |
||
| 531 | } |
||
| 532 | #endif |
||
| 533 | q->head = (q->head + 1) % q->size; |
||
| 534 | q->nrElements++; |
||
| 535 | #if 0 |
||
| 536 | printf("aft=%u\n\n", q->nrElements); |
||
| 537 | #endif |
||
| 538 | return ptr; |
||
| 539 | } |
||
| 540 | |||
| 541 | |||
| 542 | /** |
||
| 543 | * Returns a pointer to the last element in the queue (the tail). Use this pointer |
||
| 544 | * to extract the message, and then call Can_QueueRemoveTail to actually remove |
||
| 545 | * the element. |
||
| 546 | * |
||
| 547 | * @param q |
||
| 548 | * Pointer to the queue object. |
||
| 549 | * |
||
| 550 | * @return |
||
| 551 | * Pointer to the tail message element. |
||
| 552 | */ |
||
| 553 | static Can_Message_t* Can_QueueReadTailPtr(Can_MessageQueue_t *q) { |
||
| 554 | if (q->nrElements > 0) { |
||
| 555 | return &(q->dataPtr[q->tail]); |
||
| 59 | jimmy | 556 | } |
| 557 | else { |
||
| 142 | jimmy | 558 | return 0; |
| 59 | jimmy | 559 | } |
| 142 | jimmy | 560 | } |
| 59 | jimmy | 561 | |
| 142 | jimmy | 562 | |
| 563 | /** |
||
| 564 | * Removes the last element in the queue (the tail). You should have extracted |
||
| 565 | * the data using Can_QueueReadTailPtr before using this function. |
||
| 566 | * |
||
| 567 | * @param q |
||
| 568 | * Pointer to the queue object. |
||
| 569 | */ |
||
| 570 | static void Can_QueueRemoveTail(Can_MessageQueue_t *q) { |
||
| 571 | if (q->nrElements > 0) { |
||
| 572 | q->tail = (q->tail + 1) % q->size; |
||
| 573 | q->nrElements--; |
||
| 574 | #if 0 |
||
| 575 | printf("queue size = %u\n", q->nrElements); |
||
| 576 | #endif |
||
| 577 | } |
||
| 59 | jimmy | 578 | } |
| 142 | jimmy | 579 | |
| 580 | #endif |