1 #include <system_def.h>
6 #include <rtems/untar.h>
7 #include <rtems/error.h>
8 #include <rtems/mw_uid.h>
13 #include <bsp/mscan.h>
14 #include <bsp/mscan-base.h>
20 #define CAN_GW_A_TO_B_MODE 1
21 #define CAN_GW_B_TO_A_MODE 2
22 #define CAN_GW_BAUDRATE 1000000
23 #define CAN_GW_TASK_HIGH_PRIO 250 /* POSIX API actually has priorities the "right way around" that is, higher is indeed more important */
25 /* counters for informational purposes */
26 unsigned long int total_1 = 0, total_2 = 0;
27 unsigned long int succ_1 = 0, succ_2 = 0;
28 unsigned long int err_1 = 0, err_2 = 0;
30 /* Pthread handles for the GW */
31 static pthread_t CAN_A_to_B_thread, CAN_B_to_A_thread;
32 /* Dummy FDs for setting baudrate */
35 /* Prototypes for local functions. */
36 static void* CAN_GW_thread(void* arg);
37 static void fd_closer(void* arg);
38 static int start_tasks();
39 static int end_tasks();
40 static int set_baudrate(int baudrate, int* fd1, int* fd2);
43 * Simple cleanup handler for GW threads. Closes opened FD.
45 static void fd_closer(void* arg){
46 close( (*(int*)arg) );
52 * This function implements the main thread loop and enough decision logic so that it knows which device to take messages from and which device to send the messages to.
55 static void* CAN_GW_thread(void* arg){
59 unsigned long int *total = NULL, *succ = NULL, *err = NULL; /* Makes compiler shut up about warnings. */
62 struct can_message canmsg;
63 struct mscan_rx_parms rxparms;
64 struct mscan_tx_parms txparms;
65 memset(&canmsg, 0, sizeof(canmsg));
66 memset(&rxparms, 0, sizeof(rxparms));
67 memset(&txparms, 0, sizeof(txparms));
69 /* These remain constant during the loop. */
70 rxparms.rx_mess = &canmsg;
71 rxparms.rx_timeout = rtems_clock_get_ticks_per_second(); /* 1s timeout */
72 txparms.tx_mess = &canmsg;
75 /* Decide in which direction this task should work. */
76 if (((int)arg) == CAN_GW_A_TO_B_MODE){
77 fd_in = open(MSCAN_A_DEV_NAME, O_RDWR);
78 fd_out = open(MSCAN_B_DEV_NAME, O_RDWR);
79 } else if (((int)arg) == CAN_GW_B_TO_A_MODE){
80 fd_in = open(MSCAN_B_DEV_NAME, O_RDWR);
81 fd_out = open(MSCAN_A_DEV_NAME, O_RDWR);
83 /* Invalid argument, terminate self. */
87 #ifndef BENCH_BUILD /* Overhead decrease for benching builds.*/
88 if (((int)arg) == CAN_GW_A_TO_B_MODE){
99 /* CANs are set to proper baudrate outside of these task due to potential race condition. */
102 /* Prepare cleanup for both opened FDs. */
103 pthread_cleanup_push(fd_closer, (void*)&fd_in);
104 pthread_cleanup_push(fd_closer, (void*)&fd_out);
107 /* RTEMS doesn't implement cancellation point inside read(), violating the API's contract. Luckily, pthread_testcancel() works. */
108 pthread_testcancel();
109 res = read(fd_in, &rxparms, sizeof(rxparms));
111 /* Read error, doesn't really do anything. (Currently) */
113 /* Message was read, now we should resend it. */
114 txparms.tx_idx = canmsg.mess_id;
115 res = write(fd_out, &txparms, sizeof(txparms));
117 #ifndef BENCH_BUILD /* This is the simplest way to remove all the counting */
118 /* Retry? Decide later. */
125 } /* Turns it into empty loop. */
134 static int start_tasks(){
138 pthread_attr_t attributes;
139 struct sched_param parm;
140 parm.sched_priority = CAN_GW_TASK_HIGH_PRIO;
141 pthread_attr_init(&attributes);
142 #ifdef HIGH_PRIO /* Without setting PTHREAD_EXPLICIT_SCHED, thread is created with parameters inherited from this thread. */
143 res = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED);
145 pthread_attr_setschedparam(&attributes, &parm);
147 res = pthread_create(&CAN_A_to_B_thread, &attributes, CAN_GW_thread, (void*)CAN_GW_A_TO_B_MODE);
149 /* No cleanup is needed here. */
153 res = pthread_create(&CAN_B_to_A_thread, &attributes, CAN_GW_thread, (void*)CAN_GW_B_TO_A_MODE);
155 /* First thread needs to be aborted before return. */
156 pthread_cancel(CAN_A_to_B_thread);
160 pthread_attr_destroy(&attributes);
162 /* detach is needed so that the threads call clean up handlers automatically. */
163 pthread_detach(CAN_B_to_A_thread);
164 pthread_detach(CAN_A_to_B_thread);
166 /* Threads are started and running at this point. */
171 * This function starts the GW.
173 * It opens two dummy file descriptors to set CAN baudrate (avoiding need of synchronized thread start), starts the forwarding threads.
175 * Currently has only simple error handling.
178 /* Baudrate is set for dummy FD, it should be remembered by the device. */
180 res = set_baudrate(CAN_GW_BAUDRATE, &fd1, &fd2);
181 printf("Baudrate set.\n");
184 printf("tasks started\n");
191 * This function stops threads implementing GW's forwarding. It tries to stop the threads "politely" via pthread_cancel.
193 * Error handling is not yet implemented, so it always returns 0 (success).
195 static int end_tasks(){
197 printf("Attempting to stop thread 1\n");
198 res = pthread_cancel(CAN_A_to_B_thread);
201 /* Not sure what to do with error here, will have to figure out later. */
203 printf("Attempting to stop thread 2\n");
204 res = pthread_cancel(CAN_B_to_A_thread);
207 /* Not sure what to do with error here, will have to figure out later. */
210 printf("Both threads should now be stopped.\n");
216 * Sets baudrate to the devices via dummy fd.
218 static int set_baudrate(int baudrate, int* fd1, int* fd2){
220 struct mscan_ctrl_parms ctrl_parms;
221 memset(&ctrl_parms, 0, sizeof(ctrl_parms));
222 ctrl_parms.ctrl_can_bitrate = baudrate;
224 printf("Attempting to set bitrate %"PRIu32" for fd.\n", ctrl_parms.ctrl_can_bitrate);
226 fd = open(MSCAN_A_DEV_NAME, O_RDWR);
230 res = ioctl(fd, MSCAN_SET_BAUDRATE, &ctrl_parms);
232 printf("fd - MSCAN_SET_BAUDRATE error (%x:%x) %s\n", res, errno, strerror(errno));
237 fd = open(MSCAN_B_DEV_NAME, O_RDWR);
239 /* Needs to cleanup by closing first fd. */
243 res = ioctl(fd, MSCAN_SET_BAUDRATE, &ctrl_parms);
245 printf("fd - MSCAN_SET_BAUDRATE error (%x:%x) %s\n", res, errno, strerror(errno));
255 * Wrapper function and entry point for stopping the GW.
259 /* Clean up of dummy FDs. */