1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2021-05-11     Carl        the first version
9  */
10 
11 #include "drv_can.h"
12 #include "interrupt.h"
13 #include <string.h>
14 
15 #ifdef BSP_USE_CAN
16 
17 #define LOG_TAG "drv_can"
18 #include <drv_log.h>
19 
20 #define _CAN0_NAME "can0"
21 #define _CAN1_NAME "can1"
22 
23 #define RTHW_CAN_WAIT(_can) rt_sem_take(&_can->recv_semaphore, RT_WAITING_FOREVER);
24 #define RTHW_CAN_SEND(_can) rt_sem_release(&_can->recv_semaphore);
25 
26 #ifdef BSP_USING_CAN0
27 struct ft2004_can drv_can0 =
28     {
29         .name = _CAN0_NAME,
30         .can_handle.Config.InstanceId = 0};
31 #endif
32 
33 #ifdef BSP_USING_CAN1
34 struct ft2004_can drv_can1 =
35     {
36         .name = _CAN1_NAME,
37         .can_handle.Config.InstanceId = 1};
38 #endif
39 
_can_recv_irq(void * args)40 static void _can_recv_irq(void *args)
41 {
42     struct ft2004_can *drv_can = (struct ft2004_can *)args;
43     RTHW_CAN_SEND(drv_can);
44 }
45 
rt_hw_inner_can_isr(int irqno,void * param)46 static void rt_hw_inner_can_isr(int irqno, void *param)
47 {
48     FCan_IntrHandler(param);
49 }
50 
_can_config(struct rt_can_device * can,struct can_configure * cfg)51 static rt_err_t _can_config(struct rt_can_device *can, struct can_configure *cfg)
52 {
53     struct FCan_Bittiming bit_timing = {0};
54     struct ft2004_can *drv_can;
55     RT_ASSERT(can);
56     RT_ASSERT(cfg);
57     drv_can = (struct ft2004_can *)can->parent.user_data;
58     RT_ASSERT(drv_can);
59 
60     FCan_CfgInitialize(&drv_can->can_handle, FCan_LookupConfig(drv_can->can_handle.Config.InstanceId));
61 
62     FCan_SetHandler(&drv_can->can_handle, FCAN_HANDLER_RECV, _can_recv_irq, drv_can);
63 
64     bit_timing.bitrate = cfg->baud_rate;
65 
66     if (FCan_CalcBittiming(&bit_timing) != FCAN_SUCCESS)
67     {
68         LOG_E("Setting baud rate %x is not valid \r\n", bit_timing.bitrate);
69         return -RT_ERROR;
70     }
71 
72     FCan_SetTiming(&drv_can->can_handle, &bit_timing);
73 
74     rt_hw_interrupt_set_priority(drv_can->can_handle.Config.IrqNum, 16);
75     rt_hw_interrupt_install(drv_can->can_handle.Config.IrqNum, rt_hw_inner_can_isr, &drv_can->can_handle, drv_can->name);
76     rt_hw_interrupt_umask(drv_can->can_handle.Config.IrqNum);
77 
78     FCan_Enable(&drv_can->can_handle);
79 
80     return RT_EOK;
81 }
82 
_can_control(struct rt_can_device * can,int cmd,void * arg)83 static rt_err_t _can_control(struct rt_can_device *can, int cmd, void *arg)
84 {
85     return RT_EOK;
86 }
87 
_can_sendmsg(struct rt_can_device * can,const void * buf,rt_uint32_t box_num)88 static int _can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t box_num)
89 {
90     struct ft2004_can *drv_can;
91     struct rt_can_msg *pmsg = (struct rt_can_msg *)buf;
92     struct FCan_Frame can_frame = {0};
93     RT_ASSERT(can);
94     drv_can = (struct ft2004_can *)can->parent.user_data;
95     RT_ASSERT(drv_can);
96 
97     /* Check the parameters */
98     RT_ASSERT(pmsg->len <= 8U);
99 
100     if (RT_CAN_STDID == pmsg->ide)
101     {
102         can_frame.CanId = pmsg->id;
103     }
104     else
105     {
106         can_frame.CanId = pmsg->id;
107         can_frame.CanId |= CAN_EFF_FLAG;
108     }
109 
110     if (RT_CAN_DTR == pmsg->rtr)
111     {
112     }
113     else
114     {
115         can_frame.CanId |= CAN_RTR_FLAG;
116     }
117 
118     can_frame.CanDlc = pmsg->len & 0x0FU;
119     memcpy(can_frame.data, pmsg->data, 8);
120 
121     return (FCan_SendByIrq(&drv_can->can_handle, &can_frame, 1, RT_NULL) == 1) ? RT_EOK : -RT_ERROR;
122 }
123 
_can_recvmsg(struct rt_can_device * can,void * buf,rt_uint32_t fifo)124 static int _can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t fifo)
125 {
126     struct ft2004_can *drv_can;
127     struct rt_can_msg *pmsg = (struct rt_can_msg *)buf;
128     RT_ASSERT(can);
129     struct FCan_Frame recv_frame = {0};
130     drv_can = (struct ft2004_can *)can->parent.user_data;
131     RT_ASSERT(drv_can);
132 
133     RTHW_CAN_WAIT(drv_can);
134 
135     if (FCan_RecvByIrq(&drv_can->can_handle, &recv_frame, 1) == 0)
136     {
137         LOG_E("rx msg is error");
138         return -RT_ERROR;
139     }
140 
141     if (CAN_EFF_FLAG & recv_frame.CanId)
142     {
143         pmsg->ide = RT_CAN_EXTID;
144         pmsg->id = (recv_frame.CanId & ~(RT_CAN_EXTID));
145     }
146     else
147     {
148         pmsg->ide = RT_CAN_STDID;
149         pmsg->id = recv_frame.CanId;
150     }
151 
152     if (CAN_RTR_FLAG & recv_frame.CanId)
153     {
154         pmsg->id &= ~CAN_RTR_FLAG;
155         pmsg->rtr = RT_CAN_RTR;
156     }
157     else
158     {
159         pmsg->rtr = RT_CAN_DTR;
160     }
161 
162     /* get len */
163     pmsg->len = recv_frame.CanDlc;
164     return RT_EOK;
165 }
166 
167 static const struct rt_can_ops _can_ops =
168     {
169         _can_config,
170         _can_control,
171         _can_sendmsg,
172         _can_recvmsg,
173 };
174 
rt_hw_can_init(void)175 int rt_hw_can_init(void)
176 {
177 #ifdef BSP_USING_CAN0
178     drv_can0.can_handle.Config.InstanceId = 0;
179     rt_sem_init(&drv_can0.recv_semaphore, "can0_recv", 0, RT_IPC_FLAG_FIFO);
180     drv_can0.device.config.ticks = 20000;
181     drv_can0.device.config.baud_rate = 1000000;
182     rt_hw_can_register(&drv_can0.device,
183                        drv_can0.name,
184                        &_can_ops,
185                        &drv_can0);
186 
187 #endif
188 
189 #ifdef BSP_USING_CAN1
190     drv_can1.can_handle.Config.InstanceId = 1;
191     drv_can1.device.config.ticks = 20000;
192     drv_can1.device.config.baud_rate = 1000000;
193     rt_sem_init(&drv_can1.recv_semaphore, "can1_recv", 0, RT_IPC_FLAG_FIFO);
194     rt_hw_can_register(&drv_can1.device,
195                        drv_can1.name,
196                        &_can_ops,
197                        &drv_can1);
198 
199 #endif
200     return 0;
201 }
202 
203 INIT_BOARD_EXPORT(rt_hw_can_init);
204 
205 #ifdef BSP_USING_CAN0_DEBUG
206 
207 struct can_test_struct
208 {
209     const char *name;
210     struct rt_can_filter_config *filter;
211     rt_device_t candev;
212     struct rt_semaphore _sem;
213 };
214 
215 static struct can_test_struct can0_test_obj = {
216     .name = _CAN0_NAME};
217 
can_recv_irq(void * param)218 void can_recv_irq(void *param)
219 {
220     struct can_test_struct *_can_obj = (struct can_test_struct *)param;
221     rt_kprintf("can_recv_iqr \r\n");
222     rt_sem_release(&_can_obj->_sem);
223 }
224 
rt_can_test_loopback_thread_entry(void * param)225 static void rt_can_test_loopback_thread_entry(void *param)
226 {
227     struct can_test_struct *_can_obj = (struct can_test_struct *)param;
228     struct FCan_Frame recv_frame;
229     struct ft2004_can *drv_can;
230     rt_uint32_t i;
231     _can_obj->candev = rt_device_find(_can_obj->name);
232     RT_ASSERT(_can_obj->candev);
233     drv_can = (struct ft2004_can *)_can_obj->candev->user_data;
234     rt_sem_init(&_can_obj->_sem, "canrx_wait", 0, RT_IPC_FLAG_FIFO);
235     rt_device_open(_can_obj->candev, RT_DEVICE_OFLAG_RDWR);
236 
237     while (1)
238     {
239         rt_kprintf(" start to wait  loopback \r\n");
240         RTHW_CAN_WAIT(drv_can);
241         while (0 != FCan_RecvByIrq(&drv_can->can_handle, &recv_frame, 1))
242         {
243             rt_kprintf("CanId %x \r\n", recv_frame.CanId);
244             rt_kprintf("CanDlc %x \r\n", recv_frame.CanDlc);
245             for (i = 0; i < recv_frame.CanDlc; i++)
246             {
247                 rt_kprintf("data [%d] %x \r\n", i, recv_frame.data[i]);
248             }
249             FCan_SendByIrq(&drv_can->can_handle, &recv_frame, 1, RT_NULL);
250         }
251     }
252 }
253 
rt_can0_test(void)254 int rt_can0_test(void)
255 {
256     rt_thread_t tid;
257 
258     tid = rt_thread_create("can0_loopback",
259                            rt_can_test_loopback_thread_entry, &can0_test_obj,
260                            1024, 16, 20);
261     if (tid != RT_NULL)
262         rt_thread_startup(tid);
263 
264     return 0;
265 }
266 
267 INIT_APP_EXPORT(rt_can0_test);
268 
269 #endif
270 
271 #endif
272