1 /*
2  * Copyright (c) 2006-2025, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author            Notes
8  * 2015-05-14     aubrcool@qq.com   first version
9  * 2015-07-06     Bernard           code cleanup and remove RT_CAN_USING_LED;
10  */
11 
12 #include <rthw.h>
13 #include <rtthread.h>
14 #include <rtdevice.h>
15 
16 #define CAN_LOCK(can)   rt_mutex_take(&(can->lock), RT_WAITING_FOREVER)
17 #define CAN_UNLOCK(can) rt_mutex_release(&(can->lock))
18 
rt_can_init(struct rt_device * dev)19 static rt_err_t rt_can_init(struct rt_device *dev)
20 {
21     rt_err_t result = RT_EOK;
22     struct rt_can_device *can;
23 
24     RT_ASSERT(dev != RT_NULL);
25     can = (struct rt_can_device *)dev;
26 
27     /* initialize rx/tx */
28     can->can_rx = RT_NULL;
29     can->can_tx = RT_NULL;
30 #ifdef RT_CAN_USING_HDR
31     can->hdr = RT_NULL;
32 #endif
33 
34     /* apply configuration */
35     if (can->ops->configure)
36         result = can->ops->configure(can, &can->config);
37     else
38         result = -RT_ENOSYS;
39 
40     return result;
41 }
42 
43 /*
44  * can interrupt routines
45  */
_can_int_rx(struct rt_can_device * can,struct rt_can_msg * data,rt_ssize_t msgs)46 rt_inline rt_ssize_t _can_int_rx(struct rt_can_device *can, struct rt_can_msg *data, rt_ssize_t msgs)
47 {
48     rt_ssize_t size;
49     struct rt_can_rx_fifo *rx_fifo;
50     RT_ASSERT(can != RT_NULL);
51     size = msgs;
52 
53     rx_fifo = (struct rt_can_rx_fifo *) can->can_rx;
54     RT_ASSERT(rx_fifo != RT_NULL);
55 
56     /* read from software FIFO */
57     while (msgs / sizeof(struct rt_can_msg) > 0)
58     {
59         rt_base_t level;
60 #ifdef RT_CAN_USING_HDR
61         rt_int8_t hdr;
62 #endif /*RT_CAN_USING_HDR*/
63         struct rt_can_msg_list *listmsg = RT_NULL;
64 
65         /* disable interrupt */
66         level = rt_hw_interrupt_disable();
67 #ifdef RT_CAN_USING_HDR
68         hdr = data->hdr_index;
69 
70         if (hdr >= 0 && can->hdr && hdr < can->config.maxhdr && !rt_list_isempty(&can->hdr[hdr].list))
71         {
72             listmsg = rt_list_entry(can->hdr[hdr].list.next, struct rt_can_msg_list, hdrlist);
73             rt_list_remove(&listmsg->list);
74             rt_list_remove(&listmsg->hdrlist);
75             if (can->hdr[hdr].msgs)
76             {
77                 can->hdr[hdr].msgs--;
78             }
79             listmsg->owner = RT_NULL;
80         }
81         else if (hdr == -1)
82 #endif /*RT_CAN_USING_HDR*/
83         {
84             if (!rt_list_isempty(&rx_fifo->uselist))
85             {
86                 listmsg = rt_list_entry(rx_fifo->uselist.next, struct rt_can_msg_list, list);
87                 rt_list_remove(&listmsg->list);
88 #ifdef RT_CAN_USING_HDR
89                 rt_list_remove(&listmsg->hdrlist);
90                 if (listmsg->owner != RT_NULL && listmsg->owner->msgs)
91                 {
92                     listmsg->owner->msgs--;
93                 }
94                 listmsg->owner = RT_NULL;
95 #endif /*RT_CAN_USING_HDR*/
96             }
97             else
98             {
99                 /* no data, enable interrupt and break out */
100                 rt_hw_interrupt_enable(level);
101                 break;
102             }
103         }
104 
105         /* enable interrupt */
106         rt_hw_interrupt_enable(level);
107         if (listmsg != RT_NULL)
108         {
109             rt_memcpy(data, &listmsg->data, sizeof(struct rt_can_msg));
110 
111             level = rt_hw_interrupt_disable();
112             rt_list_insert_before(&rx_fifo->freelist, &listmsg->list);
113             rx_fifo->freenumbers++;
114             RT_ASSERT(rx_fifo->freenumbers <= can->config.msgboxsz);
115             rt_hw_interrupt_enable(level);
116 
117             listmsg = RT_NULL;
118         }
119         else
120         {
121             break;
122         }
123         data ++;
124         msgs -= sizeof(struct rt_can_msg);
125     }
126 
127     return (size - msgs);
128 }
129 
_can_int_tx(struct rt_can_device * can,const struct rt_can_msg * data,int msgs)130 rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *data, int msgs)
131 {
132     int size;
133     struct rt_can_tx_fifo *tx_fifo;
134 
135     RT_ASSERT(can != RT_NULL);
136 
137     size = msgs;
138     tx_fifo = (struct rt_can_tx_fifo *) can->can_tx;
139     RT_ASSERT(tx_fifo != RT_NULL);
140 
141     while (msgs)
142     {
143         rt_base_t level;
144         rt_uint32_t no;
145         rt_uint32_t result;
146         struct rt_can_sndbxinx_list *tx_tosnd = RT_NULL;
147 
148         rt_sem_take(&(tx_fifo->sem), RT_WAITING_FOREVER);
149         level = rt_hw_interrupt_disable();
150         tx_tosnd = rt_list_entry(tx_fifo->freelist.next, struct rt_can_sndbxinx_list, list);
151         RT_ASSERT(tx_tosnd != RT_NULL);
152         rt_list_remove(&tx_tosnd->list);
153         rt_hw_interrupt_enable(level);
154 
155         no = ((rt_ubase_t)tx_tosnd - (rt_ubase_t)tx_fifo->buffer) / sizeof(struct rt_can_sndbxinx_list);
156         tx_tosnd->result = RT_CAN_SND_RESULT_WAIT;
157         rt_completion_init(&tx_tosnd->completion);
158         if (can->ops->sendmsg(can, data, no) != RT_EOK)
159         {
160             /* send failed. */
161             level = rt_hw_interrupt_disable();
162             rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list);
163             rt_hw_interrupt_enable(level);
164             rt_sem_release(&(tx_fifo->sem));
165             goto err_ret;
166         }
167 
168         can->status.sndchange |= 1<<no;
169         if (rt_completion_wait(&(tx_tosnd->completion), RT_CANSND_MSG_TIMEOUT) != RT_EOK)
170         {
171             level = rt_hw_interrupt_disable();
172             rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list);
173             can->status.sndchange &= ~ (1<<no);
174             rt_hw_interrupt_enable(level);
175             rt_sem_release(&(tx_fifo->sem));
176             goto err_ret;
177         }
178 
179         level = rt_hw_interrupt_disable();
180         result = tx_tosnd->result;
181         if (!rt_list_isempty(&tx_tosnd->list))
182         {
183             rt_list_remove(&tx_tosnd->list);
184         }
185         rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list);
186         rt_hw_interrupt_enable(level);
187         rt_sem_release(&(tx_fifo->sem));
188 
189         if (result == RT_CAN_SND_RESULT_OK)
190         {
191             level = rt_hw_interrupt_disable();
192             can->status.sndpkg++;
193             rt_hw_interrupt_enable(level);
194 
195             data ++;
196             msgs -= sizeof(struct rt_can_msg);
197             if (!msgs) break;
198         }
199         else
200         {
201 err_ret:
202             level = rt_hw_interrupt_disable();
203             can->status.dropedsndpkg++;
204             rt_hw_interrupt_enable(level);
205             break;
206         }
207     }
208 
209     return (size - msgs);
210 }
211 
_can_int_tx_priv(struct rt_can_device * can,const struct rt_can_msg * data,int msgs)212 rt_inline int _can_int_tx_priv(struct rt_can_device *can, const struct rt_can_msg *data, int msgs)
213 {
214     int size;
215     rt_base_t level;
216     rt_uint32_t no, result;
217     struct rt_can_tx_fifo *tx_fifo;
218 
219     RT_ASSERT(can != RT_NULL);
220 
221     size = msgs;
222     tx_fifo = (struct rt_can_tx_fifo *) can->can_tx;
223     RT_ASSERT(tx_fifo != RT_NULL);
224 
225     while (msgs)
226     {
227         no = data->priv;
228         if (no >= can->config.sndboxnumber)
229         {
230             break;
231         }
232 
233         level = rt_hw_interrupt_disable();
234         if ((tx_fifo->buffer[no].result != RT_CAN_SND_RESULT_OK))
235         {
236             rt_hw_interrupt_enable(level);
237 
238             rt_completion_wait(&(tx_fifo->buffer[no].completion), RT_WAITING_FOREVER);
239             continue;
240         }
241         tx_fifo->buffer[no].result = RT_CAN_SND_RESULT_WAIT;
242         rt_hw_interrupt_enable(level);
243 
244         if (can->ops->sendmsg(can, data, no) != RT_EOK)
245         {
246             continue;
247         }
248         can->status.sndchange |= 1<<no;
249         if (rt_completion_wait(&(tx_fifo->buffer[no].completion), RT_CANSND_MSG_TIMEOUT) != RT_EOK)
250         {
251             can->status.sndchange &= ~ (1<<no);
252             continue;
253         }
254 
255         result = tx_fifo->buffer[no].result;
256         if (result == RT_CAN_SND_RESULT_OK)
257         {
258             level = rt_hw_interrupt_disable();
259             can->status.sndpkg++;
260             rt_hw_interrupt_enable(level);
261             data ++;
262             msgs -= sizeof(struct rt_can_msg);
263             if (!msgs) break;
264         }
265         else
266         {
267             level = rt_hw_interrupt_disable();
268             can->status.dropedsndpkg++;
269             rt_hw_interrupt_enable(level);
270             break;
271         }
272     }
273 
274     return (size - msgs);
275 }
276 
rt_can_open(struct rt_device * dev,rt_uint16_t oflag)277 static rt_err_t rt_can_open(struct rt_device *dev, rt_uint16_t oflag)
278 {
279     struct rt_can_device *can;
280     char tmpname[16];
281     RT_ASSERT(dev != RT_NULL);
282     can = (struct rt_can_device *)dev;
283 
284     CAN_LOCK(can);
285 
286     /* get open flags */
287     dev->open_flag = oflag & 0xff;
288     if (can->can_rx == RT_NULL)
289     {
290         if (oflag & RT_DEVICE_FLAG_INT_RX)
291         {
292             int i = 0;
293             struct rt_can_rx_fifo *rx_fifo;
294 
295             rx_fifo = (struct rt_can_rx_fifo *) rt_malloc(sizeof(struct rt_can_rx_fifo) +
296                       can->config.msgboxsz * sizeof(struct rt_can_msg_list));
297             RT_ASSERT(rx_fifo != RT_NULL);
298 
299             rx_fifo->buffer = (struct rt_can_msg_list *)(rx_fifo + 1);
300             rt_memset(rx_fifo->buffer, 0, can->config.msgboxsz * sizeof(struct rt_can_msg_list));
301             rt_list_init(&rx_fifo->freelist);
302             rt_list_init(&rx_fifo->uselist);
303             rx_fifo->freenumbers = can->config.msgboxsz;
304             for (i = 0;  i < can->config.msgboxsz; i++)
305             {
306                 rt_list_insert_before(&rx_fifo->freelist, &rx_fifo->buffer[i].list);
307 #ifdef RT_CAN_USING_HDR
308                 rt_list_init(&rx_fifo->buffer[i].hdrlist);
309                 rx_fifo->buffer[i].owner = RT_NULL;
310 #endif
311             }
312             can->can_rx = rx_fifo;
313 
314             dev->open_flag |= RT_DEVICE_FLAG_INT_RX;
315             /* open can rx interrupt */
316             can->ops->control(can, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
317         }
318     }
319 
320     if (can->can_tx == RT_NULL)
321     {
322         if (oflag & RT_DEVICE_FLAG_INT_TX)
323         {
324             int i = 0;
325             struct rt_can_tx_fifo *tx_fifo;
326 
327             tx_fifo = (struct rt_can_tx_fifo *) rt_malloc(sizeof(struct rt_can_tx_fifo) +
328                       can->config.sndboxnumber * sizeof(struct rt_can_sndbxinx_list));
329             RT_ASSERT(tx_fifo != RT_NULL);
330 
331             tx_fifo->buffer = (struct rt_can_sndbxinx_list *)(tx_fifo + 1);
332             rt_memset(tx_fifo->buffer, 0,
333                     can->config.sndboxnumber * sizeof(struct rt_can_sndbxinx_list));
334             rt_list_init(&tx_fifo->freelist);
335             for (i = 0;  i < can->config.sndboxnumber; i++)
336             {
337                 rt_list_insert_before(&tx_fifo->freelist, &tx_fifo->buffer[i].list);
338                 rt_completion_init(&(tx_fifo->buffer[i].completion));
339                 tx_fifo->buffer[i].result = RT_CAN_SND_RESULT_OK;
340             }
341 
342             rt_sprintf(tmpname, "%stl", dev->parent.name);
343             rt_sem_init(&(tx_fifo->sem), tmpname, can->config.sndboxnumber, RT_IPC_FLAG_FIFO);
344             can->can_tx = tx_fifo;
345 
346             dev->open_flag |= RT_DEVICE_FLAG_INT_TX;
347             /* open can tx interrupt */
348             can->ops->control(can, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_TX);
349         }
350     }
351 
352     can->ops->control(can, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_CAN_INT_ERR);
353 
354 #ifdef RT_CAN_USING_HDR
355     if (can->hdr == RT_NULL)
356     {
357         int i = 0;
358         struct rt_can_hdr *phdr;
359 
360         phdr = (struct rt_can_hdr *) rt_malloc(can->config.maxhdr * sizeof(struct rt_can_hdr));
361         RT_ASSERT(phdr != RT_NULL);
362         rt_memset(phdr, 0, can->config.maxhdr * sizeof(struct rt_can_hdr));
363         for (i = 0;  i < can->config.maxhdr; i++)
364         {
365             rt_list_init(&phdr[i].list);
366         }
367 
368         can->hdr = phdr;
369     }
370 #endif
371 
372     if (!can->timerinitflag)
373     {
374         can->timerinitflag = 1;
375 
376         rt_timer_start(&can->timer);
377     }
378 
379     CAN_UNLOCK(can);
380 
381     return RT_EOK;
382 }
383 
rt_can_close(struct rt_device * dev)384 static rt_err_t rt_can_close(struct rt_device *dev)
385 {
386     struct rt_can_device *can;
387 
388     RT_ASSERT(dev != RT_NULL);
389     can = (struct rt_can_device *)dev;
390 
391     CAN_LOCK(can);
392 
393     /* this device has more reference count */
394     if (dev->ref_count > 1)
395     {
396         CAN_UNLOCK(can);
397         return RT_EOK;
398     }
399 
400     if (can->timerinitflag)
401     {
402         can->timerinitflag = 0;
403 
404         rt_timer_stop(&can->timer);
405     }
406 
407     can->status_indicate.ind = RT_NULL;
408     can->status_indicate.args = RT_NULL;
409 
410 #ifdef RT_CAN_USING_HDR
411     if (can->hdr != RT_NULL)
412     {
413         rt_free(can->hdr);
414         can->hdr = RT_NULL;
415     }
416 #endif
417 
418     if (dev->open_flag & RT_DEVICE_FLAG_INT_RX)
419     {
420         struct rt_can_rx_fifo *rx_fifo;
421 
422         /* clear can rx interrupt */
423         can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX);
424 
425         rx_fifo = (struct rt_can_rx_fifo *)can->can_rx;
426         RT_ASSERT(rx_fifo != RT_NULL);
427 
428         rt_free(rx_fifo);
429         dev->open_flag &= ~RT_DEVICE_FLAG_INT_RX;
430         can->can_rx = RT_NULL;
431     }
432 
433     if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
434     {
435         struct rt_can_tx_fifo *tx_fifo;
436 
437         /* clear can tx interrupt */
438         can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_TX);
439 
440         tx_fifo = (struct rt_can_tx_fifo *)can->can_tx;
441         RT_ASSERT(tx_fifo != RT_NULL);
442 
443         rt_sem_detach(&(tx_fifo->sem));
444         rt_free(tx_fifo);
445         dev->open_flag &= ~RT_DEVICE_FLAG_INT_TX;
446         can->can_tx = RT_NULL;
447     }
448 
449     can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_CAN_INT_ERR);
450     can->ops->control(can, RT_CAN_CMD_START, RT_FALSE);
451     CAN_UNLOCK(can);
452 
453     return RT_EOK;
454 }
455 
rt_can_read(struct rt_device * dev,rt_off_t pos,void * buffer,rt_size_t size)456 static rt_ssize_t rt_can_read(struct rt_device *dev,
457                              rt_off_t          pos,
458                              void             *buffer,
459                              rt_size_t         size)
460 {
461     struct rt_can_device *can;
462 
463     RT_ASSERT(dev != RT_NULL);
464     if (size == 0) return 0;
465 
466     can = (struct rt_can_device *)dev;
467 
468     if ((dev->open_flag & RT_DEVICE_FLAG_INT_RX) && (dev->ref_count > 0))
469     {
470         return _can_int_rx(can, buffer, size);
471     }
472 
473     return 0;
474 }
475 
rt_can_write(struct rt_device * dev,rt_off_t pos,const void * buffer,rt_size_t size)476 static rt_ssize_t rt_can_write(struct rt_device *dev,
477                               rt_off_t          pos,
478                               const void       *buffer,
479                               rt_size_t         size)
480 {
481     struct rt_can_device *can;
482 
483     RT_ASSERT(dev != RT_NULL);
484     if (size == 0) return 0;
485 
486     can = (struct rt_can_device *)dev;
487 
488     if ((dev->open_flag & RT_DEVICE_FLAG_INT_TX) && (dev->ref_count > 0))
489     {
490         if (can->config.privmode)
491         {
492             return _can_int_tx_priv(can, buffer, size);
493         }
494         else
495         {
496             return _can_int_tx(can, buffer, size);
497         }
498     }
499     return 0;
500 }
501 
rt_can_control(struct rt_device * dev,int cmd,void * args)502 static rt_err_t rt_can_control(struct rt_device *dev,
503                                int              cmd,
504                                void             *args)
505 {
506     struct rt_can_device *can;
507     rt_err_t res;
508 
509     res = RT_EOK;
510     RT_ASSERT(dev != RT_NULL);
511     can = (struct rt_can_device *)dev;
512 
513     switch (cmd)
514     {
515     case RT_DEVICE_CTRL_SUSPEND:
516         /* suspend device */
517         dev->flag |= RT_DEVICE_FLAG_SUSPENDED;
518         break;
519 
520     case RT_DEVICE_CTRL_RESUME:
521         /* resume device */
522         dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED;
523         break;
524 
525     case RT_DEVICE_CTRL_CONFIG:
526         /* configure device */
527         res = can->ops->configure(can, (struct can_configure *)args);
528         break;
529 
530     case RT_CAN_CMD_SET_PRIV:
531         /* configure device */
532         if ((rt_uint32_t)(rt_ubase_t)args != can->config.privmode)
533         {
534             int i;
535             rt_base_t level;
536             struct rt_can_tx_fifo *tx_fifo;
537 
538             res = can->ops->control(can, cmd, args);
539             if (res != RT_EOK) return res;
540             tx_fifo = (struct rt_can_tx_fifo *) can->can_tx;
541             if (can->config.privmode)
542             {
543                 for (i = 0;  i < can->config.sndboxnumber; i++)
544                 {
545                     level = rt_hw_interrupt_disable();
546                     if(rt_list_isempty(&tx_fifo->buffer[i].list))
547                     {
548                         rt_sem_release(&(tx_fifo->sem));
549                     }
550                     else
551                     {
552                         rt_list_remove(&tx_fifo->buffer[i].list);
553                     }
554                     rt_hw_interrupt_enable(level);
555                 }
556 
557             }
558             else
559             {
560                 for (i = 0;  i < can->config.sndboxnumber; i++)
561                 {
562                     level = rt_hw_interrupt_disable();
563                     if (tx_fifo->buffer[i].result == RT_CAN_SND_RESULT_OK)
564                     {
565                         rt_list_insert_before(&tx_fifo->freelist, &tx_fifo->buffer[i].list);
566                     }
567                     rt_hw_interrupt_enable(level);
568                 }
569             }
570         }
571         break;
572 
573     case RT_CAN_CMD_SET_STATUS_IND:
574         can->status_indicate.ind = ((rt_can_status_ind_type_t)args)->ind;
575         can->status_indicate.args = ((rt_can_status_ind_type_t)args)->args;
576         break;
577 
578 #ifdef RT_CAN_USING_HDR
579     case RT_CAN_CMD_SET_FILTER:
580         res = can->ops->control(can, cmd, args);
581         if (res != RT_EOK || can->hdr == RT_NULL)
582         {
583             return res;
584         }
585 
586         struct rt_can_filter_config *pfilter;
587         struct rt_can_filter_item *pitem;
588         rt_uint32_t count;
589         rt_base_t level;
590 
591         pfilter = (struct rt_can_filter_config *)args;
592         RT_ASSERT(pfilter);
593         count = pfilter->count;
594         pitem = pfilter->items;
595         if (pfilter->actived)
596         {
597             while (count)
598             {
599                 if (pitem->hdr_bank >= can->config.maxhdr || pitem->hdr_bank < 0)
600                 {
601                     count--;
602                     pitem++;
603                     continue;
604                 }
605 
606                 level = rt_hw_interrupt_disable();
607                 if (!can->hdr[pitem->hdr_bank].connected)
608                 {
609                     rt_hw_interrupt_enable(level);
610                     rt_memcpy(&can->hdr[pitem->hdr_bank].filter, pitem,
611                               sizeof(struct rt_can_filter_item));
612                     level = rt_hw_interrupt_disable();
613                     can->hdr[pitem->hdr_bank].connected = 1;
614                     can->hdr[pitem->hdr_bank].msgs = 0;
615                     rt_list_init(&can->hdr[pitem->hdr_bank].list);
616                 }
617                 rt_hw_interrupt_enable(level);
618 
619                 count--;
620                 pitem++;
621             }
622         }
623         else
624         {
625             while (count)
626             {
627                 if (pitem->hdr_bank >= can->config.maxhdr || pitem->hdr_bank < 0)
628                 {
629                     count--;
630                     pitem++;
631                     continue;
632                 }
633                 level = rt_hw_interrupt_disable();
634 
635                 if (can->hdr[pitem->hdr_bank].connected)
636                 {
637                     can->hdr[pitem->hdr_bank].connected = 0;
638                     can->hdr[pitem->hdr_bank].msgs = 0;
639                     if (!rt_list_isempty(&can->hdr[pitem->hdr_bank].list))
640                     {
641                         rt_list_remove(can->hdr[pitem->hdr_bank].list.next);
642                     }
643                     rt_hw_interrupt_enable(level);
644                     rt_memset(&can->hdr[pitem->hdr_bank].filter, 0,
645                               sizeof(struct rt_can_filter_item));
646                 }
647                 else
648                 {
649                     rt_hw_interrupt_enable(level);
650                 }
651                 count--;
652                 pitem++;
653             }
654         }
655         break;
656 #endif /*RT_CAN_USING_HDR*/
657 #ifdef RT_CAN_USING_BUS_HOOK
658     case RT_CAN_CMD_SET_BUS_HOOK:
659         can->bus_hook = (rt_can_bus_hook) args;
660         break;
661 #endif /*RT_CAN_USING_BUS_HOOK*/
662     default :
663         /* control device */
664         if (can->ops->control != RT_NULL)
665         {
666             res = can->ops->control(can, cmd, args);
667         }
668         else
669         {
670             res = -RT_ENOSYS;
671         }
672         break;
673     }
674 
675     return res;
676 }
677 
678 /*
679  * can timer
680  */
cantimeout(void * arg)681 static void cantimeout(void *arg)
682 {
683     rt_can_t can;
684 
685     can = (rt_can_t)arg;
686     RT_ASSERT(can);
687     rt_device_control((rt_device_t)can, RT_CAN_CMD_GET_STATUS, (void *)&can->status);
688 
689     if (can->status_indicate.ind != RT_NULL)
690     {
691         can->status_indicate.ind(can, can->status_indicate.args);
692     }
693 #ifdef RT_CAN_USING_BUS_HOOK
694     if(can->bus_hook)
695     {
696         can->bus_hook(can);
697     }
698 #endif /*RT_CAN_USING_BUS_HOOK*/
699     if (can->timerinitflag == 1)
700     {
701         can->timerinitflag = 0xFF;
702     }
703 }
704 
705 #ifdef RT_USING_DEVICE_OPS
706 const static struct rt_device_ops can_device_ops =
707 {
708     rt_can_init,
709     rt_can_open,
710     rt_can_close,
711     rt_can_read,
712     rt_can_write,
713     rt_can_control
714 };
715 #endif
716 
717 /*
718  * can register
719  */
rt_hw_can_register(struct rt_can_device * can,const char * name,const struct rt_can_ops * ops,void * data)720 rt_err_t rt_hw_can_register(struct rt_can_device    *can,
721                             const char              *name,
722                             const struct rt_can_ops *ops,
723                             void                    *data)
724 {
725     struct rt_device *device;
726     RT_ASSERT(can != RT_NULL);
727 
728     device = &(can->parent);
729 
730     device->type        = RT_Device_Class_CAN;
731     device->rx_indicate = RT_NULL;
732     device->tx_complete = RT_NULL;
733 #ifdef RT_CAN_USING_HDR
734     can->hdr            = RT_NULL;
735 #endif
736     can->can_rx         = RT_NULL;
737     can->can_tx         = RT_NULL;
738     rt_mutex_init(&(can->lock), "can", RT_IPC_FLAG_PRIO);
739 #ifdef RT_CAN_USING_BUS_HOOK
740     can->bus_hook       = RT_NULL;
741 #endif /*RT_CAN_USING_BUS_HOOK*/
742 
743 #ifdef RT_USING_DEVICE_OPS
744     device->ops         = &can_device_ops;
745 #else
746     device->init        = rt_can_init;
747     device->open        = rt_can_open;
748     device->close       = rt_can_close;
749     device->read        = rt_can_read;
750     device->write       = rt_can_write;
751     device->control     = rt_can_control;
752 #endif
753     can->ops            = ops;
754 
755     can->status_indicate.ind  = RT_NULL;
756     can->status_indicate.args = RT_NULL;
757     rt_memset(&can->status, 0, sizeof(can->status));
758 
759     device->user_data   = data;
760 
761     can->timerinitflag  = 0;
762     rt_timer_init(&can->timer,
763                   name,
764                   cantimeout,
765                   (void *)can,
766                   can->config.ticks,
767                   RT_TIMER_FLAG_PERIODIC);
768     /* register a character device */
769     return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
770 }
771 
772 /* ISR for can interrupt */
rt_hw_can_isr(struct rt_can_device * can,int event)773 void rt_hw_can_isr(struct rt_can_device *can, int event)
774 {
775     switch (event & 0xff)
776     {
777     case RT_CAN_EVENT_RXOF_IND:
778     {
779         rt_base_t level;
780         level = rt_hw_interrupt_disable();
781         can->status.dropedrcvpkg++;
782         rt_hw_interrupt_enable(level);
783     }
784     case RT_CAN_EVENT_RX_IND:
785     {
786         struct rt_can_msg tmpmsg;
787         struct rt_can_rx_fifo *rx_fifo;
788         struct rt_can_msg_list *listmsg = RT_NULL;
789 #ifdef RT_CAN_USING_HDR
790         rt_int8_t hdr;
791 #endif
792         int ch = -1;
793         rt_base_t level;
794         rt_uint32_t no;
795 
796         rx_fifo = (struct rt_can_rx_fifo *)can->can_rx;
797         RT_ASSERT(rx_fifo != RT_NULL);
798         /* interrupt mode receive */
799         RT_ASSERT(can->parent.open_flag & RT_DEVICE_FLAG_INT_RX);
800 
801         no = event >> 8;
802         ch = can->ops->recvmsg(can, &tmpmsg, no);
803         if (ch == -1) break;
804 
805         /* disable interrupt */
806         level = rt_hw_interrupt_disable();
807         can->status.rcvpkg++;
808         can->status.rcvchange = 1;
809         if (!rt_list_isempty(&rx_fifo->freelist))
810         {
811             listmsg = rt_list_entry(rx_fifo->freelist.next, struct rt_can_msg_list, list);
812             rt_list_remove(&listmsg->list);
813 #ifdef RT_CAN_USING_HDR
814             rt_list_remove(&listmsg->hdrlist);
815             if (listmsg->owner != RT_NULL && listmsg->owner->msgs)
816             {
817                 listmsg->owner->msgs--;
818             }
819             listmsg->owner = RT_NULL;
820 #endif /*RT_CAN_USING_HDR*/
821             RT_ASSERT(rx_fifo->freenumbers > 0);
822             rx_fifo->freenumbers--;
823         }
824         else if (!rt_list_isempty(&rx_fifo->uselist))
825         {
826             listmsg = rt_list_entry(rx_fifo->uselist.next, struct rt_can_msg_list, list);
827             can->status.dropedrcvpkg++;
828             rt_list_remove(&listmsg->list);
829 #ifdef RT_CAN_USING_HDR
830             rt_list_remove(&listmsg->hdrlist);
831             if (listmsg->owner != RT_NULL && listmsg->owner->msgs)
832             {
833                 listmsg->owner->msgs--;
834             }
835             listmsg->owner = RT_NULL;
836 #endif
837         }
838         /* enable interrupt */
839         rt_hw_interrupt_enable(level);
840 
841         if (listmsg != RT_NULL)
842         {
843             rt_memcpy(&listmsg->data, &tmpmsg, sizeof(struct rt_can_msg));
844             level = rt_hw_interrupt_disable();
845             rt_list_insert_before(&rx_fifo->uselist, &listmsg->list);
846 #ifdef RT_CAN_USING_HDR
847             hdr = tmpmsg.hdr_index;
848             if (can->hdr != RT_NULL)
849             {
850                 RT_ASSERT(hdr < can->config.maxhdr && hdr >= 0);
851                 if (can->hdr[hdr].connected)
852                 {
853                     rt_list_insert_before(&can->hdr[hdr].list, &listmsg->hdrlist);
854                     listmsg->owner = &can->hdr[hdr];
855                     can->hdr[hdr].msgs++;
856                 }
857 
858             }
859 #endif
860             rt_hw_interrupt_enable(level);
861         }
862 
863         /* invoke callback */
864 #ifdef RT_CAN_USING_HDR
865         if (can->hdr != RT_NULL && can->hdr[hdr].connected && can->hdr[hdr].filter.ind)
866         {
867             rt_size_t rx_length;
868             RT_ASSERT(hdr < can->config.maxhdr && hdr >= 0);
869 
870             level = rt_hw_interrupt_disable();
871             rx_length = can->hdr[hdr].msgs * sizeof(struct rt_can_msg);
872             rt_hw_interrupt_enable(level);
873             if (rx_length)
874             {
875                 can->hdr[hdr].filter.ind(&can->parent, can->hdr[hdr].filter.args, hdr, rx_length);
876             }
877         }
878         else
879 #endif
880         {
881             if (can->parent.rx_indicate != RT_NULL)
882             {
883                 rt_size_t rx_length;
884 
885                 level = rt_hw_interrupt_disable();
886                 /* get rx length */
887                 rx_length = rt_list_len(&rx_fifo->uselist)* sizeof(struct rt_can_msg);
888                 rt_hw_interrupt_enable(level);
889 
890                 if (rx_length)
891                 {
892                     can->parent.rx_indicate(&can->parent, rx_length);
893                 }
894             }
895         }
896         break;
897     }
898 
899     case RT_CAN_EVENT_TX_DONE:
900     case RT_CAN_EVENT_TX_FAIL:
901     {
902         struct rt_can_tx_fifo *tx_fifo;
903         rt_uint32_t no;
904         no = event >> 8;
905         tx_fifo = (struct rt_can_tx_fifo *) can->can_tx;
906         RT_ASSERT(tx_fifo != RT_NULL);
907         if (can->status.sndchange&(1<<no))
908         {
909             if ((event & 0xff) == RT_CAN_EVENT_TX_DONE)
910             {
911                 tx_fifo->buffer[no].result = RT_CAN_SND_RESULT_OK;
912             }
913             else
914             {
915                 tx_fifo->buffer[no].result = RT_CAN_SND_RESULT_ERR;
916             }
917             rt_completion_done(&(tx_fifo->buffer[no].completion));
918         }
919         break;
920     }
921     }
922 }
923 
924 #ifdef RT_USING_FINSH
925 #include <finsh.h>
cmd_canstat(int argc,void ** argv)926 int cmd_canstat(int argc, void **argv)
927 {
928     static const char *ErrCode[] =
929     {
930         "No Error!",
931         "Warning !",
932         "Passive !",
933         "Bus Off !"
934     };
935 
936     if (argc >= 2)
937     {
938         struct rt_can_status status;
939         rt_device_t candev = rt_device_find(argv[1]);
940         if (!candev)
941         {
942             rt_kprintf(" Can't find can device %s\n", argv[1]);
943             return -1;
944         }
945         rt_kprintf(" Found can device: %s...", argv[1]);
946 
947         rt_device_control(candev, RT_CAN_CMD_GET_STATUS, &status);
948         rt_kprintf("\n Receive...error..count: %010ld. Send.....error....count: %010ld.",
949                    status.rcverrcnt, status.snderrcnt);
950         rt_kprintf("\n Bit..pad..error..count: %010ld. Format...error....count: %010ld",
951                    status.bitpaderrcnt, status.formaterrcnt);
952         rt_kprintf("\n Ack.......error..count: %010ld. Bit......error....count: %010ld.",
953                    status.ackerrcnt, status.biterrcnt);
954         rt_kprintf("\n CRC.......error..count: %010ld. Error.code.[%010ld]: ",
955                    status.crcerrcnt, status.errcode);
956         switch (status.errcode)
957         {
958         case 0:
959             rt_kprintf("%s.", ErrCode[0]);
960             break;
961         case 1:
962             rt_kprintf("%s.", ErrCode[1]);
963             break;
964         case 2:
965         case 3:
966             rt_kprintf("%s.", ErrCode[2]);
967             break;
968         case 4:
969         case 5:
970         case 6:
971         case 7:
972             rt_kprintf("%s.", ErrCode[3]);
973             break;
974         }
975         rt_kprintf("\n Total.receive.packages: %010ld. Dropped.receive.packages: %010ld.",
976                    status.rcvpkg, status.dropedrcvpkg);
977         rt_kprintf("\n Total..send...packages: %010ld. Dropped...send..packages: %010ld.\n",
978                    status.sndpkg + status.dropedsndpkg, status.dropedsndpkg);
979     }
980     else
981     {
982         rt_kprintf(" Invalid Call %s\n", argv[0]);
983         rt_kprintf(" Please using %s cannamex .Here canname is driver name and x is candrive number.\n", argv[0]);
984     }
985     return 0;
986 }
987 MSH_CMD_EXPORT_ALIAS(cmd_canstat, canstat, stat can device status);
988 #endif
989 
990