]> rtime.felk.cvut.cz Git - pes-rpp/rpp-test-sw.git/blob - rpp-test-sw/commands/cmd_can.c
Fix indentation
[pes-rpp/rpp-test-sw.git] / rpp-test-sw / commands / cmd_can.c
1 /*
2  * Copyright (C) 2012-2013 Czech Technical University in Prague
3  *
4  * Created on: 28.2.2013
5  *
6  * Authors:
7  *     - Michal Horn
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  * File : cmd_can.c
23  *
24  * Abstract:
25  *      This file contains commands for CAN test
26  *
27  */
28
29 #include "cmd_can.h"
30
31 #ifndef DOCGEN
32
33 #include "rpp/rpp.h"
34 #include "sys/sys.h"
35 #include <stdio.h>
36
37 /** Semaphore used for blocking task until message is received */
38 extern xSemaphoreHandle canMsgReceived;
39 /** Semaphore used for blocking task until message is sent */
40 extern xSemaphoreHandle canMsgSent;
41 /** Pointer to Destination CAN registers */
42 extern canBASE_t* canDst;
43 /** Pointer to Source CAN registers */
44 extern canBASE_t* canSrc;
45 /** Can message box for received messages */
46 extern uint32_t canMsgBox;
47 /** Error counter for errors in sending */
48 extern uint32_t canSendError;
49 /** Error counter for errors in receiving */
50 extern uint32_t canRecError;
51
52 static void canPrintStatus(int can_num, uint32_t es)
53 {
54         uint32_t errorLevel = es & 0xE0U;
55         char* levText;
56
57         switch (errorLevel) {
58         case canLEVEL_BUS_OFF:
59                 levText = "Bus-Off";
60                 break;
61         case canLEVEL_PASSIVE:
62                 levText = "Error Passive";
63                 break;
64         case canLEVEL_WARNING:
65                 levText = "Warning";
66                 break;
67         case canLEVEL_ACTIVE:
68                 levText = "Bus-On";
69                 break;
70         default:
71                 levText = "Unknown";
72         }
73
74         rpp_sci_printf("CAN%d status: %s, ES: %#x\n", can_num, levText, es);
75 }
76
77 uint32_t canCheckForError(int can_num, uint32_t es)
78 {
79         uint32_t errorLevel = es & 0xE0U;
80
81         if (errorLevel != 0) {
82                 canPrintStatus(can_num, es);
83         }
84
85         return errorLevel;
86 }
87
88 /**
89  *      @brief  Command for external CAN loopback testing.
90  *
91  * @param[in]   cmd_io  Pointer to IO stack
92  * @param[in]   des             Pointer to command descriptor
93  * @param[in]   param   Parameters of command
94  * @return      0 when OK or error code
95  */
96 int cmd_do_test_can_loopback(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
97 {
98         uint32_t can_src, can_dst;
99         canBASE_t *canBases[3] = {canREG1, canREG2, canREG3};
100         uint32_t canMailBoxes[3] = {canMESSAGE_BOX1, canMESSAGE_BOX2, canMESSAGE_BOX3};
101         uint32_t txTimeOutCnt = 0;
102         uint32_t rxTimeOutCnt = 0;
103         uint32_t messagesTransmitted = 0;
104         uint32_t messagesReceived = 0;
105         uint32_t i;
106         uint8_t tx_data[8] = {'T', 'E', 'S', 'T', ' ', 'C', 'A', 'N'};
107         uint8_t rx_data[8] = {0, 0, 0, 0, 0, 0, 0, 0 };
108         char *p=param[1];
109         char spareParams;
110
111
112         dmmREG->PC4 = (1<<(13)); // set CAN_NSTB
113         vTaskDelay(50/portTICK_RATE_MS);
114         dmmREG->PC5 = (1<<(15)); // clr CAN_EN
115         vTaskDelay(50/portTICK_RATE_MS);
116         dmmREG->PC5 = (1<<(13)); // clr CAN_NSTB
117         vTaskDelay(50/portTICK_RATE_MS);
118         dmmREG->PC4 = (1<<(13)); // set CAN_NSTB
119         vTaskDelay(50/portTICK_RATE_MS);
120         dmmREG->PC4 = (1<<(15)); // set CAN_EN
121         vTaskDelay(50/portTICK_RATE_MS);
122
123
124         if (sscanf(p, "%d %d %1s", &can_src, &can_dst, &spareParams) != 2) {
125                 return -CMDERR_BADPAR;
126         }
127
128         if (can_src == can_dst) {
129                 rpp_sci_printf("ERROR: Destination equals source!\n");
130                 return 1;
131         }
132         if (can_src < 1 | can_dst > 3) {
133                 rpp_sci_printf("Parameter out of range <1;3>!\n");
134                 return 1;
135         }
136         canSrc = canBases[can_src-1];
137         canDst = canBases[can_dst-1];
138         canMsgBox = canMailBoxes[can_src-1];
139         canMsgReceived = xSemaphoreCreateCounting(1, 0);
140         canMsgSent = xSemaphoreCreateCounting(1, 0);
141
142         rpp_sci_printf("Testing CAN loopback\r\n");
143         canREG1->CTL |= 1|(1<<9);
144         canREG2->CTL |= 1|(1<<9);
145         canREG3->CTL |= 1|(1<<9);
146         canRecError = 0;
147         canDst->CTL |= 1<<15;           // Reset
148         while (canDst->CTL & (1<<15)) ; // Wait for reset
149         canSendError = 0;
150         canSrc->CTL |= 1<<15;
151         while (canSrc->CTL & (1<<15)) ;
152         canInit();
153         canDst->CTL |= 1<<9;
154         canSrc->CTL |= 1<<9;
155         vTaskDelay(50/portTICK_RATE_MS);
156
157         i = canSrc->ES; // Reset error flag
158         i = canDst->ES; // Reset error flag
159         canEnableErrorNotification(canDst);
160         canEnableErrorNotification(canSrc);
161
162         for (i = 0; i < 100; i++) {             // Send 100 times the message
163                 if (canCheckForError(can_src, canSendError) != canLEVEL_ACTIVE) {
164                         break;
165                 }
166                 canTransmit(canSrc, canMsgBox, tx_data);
167                 if (xSemaphoreTake(canMsgSent, 100/portTICK_RATE_MS) == pdFALSE) {
168                         txTimeOutCnt++;
169                 }
170                 else {
171                         if (canCheckForError(can_src, canSendError) & canLEVEL_BUS_OFF) {
172                                 break;
173                         }
174                         else {
175                                 messagesTransmitted++;
176                                 if (xSemaphoreTake(canMsgReceived, 100/portTICK_RATE_MS) == pdFALSE) {
177                                         rxTimeOutCnt++;
178                                 }
179                                 else {
180                                         if (canGetData(canDst, canMsgBox, rx_data))
181                                                 messagesReceived++;
182
183                                         if (canCheckForError(can_dst, canRecError) & canLEVEL_BUS_OFF) {
184                                                 break;
185                                         }
186                                 }
187                         }
188                 }
189
190                 rpp_sci_printf("Messages transmitted: %d/100\r\n", messagesTransmitted);
191                 rpp_sci_printf("Messages received: %d/100\r\n", messagesReceived);
192                 rpp_sci_printf("TX timeouts: %d\r\n", txTimeOutCnt);
193                 rpp_sci_printf("RX timeouts: %d\r\n", rxTimeOutCnt);
194                 rpp_sci_printf("Src TX error counter: %d\r\n", canSrc->EERC & 0xFFU);
195                 rpp_sci_printf("Src RX error counter: %d\r\n", (canSrc->EERC & 0xFF00U) >> 8);
196                 rpp_sci_printf("Dst TX error counter: %d\r\n", canDst->EERC & 0xFFU);
197                 rpp_sci_printf("Dst RX error counter: %d\r\n", (canDst->EERC & 0xFF00U) >> 8);
198                 canPrintStatus(can_src, canSendError);
199                 canPrintStatus(can_dst, canRecError);
200
201                 canDisableErrorNotification(canDst);
202                 canDisableErrorNotification(canSrc);
203                 vSemaphoreDelete(canMsgReceived);
204                 vSemaphoreDelete(canMsgSent);
205                 return 0;
206         }
207
208 }
209
210
211 static int can_inited = 0;
212
213 static struct rpp_can_ctrl_config ctrl_config[] = {
214         {
215                 .baudrate = 500000
216         },
217         {
218                 .baudrate = 500000
219         },
220         {
221                 .baudrate = 500000
222         }
223 };
224
225 static struct rpp_can_tx_config tx_config[] = {
226         {
227                 .type = RPP_CAN_EXTENDED,
228                 .controller = 1,
229                 .msg_obj = 2,
230         },
231         {
232                 .type = RPP_CAN_EXTENDED,
233                 .controller = 2,
234                 .msg_obj = 2,
235         },
236         {
237                 .type = RPP_CAN_EXTENDED,
238                 .controller = 3,
239                 .msg_obj = 2,
240         }
241 };
242
243 static struct rpp_can_rx_config rx_config[] = {
244         {
245                 .type = RPP_CAN_MIXED,
246                 .controller = 1,
247                 .msg_obj = 1,
248                 .id = 1,
249                 .mask = 0,
250         },
251         {
252                 .type = RPP_CAN_MIXED,
253                 .controller = 2,
254                 .msg_obj = 1,
255                 .id = 1,
256                 .mask = 0,
257         },
258         {
259                 .type = RPP_CAN_MIXED,
260                 .controller = 3,
261                 .msg_obj = 1,
262                 .id = 1,
263                 .mask = 0,
264         }
265 };
266
267 static struct rpp_can_config can_config = {
268         .num_tx_obj = 3,
269         .num_rx_obj = 3,
270         .tx_config = tx_config,
271         .rx_config = rx_config,
272         .ctrl = ctrl_config,
273 };
274
275
276 int cmd_do_can_init(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
277 {
278     dmmREG->PC4 = (1<<(13)); // set CAN_NSTB
279     dmmREG->PC5 = (1<<(15)); // clr CAN_EN
280     dmmREG->PC5 = (1<<(13)); // clr CAN_NSTB
281     dmmREG->PC4 = (1<<(13)); // set CAN_NSTB
282     dmmREG->PC4 = (1<<(15)); // set CAN_EN
283
284
285
286     can_inited = (rpp_can_init(&can_config) == SUCCESS ? 1 : 0);
287     return (can_inited ? 0 : 1);
288 }
289
290
291 int cmd_do_can_send(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
292 {
293         uint32_t controller_id;
294         uint32_t i, l = 0;
295         int ret;
296         struct rpp_can_pdu pdu;
297         char *p;
298
299         if (!can_inited)
300         {
301                 rpp_sci_printf("WARNING: CAN is not initialized\n");
302         }
303
304         p = param[1];
305         ret = sscanf(p, "%i %i%n", &controller_id, &pdu.id, &l);
306         if (ret < 2)
307         {
308                 rpp_sci_printf("Cannot parse parameter %d\n", ret+1);
309                 return -CMDERR_BADPAR;
310         }
311         p += l;
312
313         i = 0;
314         do {
315                 ret = sscanf(p, "%2hhx%n", &pdu.data[i], &l);
316                 if (ret < 1) break;
317                 i++;
318                 p += l;
319         } while (1);
320
321         pdu.dlc = i;
322
323
324         if (rpp_can_write(controller_id-1, &pdu) == SUCCESS)
325         {
326                 rpp_sci_printf("Sent: can%u\t%X\t[%u]\t", controller_id, pdu.id, pdu.dlc);
327                 for (i=0; i<pdu.dlc; i++)
328                 {
329                         rpp_sci_printf("%X ", pdu.data[i]);
330                 }
331         }
332         else
333         {
334                 rpp_sci_printf("Error: rpp_can_write");
335         }
336         rpp_sci_printf("\n");
337
338
339         return 0;
340 }
341
342
343 int cmd_do_can_dump(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
344 {
345         uint32_t controller_id = 0;
346         bool rx_ind;
347         struct rpp_can_pdu pdu;
348
349         uint32_t i;
350
351         if (!can_inited)
352         {
353                 rpp_sci_printf("WARNING: CAN is not initialized\n");
354         }
355
356         if (!(sscanf(param[1], "%u", &controller_id) == 1))
357         {
358                 rpp_sci_printf("Unable to parse controller ID\n");
359                 return 1;
360         }
361
362         rpp_can_init(&can_config);
363
364         while(cmd_io->getc(cmd_io) < 0)
365         {
366                 rpp_can_check_rx_ind(controller_id-1, &rx_ind);
367                 if (rx_ind)
368                 {
369                         if (rpp_can_read(controller_id-1, &pdu) == SUCCESS)
370                         {
371                                 if (pdu.id & CAN_EFF_FLAG)
372                                 {
373                                         rpp_sci_printf("can%u  %08X  [%u]  ", controller_id & (~CAN_EFF_FLAG), pdu.id, pdu.dlc);
374                                 }
375                                 else
376                                 {
377                                         rpp_sci_printf("can%u  %03X  [%u]  ", controller_id, pdu.id, pdu.dlc);
378                                 }
379
380                                 for (i=0; i<pdu.dlc; i++)
381                                 {
382                                             rpp_sci_printf("%X ", pdu.data[i]);
383                                 }
384                                 rpp_sci_printf("\n");
385                         }
386                         else
387                         {
388                                 rpp_sci_printf("Error rpp_can_read\n");
389                         }
390                 }
391         }
392
393         return 0;
394 }
395
396
397 int cmd_do_can_change_baudrate(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
398 {
399         int opchar;
400         uint32_t controller_id, baudrate;
401
402         if ((opchar = cmd_opchar_check(cmd_io, des, param)) < 0)
403                 return opchar;
404
405         if (opchar == ':')
406         {
407                 if (!(sscanf(param[1], "%u:%u", &controller_id, &baudrate) == 2))
408                 {
409                         rpp_sci_printf("Unable to parse arguments\n");
410                         return 1;
411                 }
412
413                 if (controller_id < 1 || controller_id > 3)
414                         return -CMDERR_BADPAR;
415
416                 can_config.ctrl[controller_id-1].baudrate = baudrate;
417         }
418         else
419         {
420                 if (!(sscanf(param[1], "%u", &controller_id) == 1))
421
422                 if (controller_id < 1 || controller_id > 3)
423                         return -CMDERR_BADPAR;
424
425                 cmd_opchar_replong(cmd_io, param, can_config.ctrl[controller_id-1].baudrate, 0, 10);
426         }
427
428         return 0;
429 }
430
431
432
433 #endif  /* DOCGEN */
434
435 /** @brief command descriptor for test CAN loopback command */
436 cmd_des_t const cmd_des_test_can_loopback={
437     0, 0,
438     "cantest*", "Test CAN loopback between two CAN interfaces",
439     "=== Command syntax ===\n"
440     "\n"
441     "   cantest<SOURCE> <DESTINATION>\n"
442     "\n"
443     "where <SOURCE> and <DESTINATION> are different numbers in range 1-3.\n"
444     "\n"
445     "=== Description ===\n"
446     "\n"
447     "This command tests CAN communication by sending and receiving messages\n"
448     "through external loopback. At the beginning, the involved CAN\n"
449     "controller are initialized to the Bus-On state.\n"
450     "\n"
451     "The command sends 100 messages and measures the numbers of TX errors,\n"
452     "RX errors and detected timeouts. At the end, these statistics are\n"
453     "printed as well as the status of the involved CAN controllers.\n"
454     "\n"
455     "When an error is detected during the test, the status of faulty CAN\n"
456     "controller is printed immediately.\n"
457     "\n"
458     "=== Example ===\n"
459     "\n"
460     "   --> cantest1 2\n"
461     "   Testing CAN loopback\n"
462     "   Messages transmitted: 100/100\n"
463     "   Messages received: 100/100\n"
464     "   TX timeouts: 0\n"
465     "   RX timeouts: 0\n"
466     "   Src TX error counter: 0\n"
467     "   Src RX error counter: 0\n"
468     "   Dst TX error counter: 0\n"
469     "   Dst RX error counter: 0\n"
470     "   CAN1 status: Bus-On, ES: 0x8\n"
471     "   CAN2 status: Bus-On, ES: 0x10\n",
472     CMD_HANDLER(cmd_do_test_can_loopback), (void *)&cmd_list_can
473 };
474
475
476 cmd_des_t const cmd_des_can_init={
477     0, 0,
478     "caninit", "Initialize CAN controllers",
479     "=== Command syntax ===\n"
480     "\n"
481     "   caninit\n"
482     "\n"
483     "=== Description ===\n"
484     "\n"
485     "This command (re-)initializes all CAN controllers using current\n"
486     "CAN configuration. This configuration can be changed using\n"
487     "canbaudrate command.\n"
488     "\n"
489     "Default configuration sets baudrate of all CAN controllers to 0.5 Mbit/s\n"
490     "\n"
491     "=== Example ===\n"
492     "  --> caninit\n",
493     CMD_HANDLER(cmd_do_can_init), (void *)&cmd_list_can
494 };
495
496 cmd_des_t const cmd_des_can_baudrate={
497     0, CDESM_OPCHR|CDESM_RW,
498     "canbaudrate#", "Change baudrate of CAN controller",
499     "=== Command syntax ===\n"
500     "\n"
501     "   canbaudrate<CONTROLLER>?\n"
502     "   canbaudrate<CONTROLLER>:<BAUDRATE>\n"
503     "\n"
504     "where <CONTROLLER> is number in range 1-3 and BAUDRATE is number\n"
505     "in range 1000-10000000.\n"
506     "\n"
507     "=== Description ===\n"
508     "\n"
509     "This command is used to set or show baudrate of CAN controller.\n"
510     "The baudrate shown is the one which would be set if caninit was\n"
511     "called now.\n"
512     "\n"
513     "=== Examples ===\n"
514     "\n"
515     "   --> canbaudrate2?\n"
516     "   canbaudrate2=500000\n"
517     "\n"
518     "   --> canbaudrate2:100000\n",
519     CMD_HANDLER(cmd_do_can_change_baudrate), (void *)&cmd_list_can
520 };
521
522 cmd_des_t const cmd_des_can_send={
523     0, 0,
524     "cansend", "Test sending message over CAN",
525     "=== Command syntax ===\n"
526     "\n"
527     "   cansend <CONTROLLER> <ID> <DATA>\n"
528     "\n"
529     "where <CONTROLLER> is number in range 1-3, <ID> is valid CAN ID\n"
530     "and <DATA> is 0-8 bytes of data in hexadecimal representation.\n"
531     "There may be any number of spaces between data bytes.\n"
532     "<ID> may be given in octal, decimal or hexadecimal base.\n"
533     "\n"
534     "=== Description ===\n"
535     "\n"
536     "This command sends a CAN frame using specified CAN controller.\n"
537     "\n"
538     "caninit shall be called before using this command, sending may\n"
539     "behave unexpectedly otherwise.\n"
540     "\n"
541     "=== Example ===\n"
542     "   --> cansend 2 0x123 DEAD BEEF\n"
543     "   Sent: can2      123     [4]     DE AD BE EF\n",
544     CMD_HANDLER(cmd_do_can_send), (void *)&cmd_list_can
545 };
546
547
548 cmd_des_t const cmd_des_can_dump={
549     0, 0,
550     "candump", "Dump all messages received over CAN",
551     "=== Command syntax ===\n"
552     "\n"
553     "   candump <CONTROLLER>\n"
554     "\n"
555     "where <CONTROLLER> is number in range 1-3.\n"
556     "\n"
557     "=== Description ===\n"
558     "\n"
559     "This command prints out any CAN message received via specified\n"
560     "controller.\n"
561     "\n"
562     "IDs are zero-filled to length 3 if standard ID is used and to 8\n"
563     "if extended ID is used.\n"
564     "\n"
565     "caninit shall be called before using this command, dump may\n"
566     "behave unexpectedly otherwise.\n"
567     "\n"
568     "=== Example ===\n"
569     "\n"
570     "   --> candump 2\n"
571     "can2  0000FADE  [2]  12 34\n",
572     CMD_HANDLER(cmd_do_can_dump), (void *)&cmd_list_can
573 };
574
575
576
577 cmd_des_t const *cmd_list_can[]={
578   &cmd_des_test_can_loopback,
579   &cmd_des_can_init,
580   &cmd_des_can_baudrate,
581   &cmd_des_can_send,
582   &cmd_des_can_dump,
583   NULL
584 };