1 /*
2  * CAN module object for Linux SocketCAN.
3  *
4  * @file        CO_driver.h
5  * @author      Janez Paternoster
6  * @copyright   2015 - 2020 Janez Paternoster
7  *
8  * This file is part of CANopenNode, an opensource CANopen Stack.
9  * Project home page is <https://github.com/CANopenNode/CANopenNode>.
10  * For more information on CANopen see <http://www.can-cia.org/>.
11  *
12  * Licensed under the Apache License, Version 2.0 (the "License");
13  * you may not use this file except in compliance with the License.
14  * You may obtain a copy of the License at
15  *
16  *     http://www.apache.org/licenses/LICENSE-2.0
17  *
18  * Unless required by applicable law or agreed to in writing, software
19  * distributed under the License is distributed on an "AS IS" BASIS,
20  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  * See the License for the specific language governing permissions and
22  * limitations under the License.
23  */
24 
25 
26 #ifndef CO_DRIVER_TARGET_H
27 #define CO_DRIVER_TARGET_H
28 
29 
30 /* For documentation see file drvTemplate/CO_driver.h */
31 
32 
33 #include <stddef.h>         /* for 'NULL' */
34 #include <stdint.h>         /* for 'int8_t' to 'uint64_t' */
35 #include <stdbool.h>        /* for 'true', 'false' */
36 #include <unistd.h>
37 #include <endian.h>
38 
39 #ifndef CO_SINGLE_THREAD
40 #include <pthread.h>
41 #endif
42 
43 #include <linux/can.h>
44 #include <linux/can/raw.h>
45 #include <linux/can/error.h>
46 
47 
48 /* Endianness */
49 #ifdef BYTE_ORDER
50 #if BYTE_ORDER == LITTLE_ENDIAN
51     #define CO_LITTLE_ENDIAN
52 #else
53     #define CO_BIG_ENDIAN
54 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
55 #endif /* BYTE_ORDER */
56 
57 
58 /* general configuration */
59 //    #define CO_LOG_CAN_MESSAGES   /* Call external function for each received or transmitted CAN message. */
60     #define CO_SDO_BUFFER_SIZE           889    /* Override default SDO buffer size. */
61 
62 
63 /* Critical sections */
64 #ifdef CO_SINGLE_THREAD
65     #define CO_LOCK_CAN_SEND()
66     #define CO_UNLOCK_CAN_SEND()
67 
68     #define CO_LOCK_EMCY()
69     #define CO_UNLOCK_EMCY()
70 
71     #define CO_LOCK_OD()
72     #define CO_UNLOCK_OD()
73 
74     #define CANrxMemoryBarrier()
75 #else
76     #define CO_LOCK_CAN_SEND()      /* not needed */
77     #define CO_UNLOCK_CAN_SEND()
78 
79     extern pthread_mutex_t CO_EMCY_mtx;
80     #define CO_LOCK_EMCY()          {if(pthread_mutex_lock(&CO_EMCY_mtx) != 0) CO_errExit("Mutex lock CO_EMCY_mtx failed");}
81     #define CO_UNLOCK_EMCY()        {if(pthread_mutex_unlock(&CO_EMCY_mtx) != 0) CO_errExit("Mutex unlock CO_EMCY_mtx failed");}
82 
83     extern pthread_mutex_t CO_OD_mtx;
84     #define CO_LOCK_OD()            {if(pthread_mutex_lock(&CO_OD_mtx) != 0) CO_errExit("Mutex lock CO_OD_mtx failed");}
85     #define CO_UNLOCK_OD()          {if(pthread_mutex_unlock(&CO_OD_mtx) != 0) CO_errExit("Mutex unlock CO_OD_mtx failed");}
86 
87     #define CANrxMemoryBarrier()    {__sync_synchronize();}
88 #endif /* CO_SINGLE_THREAD */
89 
90 /* Syncronisation functions */
91 #define IS_CANrxNew(rxNew) ((uintptr_t)rxNew)
92 #define SET_CANrxNew(rxNew) {CANrxMemoryBarrier(); rxNew = (void*)1L;}
93 #define CLEAR_CANrxNew(rxNew) {CANrxMemoryBarrier(); rxNew = (void*)0L;}
94 
95 
96 /* Data types */
97 /* int8_t to uint64_t are defined in stdint.h */
98 typedef _Bool                   bool_t;
99 typedef float                   float32_t;
100 typedef double                  float64_t;
101 typedef char                    char_t;
102 typedef unsigned char           oChar_t;
103 typedef unsigned char           domain_t;
104 
105 
106 /* CAN receive message structure as aligned in CAN module. */
107 typedef struct{
108     uint32_t        ident;
109     uint8_t         DLC;
110     uint8_t         data[8] __attribute__((aligned(8)));
111 }CO_CANrxMsg_t;
112 
113 
114 /* Received message object */
115 typedef struct{
116     uint32_t            ident;
117     uint32_t            mask;
118     void               *object;
119     void              (*pFunct)(void *object, const CO_CANrxMsg_t *message);
120 }CO_CANrx_t;
121 
122 
123 /* Transmit message object as aligned in CAN module. */
124 typedef struct{
125     uint32_t            ident;
126     uint8_t             DLC;
127     uint8_t             data[8] __attribute__((aligned(8)));
128     volatile bool_t     bufferFull;
129     volatile bool_t     syncFlag;
130 }CO_CANtx_t;
131 
132 
133 /* CAN module object. */
134 typedef struct{
135     void               *CANdriverState;
136 #ifdef CO_LOG_CAN_MESSAGES
137     CO_CANtx_t          txRecord;
138 #endif
139     CO_CANrx_t         *rxArray;
140     uint16_t            rxSize;
141     CO_CANtx_t         *txArray;
142     uint16_t            txSize;
143     uint16_t            wasConfigured;/* Zero only on first run of CO_CANmodule_init */
144     int                 fd;         /* CAN_RAW socket file descriptor */
145     struct can_filter  *filter;     /* array of CAN filters of size rxSize */
146     volatile bool_t     CANnormal;
147     volatile bool_t     useCANrxFilters;
148     volatile bool_t     bufferInhibitFlag;
149     volatile bool_t     firstCANtxMessage;
150     volatile uint8_t    error;
151     volatile uint16_t   CANtxCount;
152     uint32_t            errOld;
153     void               *em;
154 }CO_CANmodule_t;
155 
156 /* Helper function, must be defined externally. */
157 void CO_errExit(char* msg);
158 
159 
160 /* Functions receives CAN messages. It is blocking.
161  *
162  * @param CANmodule This object.
163  */
164 void CO_CANrxWait(CO_CANmodule_t *CANmodule);
165 
166 
167 #endif /* CO_DRIVER_TARGET_H */
168