U.B.O.R
The [U]seless [B]ox [O]rganizing [R]obot. A FreeRTOS study project written in C which implements a multitasked control unit for a belt conveyor system with robotic sorting arms.
ucan.c
Go to the documentation of this file.
1 /*****************************************************************************
2  *
3  * This program is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU General Public License
5  * as published by the Free Software Foundation; either version 2
6  * of the License, or (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16  * MA 02110-1301, USA.
17  *
18  *****************************************************************************/
24 
25 #include "ucan.h"
26 
27 /* ----- Definitions --------------------------------------------------------*/
28 #define SIZE_MAP 100 // The size of the message link map
29 #define QUEUE_SIZE 10 // Length of the data queues
30 #define STACKSIZE_TASK 256 // Stacksize for new tasks
31 #define PRIORITY_TASK 2 // Taskpriority
32 
33 /* ----- Datatypes -----------------------------------------------------------*/
34 
38 typedef struct msg_link_s {
39  QueueHandle_t queue;
40  uint16_t message_id;
41  uint16_t mask;
42 } msg_link_t;
43 
44 /* ----- Globals ------------------------------------------------------------*/
45 static CARME_CAN_MESSAGE rx_msg;
46 static CARME_CAN_MESSAGE tx_msg;
47 
48 static QueueHandle_t can_tx_queue;
49 static QueueHandle_t can_rx_queue;
50 
51 static msg_link_t message_map[SIZE_MAP];
52 static uint16_t n_message_map;
53 
54 static SemaphoreHandle_t can_semaphore;
55 
56 
57 /* ----- Functions -----------------------------------------------------------*/
58 
65 static void ucan_write_data(void *pv_data)
66 {
67  while(true) {
68  xQueueReceive(can_tx_queue, &tx_msg, portMAX_DELAY); // get latest message from queue
69 
70  /* check if semaphore is already taken */
71  if(xSemaphoreTake(can_semaphore, portMAX_DELAY) == pdTRUE) {
72  CARME_CAN_Write(&tx_msg); // Send message to CAN BUS
73  xSemaphoreGive(can_semaphore); //return semaphore
74  LOG_IF(UCAN_LOG_SENT,DISPLAY_NEWLINE, "Sent msg_id 0x%03x to can", tx_msg.id); // Log message to display
75  }
76  }
77 }
78 
86 static void ucan_read_data(void *pv_data)
87 {
88  while(true) {
89  /* check if semaphore is already taken */
90  if(xSemaphoreTake(can_semaphore, portMAX_DELAY) == pdTRUE) {
91  if (CARME_CAN_Read(&rx_msg) == CARME_NO_ERROR) {
92  xSemaphoreGive(can_semaphore); //return semaphore
93  LOG_IF(UCAN_LOG_RECEIVE,DISPLAY_NEWLINE, "Got msg_id 0x%03x", rx_msg.id); // Log message to display
94  xQueueSend(can_rx_queue, &rx_msg, portMAX_DELAY);
95  } else {
96  xSemaphoreGive(can_semaphore); //return semaphore
97  }
98  vTaskDelay(100);
99  }
100  }
101 }
102 
109 static void ucan_dispatch_data(void *pv_data)
110 {
111  CARME_CAN_MESSAGE tmp_msg;
112  QueueHandle_t queue;
113  bool match = false;
114 
115  while(true) {
116  xQueueReceive(can_rx_queue, &tmp_msg, portMAX_DELAY); // get a message from the rx queue
117  match = false;
118  /* search for the corresponding queue handles */
119  for(int i = 0; i < n_message_map; i++) {
120  /* Apply the message mask to the tmp id and search for matches in the message_map*/
121  if((tmp_msg.id & message_map[i].mask) == message_map[i].message_id) {
122  queue = message_map[i].queue;
123  match = true;
124  LOG_IF(UCAN_LOG_DISPATCH, DISPLAY_NEWLINE, "Dispatched msg_id 0x%03x", tmp_msg.id);
125  xQueueSend(queue, &tmp_msg, portMAX_DELAY); // forward it to the queue
126  }
127  }
128 
129  /* if there were no matches, drop messages */
130  if(!match) {
131  LOG_IF(UCAN_LOG_DROP,DISPLAY_NEWLINE, "Dropped msg_id 0x%03x", tmp_msg.id);
132  }
133  }
134 }
135 
141 static void ucan_setup_acceptance_filter(void)
142 {
143  CARME_CAN_ACCEPTANCE_FILTER af;
144 
145  /* set the SJA1000 chip in running mode */
146  CARME_CAN_SetMode(CARME_CAN_DF_RESET);
147 
148  /* single filter */
149  af.afm = MODE_SINGLE;
150 
151  /* Unmask the important bits by setting them to Zero */
152  af.amr[0] = 0x00; // unmask bit 0 - 7
153  af.amr[1] = 0x1f; // unmask bit 8 - 6
154  af.amr[2] = 0xff; // don't care in Mode with normal id length
155  af.amr[3] = 0xff; // don't care in Mode with normal id length
156 
157  /* Set the bits which have to be high */
158  af.acr[0] = 0xAA; // 11001100
159  af.acr[1] = 0xA0; // 11000000
160  af.acr[2] = 0x00; // don't care in Mode with normal id length
161  af.acr[3] = 0x00; // don't care in Mode with normal id length
162 
163  /* Set the AF */
164  CARME_CAN_SetAcceptaceFilter(&af);
165 
166  /* Set the SJA1000 chip in running mode */
167  CARME_CAN_SetMode(CARME_CAN_DF_NORMAL);
168 }
169 
178 bool ucan_link_message_to_queue_mask(uint16_t mask, uint16_t message_id, QueueHandle_t queue)
179 {
180  /* Check if there is enough space left */
181  if(n_message_map >= SIZE_MAP) {
182  return false;
183  }
184 
185  /* increment message counter, save message_id, the mask and the corresponding queue */
186  message_map[n_message_map].message_id = message_id;
187  message_map[n_message_map].queue = queue;
188  message_map[n_message_map].mask = mask;
189  n_message_map++;
190 
191  return true;
192 
193 }
194 
202 bool ucan_link_message_to_queue(uint16_t message_id, QueueHandle_t queue)
203 {
204  return ucan_link_message_to_queue_mask(0x0FFF, message_id, queue);
205 }
206 
212 bool ucan_init(void)
213 {
214  GPIO_InitTypeDef g;
215 
216  /* Init gpio for can */
217  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
218  g.GPIO_Pin = GPIO_Pin_0;
219  g.GPIO_Mode = GPIO_Mode_OUT;
220  g.GPIO_OType = GPIO_OType_PP;
221  g.GPIO_Speed = GPIO_Speed_2MHz;
222  g.GPIO_PuPd = GPIO_PuPd_NOPULL;
223  GPIO_Init(GPIOA, &g);
224 
225  /* Init can chip */
226  CARME_CAN_Init(CARME_CAN_BAUD_250K, CARME_CAN_DF_RESET);
227  CARME_CAN_SetMode(CARME_CAN_DF_NORMAL);
228 
229  /* Setup acceptance filter, unused in the scope of this project*/
230  //ucan_setup_acceptance_filter();
231 
232  /* Clear the rx and tx CAN message */
233  for(int i = 0; i < 7; i++) {
234  rx_msg.data[i] = 0;
235  tx_msg.data[i] = 0;
236  }
237 
238  /* Create message queues for can communication */
239  can_tx_queue = xQueueCreate(QUEUE_SIZE, sizeof(CARME_CAN_MESSAGE));
240  can_rx_queue = xQueueCreate(QUEUE_SIZE, sizeof(CARME_CAN_MESSAGE));
241 
242  /* create binary semaphore */
243  can_semaphore = xSemaphoreCreateBinary();
244  xSemaphoreGive(can_semaphore);
245 
246  n_message_map = 0;
247 
248  /* Spawn tasks */
249  xTaskCreate(ucan_write_data, "CAN_Write_Task", STACKSIZE_TASK, NULL, PRIORITY_TASK, NULL);
250  xTaskCreate(ucan_read_data, "CAN_Read_Task", STACKSIZE_TASK, NULL, PRIORITY_TASK, NULL);
251  xTaskCreate(ucan_dispatch_data, "CAN_Dispatch_Task", STACKSIZE_TASK, NULL, PRIORITY_TASK, NULL);
252 
253  return true;
254 }
255 
264 bool ucan_send_data(uint8_t n_data_bytes, uint16_t msg_id, const uint8_t *data)
265 {
266  CARME_CAN_MESSAGE tmp_msg;
267 
268  /* Setup basic CAN message header for temporary message */
269  tmp_msg.id = msg_id; // Message ID
270  tmp_msg.rtr = 0; // Something weird
271  tmp_msg.ext = 0; // Something weird
272  tmp_msg.dlc = n_data_bytes; // Number of bytes
273 
274  memcpy(tmp_msg.data, data, min(n_data_bytes, 8)); // copy databytes to output buffer but only 8bytes
275  LOG_IF(UCAN_LOG_SENDING,DISPLAY_NEWLINE, "Insert msg_id 0x%03x to queue", msg_id); // Log message to display
276  xQueueSend(can_tx_queue, &tmp_msg, portMAX_DELAY); // Send message to the message queue
277 
278  return true;
279 }
280 
#define LOG_IF(cond,...)
Definition: ucan.h:28
#define DISPLAY_NEWLINE
Definition: display.h:10
struct msg_link_s msg_link_t
This datatype combines a message queue its id and a mask for filtering.
#define UCAN_LOG_RECEIVE
Set loglevel to recieved messages.
Definition: ucan.h:24
#define STACKSIZE_TASK
Definition: ucan.c:30
bool ucan_init(void)
Initialize the hardware and call each init function global.
Definition: ucan.c:212
#define UCAN_LOG_SENT
Enable or disable logging by setting this to either true or false.
Definition: ucan.h:22
bool ucan_link_message_to_queue(uint16_t message_id, QueueHandle_t queue)
Link a single message type to a queue global.
Definition: ucan.c:202
bool ucan_send_data(uint8_t n_data_bytes, uint16_t msg_id, const uint8_t *data)
Send data to the can output message queue global.
Definition: ucan.c:264
#define SIZE_MAP
Definition: ucan.c:28
#define UCAN_LOG_SENDING
Set loglevel to sent messages.
Definition: ucan.h:23
bool ucan_link_message_to_queue_mask(uint16_t mask, uint16_t message_id, QueueHandle_t queue)
Set a message mask to map multiple message to a queue global.
Definition: ucan.c:178
#define UCAN_LOG_DROP
Set loglevel to dropped messages (unable to dispatch)
Definition: ucan.h:26
#define PRIORITY_TASK
Definition: ucan.c:31
#define QUEUE_SIZE
Definition: ucan.c:29
#define UCAN_LOG_DISPATCH
Set loglevel to dispatched messages.
Definition: ucan.h:25