]> rtime.felk.cvut.cz Git - pes-rpp/rpp-test-sw.git/blob - rpp-test-sw/commands/cmd_can.c
doc: Remove extra quotes
[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         return 0;
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("CAN is not initialized\n");
302                 return -CMDERR_NODEV;
303         }
304
305         p = param[1];
306         ret = sscanf(p, "%i %i%n", &controller_id, &pdu.id, &l);
307         if (ret < 2)
308         {
309                 rpp_sci_printf("Cannot parse parameter %d\n", ret+1);
310                 return -CMDERR_BADPAR;
311         }
312         p += l;
313
314         i = 0;
315         do {
316                 uint16_t data;
317                 ret = sscanf(p, "%2hx%n", &data, &l);
318                 if (ret < 1) break;
319                 pdu.data[i] = data & 0xff;
320                 i++;
321                 p += l;
322         } while (1);
323
324         pdu.dlc = i;
325
326
327         if (rpp_can_write(controller_id-1, &pdu) == SUCCESS)
328         {
329                 rpp_sci_printf("Sent: can%u\t%X\t[%u]\t", controller_id, pdu.id, pdu.dlc);
330                 for (i=0; i<pdu.dlc; i++)
331                 {
332                         rpp_sci_printf("%X ", pdu.data[i]);
333                 }
334         }
335         else
336         {
337                 rpp_sci_printf("Error: rpp_can_write");
338         }
339         rpp_sci_printf("\n");
340
341
342         return 0;
343 }
344
345
346 int cmd_do_can_dump(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
347 {
348         uint32_t controller_id = 0;
349         bool rx_ind;
350         struct rpp_can_pdu pdu;
351
352         uint32_t i;
353
354         if (!can_inited)
355         {
356                 rpp_sci_printf("CAN is not initialized\n");
357                 return -CMDERR_NODEV;
358         }
359
360         if (!(sscanf(param[1], "%u", &controller_id) == 1))
361         {
362                 rpp_sci_printf("Unable to parse controller ID\n");
363                 return 1;
364         }
365
366         rpp_can_init(&can_config);
367
368         while(cmd_io->getc(cmd_io) < 0)
369         {
370                 rpp_can_check_rx_ind(controller_id-1, &rx_ind);
371                 if (rx_ind)
372                 {
373                         if (rpp_can_read(controller_id-1, &pdu) == SUCCESS)
374                         {
375                                 if (pdu.id & CAN_EFF_FLAG)
376                                 {
377                                         rpp_sci_printf("can%u  %08X  [%u]  ", controller_id & (~CAN_EFF_FLAG), pdu.id, pdu.dlc);
378                                 }
379                                 else
380                                 {
381                                         rpp_sci_printf("can%u  %03X  [%u]  ", controller_id, pdu.id, pdu.dlc);
382                                 }
383
384                                 for (i=0; i<pdu.dlc; i++)
385                                 {
386                                             rpp_sci_printf("%X ", pdu.data[i]);
387                                 }
388                                 rpp_sci_printf("\n");
389                         }
390                         else
391                         {
392                                 rpp_sci_printf("Error rpp_can_read\n");
393                         }
394                 }
395         }
396
397         return 0;
398 }
399
400
401 int cmd_do_can_change_baudrate(cmd_io_t *cmd_io, const struct cmd_des *des, char *param[])
402 {
403         int opchar;
404         uint32_t controller_id, baudrate;
405
406         if ((opchar = cmd_opchar_check(cmd_io, des, param)) < 0)
407                 return opchar;
408
409         if (opchar == ':')
410         {
411                 if (!(sscanf(param[1], "%u:%u", &controller_id, &baudrate) == 2))
412                 {
413                         rpp_sci_printf("Unable to parse arguments\n");
414                         return 1;
415                 }
416
417                 if (controller_id < 1 || controller_id > 3)
418                         return -CMDERR_BADPAR;
419
420                 can_config.ctrl[controller_id-1].baudrate = baudrate;
421         }
422         else
423         {
424                 if (!(sscanf(param[1], "%u", &controller_id) == 1))
425
426                 if (controller_id < 1 || controller_id > 3)
427                         return -CMDERR_BADPAR;
428
429                 cmd_opchar_replong(cmd_io, param, can_config.ctrl[controller_id-1].baudrate, 0, 10);
430         }
431
432         return 0;
433 }
434
435
436
437 #endif  /* DOCGEN */
438
439 /** @brief command descriptor for test CAN loopback command */
440 cmd_des_t const cmd_des_test_can_loopback={
441     0, 0,
442     "cantest*", "Test CAN loopback between two CAN interfaces",
443     "### Command syntax ###\n"
444     "\n"
445     "    cantest<SRC> <DST>\n"
446     "\n"
447     "where `<SRC>` and `<DST>` are different numbers in range 1-3.\n"
448     "\n"
449     "### Description ###\n"
450     "\n"
451     "This command tests CAN communication by sending and receiving messages\n"
452     "through external loopback. At the beginning, the involved CAN\n"
453     "controller are initialized to the Bus-On state.\n"
454     "\n"
455     "The command sends 100 messages and measures the numbers of TX errors,\n"
456     "RX errors and detected timeouts. At the end, these statistics are\n"
457     "printed as well as the status of the involved CAN controllers.\n"
458     "\n"
459     "When an error is detected during the test, the status of faulty CAN\n"
460     "controller is printed immediately.\n"
461     "\n"
462     "### Example ###\n"
463     "\n"
464     "    --> cantest1 2\n"
465     "    Testing CAN loopback\n"
466     "    Messages transmitted: 100/100\n"
467     "    Messages received: 100/100\n"
468     "    TX timeouts: 0\n"
469     "    RX timeouts: 0\n"
470     "    Src TX error counter: 0\n"
471     "    Src RX error counter: 0\n"
472     "    Dst TX error counter: 0\n"
473     "    Dst RX error counter: 0\n"
474     "    CAN1 status: Bus-On, ES: 0x8\n"
475     "    CAN2 status: Bus-On, ES: 0x10\n",
476     CMD_HANDLER(cmd_do_test_can_loopback), (void *)&cmd_list_can
477 };
478
479
480 cmd_des_t const cmd_des_can_init={
481     0, 0,
482     "caninit", "Initialize CAN controllers",
483     "### Command syntax ###\n"
484     "\n"
485     "    caninit\n"
486     "\n"
487     "### Description ###\n"
488     "\n"
489     "This command (re-)initializes all CAN controllers using current\n"
490     "CAN configuration. This configuration can be changed using\n"
491     "canbaudrate command.\n"
492     "\n"
493     "In the default configuration the baudrate of all CAN controllers i set\n"
494     "to 500 kbit/s.\n"
495     "\n"
496     "### Example ###\n"
497     "  --> caninit\n",
498     CMD_HANDLER(cmd_do_can_init), (void *)&cmd_list_can
499 };
500
501 cmd_des_t const cmd_des_can_baudrate={
502     0, CDESM_OPCHR|CDESM_RW,
503     "canbaudrate#", "Change baudrate of CAN controller",
504     "### Command syntax ###\n"
505     "\n"
506     "    canbaudrate<CONTROLLER>?\n"
507     "    canbaudrate<CONTROLLER>:<BAUDRATE>\n"
508     "\n"
509     "where `<CONTROLLER>` is number in range 1-3 and BAUDRATE is number in\n"
510     "range 1000-10000000 specifying the baurdate in bits per second.\n"
511     "\n"
512     "### Description ###\n"
513     "\n"
514     "This command is used to set or show the baudrate of a CAN controller.\n"
515     "The baudrate shown is the one which will be used by next invocation of\n"
516     "the caninit command.\n"
517     "\n"
518     "### Examples ###\n"
519     "\n"
520     "    --> canbaudrate2?\n"
521     "    canbaudrate2=500000\n"
522     "\n"
523     "    --> canbaudrate2:100000\n",
524     CMD_HANDLER(cmd_do_can_change_baudrate), (void *)&cmd_list_can
525 };
526
527 cmd_des_t const cmd_des_can_send={
528     0, 0,
529     "cansend", "Test sending message over CAN",
530     "### Command syntax ###\n"
531     "\n"
532     "    cansend <CONTROLLER> <ID> <DATA>\n"
533     "\n"
534     "where `<CONTROLLER>` is number in range 1-3, `<ID>` is a valid CAN ID\n"
535     "and `<DATA>` is 0-8 bytes of data in hexadecimal representation.\n"
536     "There may be any number of spaces between the data bytes.\n"
537     "`<ID>` may be given in octal, decimal or hexadecimal base.\n"
538     "\n"
539     "### Description ###\n"
540     "\n"
541     "This command sends a CAN frame using specified CAN controller.\n"
542     "\n"
543     "The caninit command must be called before using this command.\n"
544     "\n"
545     "### Example ###\n"
546     "    --> cansend 2 0x123 DEAD BEEF\n"
547     "    Sent: can2      123     [4]     DE AD BE EF\n",
548     CMD_HANDLER(cmd_do_can_send), (void *)&cmd_list_can
549 };
550
551
552 cmd_des_t const cmd_des_can_dump={
553     0, 0,
554     "candump", "Dump all messages received over CAN",
555     "### Command syntax ###\n"
556     "\n"
557     "    candump <CONTROLLER>\n"
558     "\n"
559     "where `<CONTROLLER>` is a number in range 1-3.\n"
560     "\n"
561     "### Description ###\n"
562     "\n"
563     "This command prints out all CAN messages received via the specified\n"
564     "controller.\n"
565     "\n"
566     "IDs are zero-filled to length 3 if a message in the standard frame\n"
567     "format is received and to 8 for extended frame format messages.\n"
568     "\n"
569     "caninit must be called before using this command.\n"
570     "\n"
571     "### Example ###\n"
572     "\n"
573     "    --> candump 2\n"
574     "can2  0000FADE  [2]  12 34\n",
575     CMD_HANDLER(cmd_do_can_dump), (void *)&cmd_list_can
576 };
577
578
579
580 cmd_des_t const *cmd_list_can[]={
581   &cmd_des_test_can_loopback,
582   &cmd_des_can_init,
583   &cmd_des_can_baudrate,
584   &cmd_des_can_send,
585   &cmd_des_can_dump,
586   NULL
587 };